diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm
index bd4b48893f..a761ad73c1 100644
--- a/code/modules/hydroponics/spreading/spreading_growth.dm
+++ b/code/modules/hydroponics/spreading/spreading_growth.dm
@@ -1,166 +1,175 @@
-#define NEIGHBOR_REFRESH_TIME 100
-
-/obj/effect/plant/proc/get_cardinal_neighbors()
- var/list/cardinal_neighbors = list()
- for(var/check_dir in cardinal)
- var/turf/simulated/T = get_step(get_turf(src), check_dir)
- if(istype(T))
- cardinal_neighbors |= T
- return cardinal_neighbors
-
-/obj/effect/plant/proc/update_neighbors()
- // Update our list of valid neighboring turfs.
- neighbors = list()
- for(var/turf/simulated/floor in get_cardinal_neighbors())
- if(get_dist(parent, floor) > spread_distance)
- continue
-
- var/blocked = 0
- for(var/obj/effect/plant/other in floor.contents)
- if(other.seed == src.seed)
- blocked = 1
- break
- if(blocked)
- continue
-
- if(floor.density)
- if(!isnull(seed.chems["pacid"]))
- spawn(rand(5,25)) floor.ex_act(3)
- continue
-
- if(!Adjacent(floor) || !floor.Enter(src))
- continue
- neighbors |= floor
-
- if(neighbors.len)
- plant_controller.add_plant(src) //if we have neighbours again, start processing
-
- // Update all of our friends.
- var/turf/T = get_turf(src)
- for(var/obj/effect/plant/neighbor in range(1,src))
- if(neighbor.seed == src.seed)
- neighbor.neighbors -= T
-
-/obj/effect/plant/process()
-
- // Something is very wrong, kill ourselves.
- if(!seed)
- die_off()
- return 0
-
- for(var/obj/effect/effect/smoke/chem/smoke in view(1, src))
- if(smoke.reagents.has_reagent("plantbgone"))
- die_off()
- return
-
- // Handle life.
- var/turf/simulated/T = get_turf(src)
- if(istype(T))
- health -= seed.handle_environment(T,T.return_air(),null,1)
- if(health < max_health)
- health += rand(3,5)
- refresh_icon()
- if(health > max_health)
- health = max_health
- else if(health == max_health && !plant)
- plant = new(T,seed)
- plant.dir = src.dir
- plant.transform = src.transform
- plant.age = seed.get_trait(TRAIT_MATURATION)-1
- plant.update_icon()
- if(growth_type==0) //Vines do not become invisible.
- invisibility = INVISIBILITY_MAXIMUM
- else
- plant.layer = layer + 0.1
-
- if(has_buckled_mobs())
- for(var/A in buckled_mobs)
- var/mob/living/L = A
- seed.do_sting(L,src)
- if(seed.get_trait(TRAIT_CARNIVOROUS))
- seed.do_thorns(L,src)
-
- if(world.time >= last_tick+NEIGHBOR_REFRESH_TIME)
- last_tick = world.time
- update_neighbors()
-
- if(sampled)
- //Should be between 2-7 for given the default range of values for TRAIT_PRODUCTION
- var/chance = max(1, round(15/seed.get_trait(TRAIT_PRODUCTION)))
- if(prob(chance))
- sampled = 0
-
- if(is_mature() && !has_buckled_mobs())
- for(var/turf/neighbor in neighbors)
- for(var/mob/living/M in neighbor)
- if(seed.get_trait(TRAIT_SPREAD) >= 2 && (M.lying || prob(round(seed.get_trait(TRAIT_POTENCY)))))
- entangle(M)
-
- if(is_mature() && neighbors.len && prob(spread_chance))
- //spread to 1-3 adjacent turfs depending on yield trait.
- var/max_spread = between(1, round(seed.get_trait(TRAIT_YIELD)*3/14), 3)
-
- for(var/i in 1 to max_spread)
- if(prob(spread_chance))
- sleep(rand(3,5))
- if(!neighbors.len)
- break
- spread_to(pick(neighbors))
-
- // We shouldn't have spawned if the controller doesn't exist.
- check_health()
- if(has_buckled_mobs() || neighbors.len)
- plant_controller.add_plant(src)
-
-//spreading vines aren't created on their final turf.
-//Instead, they are created at their parent and then move to their destination.
-/obj/effect/plant/proc/spread_to(turf/target_turf)
- var/obj/effect/plant/child = new(get_turf(src),seed,parent)
-
- spawn(1) // This should do a little bit of animation.
- if(QDELETED(child))
- return
-
- //move out to the destination
- child.anchored = 0
- step_to(child, target_turf)
- child.anchored = 1
- child.update_icon()
-
- //see if anything is there
- for(var/thing in child.loc)
- if(thing != child && istype(thing, /obj/effect/plant))
- var/obj/effect/plant/other = thing
- if(other.seed != child.seed)
- other.vine_overrun(child.seed, src) //vine fight
- qdel(child)
- return
- if(istype(thing, /obj/effect/dead_plant))
- qdel(thing)
- qdel(child)
- return
- if(isliving(thing) && (seed.get_trait(TRAIT_CARNIVOROUS) || (seed.get_trait(TRAIT_SPREAD) >= 2 && prob(round(seed.get_trait(TRAIT_POTENCY))))))
- entangle(thing)
- qdel(child)
- return
-
- // Update neighboring squares.
- for(var/obj/effect/plant/neighbor in range(1, child.loc)) //can use the actual final child loc now
- if(child.seed == neighbor.seed) //neighbors of different seeds will continue to try to overrun each other
- neighbor.neighbors -= target_turf
-
- child.finish_spreading()
-
-/obj/effect/plant/proc/die_off()
- // Kill off our plant.
- if(plant) plant.die()
- // This turf is clear now, let our buddies know.
- for(var/turf/simulated/check_turf in get_cardinal_neighbors())
- if(!istype(check_turf))
- continue
- for(var/obj/effect/plant/neighbor in check_turf.contents)
- neighbor.neighbors |= check_turf
- plant_controller.add_plant(neighbor)
- spawn(1) if(src) qdel(src)
-
+#define NEIGHBOR_REFRESH_TIME 100
+
+/obj/effect/plant/proc/get_cardinal_neighbors()
+ var/list/cardinal_neighbors = list()
+ for(var/check_dir in cardinal)
+ var/turf/simulated/T = get_step(get_turf(src), check_dir)
+ if(istype(T))
+ cardinal_neighbors |= T
+ return cardinal_neighbors
+
+/obj/effect/plant/proc/update_neighbors()
+ // Update our list of valid neighboring turfs.
+ neighbors = list()
+ for(var/turf/simulated/floor in get_cardinal_neighbors())
+ if(get_dist(parent, floor) > spread_distance)
+ continue
+
+ var/blocked = 0
+ for(var/obj/effect/plant/other in floor.contents)
+ if(other.seed == src.seed)
+ blocked = 1
+ break
+ if(blocked)
+ continue
+
+ if(floor.density)
+ if(!isnull(seed.chems["pacid"]))
+ spawn(rand(5,25)) floor.ex_act(3)
+ continue
+
+ if(!Adjacent(floor) || !floor.Enter(src))
+ continue
+ neighbors |= floor
+
+ if(neighbors.len)
+ plant_controller.add_plant(src) //if we have neighbours again, start processing
+
+ // Update all of our friends.
+ var/turf/T = get_turf(src)
+ for(var/obj/effect/plant/neighbor in range(1,src))
+ if(neighbor.seed == src.seed)
+ neighbor.neighbors -= T
+
+/obj/effect/plant/process()
+
+ // Something is very wrong, kill ourselves.
+ if(!seed)
+ die_off()
+ return 0
+
+ for(var/obj/effect/effect/smoke/chem/smoke in view(1, src))
+ if(smoke.reagents.has_reagent("plantbgone"))
+ die_off()
+ return
+
+ // Handle life.
+ var/turf/simulated/T = get_turf(src)
+ if(istype(T))
+ health -= seed.handle_environment(T,T.return_air(),null,1)
+ if(health < max_health)
+ health += rand(3,5)
+ refresh_icon()
+ if(health > max_health)
+ health = max_health
+ else if(health == max_health && !plant)
+ plant = new(T,seed)
+ plant.dir = src.dir
+ plant.transform = src.transform
+ plant.age = seed.get_trait(TRAIT_MATURATION)-1
+ plant.update_icon()
+ if(growth_type==0) //Vines do not become invisible.
+ invisibility = INVISIBILITY_MAXIMUM
+ else
+ plant.layer = layer + 0.1
+
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ seed.do_sting(L,src)
+ if(seed.get_trait(TRAIT_CARNIVOROUS))
+ seed.do_thorns(L,src)
+
+ if(world.time >= last_tick+NEIGHBOR_REFRESH_TIME)
+ last_tick = world.time
+ update_neighbors()
+
+ if(sampled)
+ //Should be between 2-7 for given the default range of values for TRAIT_PRODUCTION
+ var/chance = max(1, round(15/seed.get_trait(TRAIT_PRODUCTION)))
+ if(prob(chance))
+ sampled = 0
+
+ if(is_mature() && !has_buckled_mobs())
+ for(var/turf/neighbor in neighbors)
+ for(var/mob/living/M in neighbor)
+ if(seed.get_trait(TRAIT_SPREAD) >= 2 && (M.lying || prob(round(seed.get_trait(TRAIT_POTENCY)))))
+ entangle(M)
+
+ if(is_mature() && neighbors.len && prob(spread_chance))
+ //spread to 1-3 adjacent turfs depending on yield trait.
+ var/max_spread = between(1, round(seed.get_trait(TRAIT_YIELD)*3/14), 3)
+
+ for(var/i in 1 to max_spread)
+ if(prob(spread_chance))
+ sleep(rand(3,5))
+ if(!neighbors.len)
+ break
+ spread_to(pick(neighbors))
+
+ // We shouldn't have spawned if the controller doesn't exist.
+ check_health()
+ if(has_buckled_mobs() || neighbors.len)
+ plant_controller.add_plant(src)
+
+//spreading vines aren't created on their final turf.
+//Instead, they are created at their parent and then move to their destination.
+
+/obj/effect/plant/proc/spread_to(turf/target_turf)
+ var/obj/effect/plant/child = new(get_turf(src),seed,parent)
+
+ spawn(1) // This should do a little bit of animation.
+ if(QDELETED(child))
+ return
+
+ //move out to the destination
+ child.anchored = 0
+ step_to(child, target_turf)
+ child.anchored = 1
+ child.update_icon()
+
+ if((seed.get_trait(TRAIT_POTENCY)) >= 50 && (seed.get_trait(TRAIT_CARNIVOROUS)) && prob(5))
+ var/spread_mobspawn = rand(0,2)
+ switch(spread_mobspawn)
+ if(0) new /mob/living/simple_animal/hostile/piranhaplant(src.loc)
+ if(1) new /mob/living/simple_animal/hostile/piranhaplant/spitter(src.loc)
+ if(2) new /mob/living/simple_animal/hostile/piranhaplant/pitcher(src.loc)
+
+
+ //see if anything is there
+ for(var/thing in child.loc)
+ if(thing != child && istype(thing, /obj/effect/plant))
+ var/obj/effect/plant/other = thing
+ if(other.seed != child.seed)
+ other.vine_overrun(child.seed, src) //vine fight
+ qdel(child)
+ return
+ if(istype(thing, /obj/effect/dead_plant))
+ qdel(thing)
+ qdel(child)
+ return
+ if(isliving(thing) && (seed.get_trait(TRAIT_CARNIVOROUS) || (seed.get_trait(TRAIT_SPREAD) >= 2 && prob(round(seed.get_trait(TRAIT_POTENCY))))))
+ entangle(thing)
+ qdel(child)
+ return
+
+ // Update neighboring squares.
+ for(var/obj/effect/plant/neighbor in range(1, child.loc)) //can use the actual final child loc now
+ if(child.seed == neighbor.seed) //neighbors of different seeds will continue to try to overrun each other
+ neighbor.neighbors -= target_turf
+
+ child.finish_spreading()
+
+/obj/effect/plant/proc/die_off()
+ // Kill off our plant.
+ if(plant) plant.die()
+ // This turf is clear now, let our buddies know.
+ for(var/turf/simulated/check_turf in get_cardinal_neighbors())
+ if(!istype(check_turf))
+ continue
+ for(var/obj/effect/plant/neighbor in check_turf.contents)
+ neighbor.neighbors |= check_turf
+ plant_controller.add_plant(neighbor)
+ spawn(1) if(src) qdel(src)
+
#undef NEIGHBOR_REFRESH_TIME
\ No newline at end of file
diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm
index 8a8ceabfeb..2c557ed6f0 100644
--- a/code/modules/hydroponics/spreading/spreading_response.dm
+++ b/code/modules/hydroponics/spreading/spreading_response.dm
@@ -1,100 +1,106 @@
-/obj/effect/plant/HasProximity(var/atom/movable/AM)
-
- if(!is_mature() || seed.get_trait(TRAIT_SPREAD) != 2)
- return
-
- var/mob/living/M = AM
- if(!istype(M))
- return
-
- if(!has_buckled_mobs() && !M.buckled && !M.anchored && (issmall(M) || prob(round(seed.get_trait(TRAIT_POTENCY)/3))))
- //wait a tick for the Entered() proc that called HasProximity() to finish (and thus the moving animation),
- //so we don't appear to teleport from two tiles away when moving into a turf adjacent to vines.
- spawn(1)
- entangle(M)
-
-/obj/effect/plant/attack_hand(var/mob/user)
- manual_unbuckle(user)
-
-/obj/effect/plant/attack_generic(var/mob/user)
- manual_unbuckle(user)
-
-/obj/effect/plant/Crossed(atom/movable/O)
- if(isliving(O))
- trodden_on(O)
-
-/obj/effect/plant/proc/trodden_on(var/mob/living/victim)
- if(!is_mature())
- return
- var/mob/living/carbon/human/H = victim
- if(prob(round(seed.get_trait(TRAIT_POTENCY)/3)))
- entangle(victim)
- if(istype(H) && H.shoes)
- return
- seed.do_thorns(victim,src)
- seed.do_sting(victim,src,pick("r_foot","l_foot","r_leg","l_leg"))
-
-/obj/effect/plant/proc/unbuckle()
- if(has_buckled_mobs())
- for(var/A in buckled_mobs)
- var/mob/living/L = A
- if(L.buckled == src)
- L.buckled = null
- L.anchored = initial(L.anchored)
- L.update_canmove()
- buckled_mobs = list()
- return
-
-/obj/effect/plant/proc/manual_unbuckle(mob/user as mob)
- if(has_buckled_mobs())
- var/chance = 20
- if(seed)
- chance = round(100/(20*seed.get_trait(TRAIT_POTENCY)/100))
- if(prob(chance))
- for(var/A in buckled_mobs)
- var/mob/living/L = A
- if(!(user in buckled_mobs))
- L.visible_message(\
- "\The [user] frees \the [L] from \the [src].",\
- "\The [user] frees you from \the [src].",\
- "You hear shredding and ripping.")
- else
- L.visible_message(\
- "\The [L] struggles free of \the [src].",\
- "You untangle \the [src] from around yourself.",\
- "You hear shredding and ripping.")
- unbuckle()
- else
- user.setClickCooldown(user.get_attack_speed())
- health -= rand(1,5)
- var/text = pick("rip","tear","pull", "bite", "tug")
- user.visible_message(\
- "\The [user] [text]s at \the [src].",\
- "You [text] at \the [src].",\
- "You hear shredding and ripping.")
- check_health()
- return
-
-/obj/effect/plant/proc/entangle(var/mob/living/victim)
-
- if(has_buckled_mobs())
- return
-
- if(victim.buckled || victim.anchored)
- return
-
- //grabbing people
- if(!victim.anchored && Adjacent(victim) && victim.loc != src.loc)
- var/can_grab = 1
- if(istype(victim, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = victim
- if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.item_flags & NOSLIP))
- can_grab = 0
- if(can_grab)
- src.visible_message("Tendrils lash out from \the [src] and drag \the [victim] in!")
- victim.forceMove(src.loc)
- buckle_mob(victim)
- victim.set_dir(pick(cardinal))
- victim << "Tendrils [pick("wind", "tangle", "tighten")] around you!"
- victim.Weaken(0.5)
- seed.do_thorns(victim,src)
+/obj/effect/plant/HasProximity(var/atom/movable/AM)
+
+ if(!is_mature() || seed.get_trait(TRAIT_SPREAD) != 2)
+ return
+
+ var/mob/living/M = AM
+ if(!istype(M))
+ return
+
+ if(!has_buckled_mobs() && !M.buckled && !M.anchored && (issmall(M) || prob(round(seed.get_trait(TRAIT_POTENCY)/3))))
+ //wait a tick for the Entered() proc that called HasProximity() to finish (and thus the moving animation),
+ //so we don't appear to teleport from two tiles away when moving into a turf adjacent to vines.
+ if(M.entangle_immunity == 1)
+ return
+ spawn(1)
+ entangle(M)
+
+/obj/effect/plant/attack_hand(var/mob/user)
+ manual_unbuckle(user)
+
+/obj/effect/plant/attack_generic(var/mob/user)
+ manual_unbuckle(user)
+
+/obj/effect/plant/Crossed(atom/movable/O)
+ if(isliving(O))
+ trodden_on(O)
+
+/obj/effect/plant/proc/trodden_on(var/mob/living/victim)
+ if(!is_mature())
+ return
+ var/mob/living/carbon/human/H = victim
+ if(H.entangle_immunity == 1)
+ return
+ if(prob(round(seed.get_trait(TRAIT_POTENCY)/3)))
+ entangle(victim)
+ if(istype(H) && H.shoes)
+ return
+ seed.do_thorns(victim,src)
+ seed.do_sting(victim,src,pick("r_foot","l_foot","r_leg","l_leg"))
+
+/obj/effect/plant/proc/unbuckle()
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ if(L.buckled == src)
+ L.buckled = null
+ L.anchored = initial(L.anchored)
+ L.update_canmove()
+ buckled_mobs = list()
+ return
+
+/obj/effect/plant/proc/manual_unbuckle(mob/user as mob)
+ if(has_buckled_mobs())
+ var/chance = 20
+ if(seed)
+ chance = round(100/(20*seed.get_trait(TRAIT_POTENCY)/100))
+ if(prob(chance))
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ if(!(user in buckled_mobs))
+ L.visible_message(\
+ "\The [user] frees \the [L] from \the [src].",\
+ "\The [user] frees you from \the [src].",\
+ "You hear shredding and ripping.")
+ else
+ L.visible_message(\
+ "\The [L] struggles free of \the [src].",\
+ "You untangle \the [src] from around yourself.",\
+ "You hear shredding and ripping.")
+ unbuckle()
+ else
+ user.setClickCooldown(user.get_attack_speed())
+ health -= rand(1,5)
+ var/text = pick("rip","tear","pull", "bite", "tug")
+ user.visible_message(\
+ "\The [user] [text]s at \the [src].",\
+ "You [text] at \the [src].",\
+ "You hear shredding and ripping.")
+ check_health()
+ return
+
+/obj/effect/plant/proc/entangle(var/mob/living/victim)
+
+ if(has_buckled_mobs())
+ return
+
+ if(victim.buckled || victim.anchored)
+ return
+
+ //grabbing people
+ if(!victim.anchored && Adjacent(victim) && victim.loc != src.loc)
+ var/can_grab = 1
+ if(istype(victim, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = victim
+ if(H.entangle_immunity == 1)
+ return
+ if(istype(H.shoes, /obj/item/clothing/shoes/magboots) && (H.shoes.item_flags & NOSLIP))
+ can_grab = 0
+ if(can_grab)
+ src.visible_message("Tendrils lash out from \the [src] and drag \the [victim] in!")
+ victim.forceMove(src.loc)
+ buckle_mob(victim)
+ victim.set_dir(pick(cardinal))
+ victim << "Tendrils [pick("wind", "tangle", "tighten")] around you!"
+ victim.Weaken(0.5)
+ seed.do_thorns(victim,src)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 8c6297357a..6d97f616cc 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1,1285 +1,1288 @@
-/mob/living/New()
- ..()
-
- //Prime this list if we need it.
- if(has_huds)
- add_overlay(backplane,TRUE) //Strap this on here, to block HUDs from appearing in rightclick menus: http://www.byond.com/forum/?post=2336679
- hud_list = list()
- hud_list.len = TOTAL_HUDS
- make_hud_overlays()
-
- //I'll just hang my coat up over here
- dsoverlay = image('icons/mob/darksight.dmi',global_hud.darksight) //This is a secret overlay! Go look at the file, you'll see.
- var/mutable_appearance/dsma = new(dsoverlay) //Changing like ten things, might as well.
- dsma.alpha = 0
- dsma.plane = PLANE_LIGHTING
- dsma.blend_mode = BLEND_ADD
- dsoverlay.appearance = dsma
-
-/mob/living/Destroy()
- dsoverlay.loc = null //I'll take my coat with me
- dsoverlay = null
- if(buckled)
- buckled.unbuckle_mob(src, TRUE)
- return ..()
-
-//mob verbs are faster than object verbs. See mob/verb/examine.
-/mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1))
- set name = "Pull"
- set category = "Object"
-
- if(AM.Adjacent(src))
- src.start_pulling(AM)
-
- return
-
-//mob verbs are faster than object verbs. See above.
-/mob/living/pointed(atom/A as mob|obj|turf in view())
- if(src.stat || !src.canmove || src.restrained())
- return 0
- if(src.status_flags & FAKEDEATH)
- return 0
- if(!..())
- return 0
-
- usr.visible_message("[src] points to [A]")
- return 1
-
-/*one proc, four uses
-swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive
-default behaviour is:
- - non-passive mob passes the passive version
- - passive mob checks to see if its mob_bump_flag is in the non-passive's mob_bump_flags
- - if si, the proc returns
-*/
-/mob/living/proc/can_move_mob(var/mob/living/swapped, swapping = 0, passive = 0)
- if(!swapped)
- return 1
- if(!passive)
- return swapped.can_move_mob(src, swapping, 1)
- else
- var/context_flags = 0
- if(swapping)
- context_flags = swapped.mob_swap_flags
- else
- context_flags = swapped.mob_push_flags
- if(!mob_bump_flag) //nothing defined, go wild
- return 1
- if(mob_bump_flag & context_flags)
- return 1
- return 0
-
-/mob/living/Bump(atom/movable/AM, yes)
- spawn(0)
- if ((!( yes ) || now_pushing) || !loc)
- return
- now_pushing = 1
- if (istype(AM, /mob/living))
- var/mob/living/tmob = AM
-
- //Even if we don't push/swap places, we "touched" them, so spread fire
- spread_fire(tmob)
-
- for(var/mob/living/M in range(tmob, 1))
- if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
- if ( !(world.time % 5) )
- to_chat(src, "[tmob] is restrained, you cannot push past")
- now_pushing = 0
- return
- if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
- if ( !(world.time % 5) )
- to_chat(src, "[tmob] is restraining [M], you cannot push past")
- now_pushing = 0
- return
-
- //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
- var/dense = 0
- if(loc.density)
- dense = 1
- for(var/atom/movable/A in loc)
- if(A == src)
- continue
- if(A.density)
- if(A.flags&ON_BORDER)
- dense = !A.CanPass(src, src.loc)
- else
- dense = 1
- if(dense) break
-
- //Leaping mobs just land on the tile, no pushing, no anything.
- if(status_flags & LEAPING)
- loc = tmob.loc
- status_flags &= ~LEAPING
- now_pushing = 0
- return
-
- if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
- var/turf/oldloc = loc
- forceMove(tmob.loc)
-
- //VOREstation Edit - Begin
- if (istype(tmob, /mob/living/simple_animal)) //check bumpnom chance, if it's a simplemob that's bumped
- tmob.Bumped(src)
- else if(istype(src, /mob/living/simple_animal)) //otherwise, if it's a simplemob doing the bumping. Simplemob on simplemob doesn't seem to trigger but that's fine.
- Bumped(tmob)
- if (tmob.loc == src) //check if they got ate, and if so skip the forcemove
- now_pushing = 0
- return
-
- // In case of micros, we don't swap positions; instead occupying the same square!
- if (handle_micro_bump_helping(tmob))
- now_pushing = 0
- return
- // TODO - Check if we need to do something about the slime.UpdateFeed() we are skipping below.
- // VOREStation Edit - End
-
- tmob.forceMove(oldloc)
- now_pushing = 0
- return
-
- if(!can_move_mob(tmob, 0, 0))
- now_pushing = 0
- return
- if(a_intent == I_HELP || src.restrained())
- now_pushing = 0
- return
-
- // VOREStation Edit - Begin
- // Plow that nerd.
- if(ishuman(tmob))
- var/mob/living/carbon/human/H = tmob
- if(H.species.lightweight == 1 && prob(50))
- H.visible_message("[src] bumps into [H], knocking them off balance!")
- H.Weaken(5)
- now_pushing = 0
- return
- // Handle grabbing, stomping, and such of micros!
- if(handle_micro_bump_other(tmob)) return
- // VOREStation Edit - End
-
- if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
- if(prob(40) && !(FAT in src.mutations))
- to_chat(src, "You fail to push [tmob]'s fat ass out of the way.")
- now_pushing = 0
- return
- if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot))
- if(prob(99))
- now_pushing = 0
- return
- if(tmob.l_hand && istype(tmob.l_hand, /obj/item/weapon/shield/riot))
- if(prob(99))
- now_pushing = 0
- return
- if(!(tmob.status_flags & CANPUSH))
- now_pushing = 0
- return
-
- tmob.LAssailant = src
-
- now_pushing = 0
- spawn(0)
- ..()
- if (!istype(AM, /atom/movable) || AM.anchored)
- //VOREStation Edit - object-specific proc for running into things
- if(((confused || is_blind()) && stat == CONSCIOUS && prob(50) && m_intent=="run") || flying)
- AM.stumble_into(src)
- //VOREStation Edit End
- /* VOREStation Removal - See above
- Weaken(2)
- playsound(loc, "punch", 25, 1, -1)
- visible_message("[src] [pick("ran", "slammed")] into \the [AM]!")
- src.apply_damage(5, BRUTE)
- src << ("You just [pick("ran", "slammed")] into \the [AM]!")
- to_chat(src, "You just [pick("ran", "slammed")] into \the [AM]!")
- */ // VOREStation Removal End
- return
- if (!now_pushing)
- if(isobj(AM))
- var/obj/I = AM
- if(!can_pull_size || can_pull_size < I.w_class)
- return
- now_pushing = 1
-
- var/t = get_dir(src, AM)
- if (istype(AM, /obj/structure/window))
- for(var/obj/structure/window/win in get_step(AM,t))
- now_pushing = 0
- return
- step(AM, t)
- if(ishuman(AM) && AM:grabbed_by)
- for(var/obj/item/weapon/grab/G in AM:grabbed_by)
- step(G:assailant, get_dir(G:assailant, AM))
- G.adjust_position()
- now_pushing = 0
- return
- return
-
-/mob/living/verb/succumb()
- set hidden = 1
- if ((src.health < 0 && src.health > (5-src.getMaxHealth()))) // Health below Zero but above 5-away-from-death, as before, but variable
- src.death()
- to_chat(src, "You have given up life and succumbed to death.")
- else
- to_chat(src, "You are not injured enough to succumb to death!")
-
-/mob/living/proc/updatehealth()
- if(status_flags & GODMODE)
- health = 100
- stat = CONSCIOUS
- else
- health = getMaxHealth() - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - halloss
-
-
-//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually
-//affects them once clothing is factored in. ~Errorage
-/mob/living/proc/calculate_affecting_pressure(var/pressure)
- return
-
-
-//sort of a legacy burn method for /electrocute, /shock, and the e_chair
-/mob/living/proc/burn_skin(burn_amount)
- if(istype(src, /mob/living/carbon/human))
- //world << "DEBUG: burn_skin(), mutations=[mutations]"
- if(mShock in src.mutations) //shockproof
- return 0
- if (COLD_RESISTANCE in src.mutations) //fireproof
- return 0
- var/mob/living/carbon/human/H = src //make this damage method divide the damage to be done among all the body parts, then burn each body part for that much damage. will have better effect then just randomly picking a body part
- var/divided_damage = (burn_amount)/(H.organs.len)
- var/extradam = 0 //added to when organ is at max dam
- for(var/obj/item/organ/external/affecting in H.organs)
- if(!affecting) continue
- if(affecting.take_damage(0, divided_damage+extradam)) //TODO: fix the extradam stuff. Or, ebtter yet...rewrite this entire proc ~Carn
- H.UpdateDamageIcon()
- H.updatehealth()
- return 1
- else if(istype(src, /mob/living/silicon/ai))
- return 0
-
-/mob/living/proc/adjustBodyTemp(actual, desired, incrementboost)
- var/temperature = actual
- var/difference = abs(actual-desired) //get difference
- var/increments = difference/10 //find how many increments apart they are
- var/change = increments*incrementboost // Get the amount to change by (x per increment)
-
- // Too cold
- if(actual < desired)
- temperature += change
- if(actual > desired)
- temperature = desired
- // Too hot
- if(actual > desired)
- temperature -= change
- if(actual < desired)
- temperature = desired
-// if(istype(src, /mob/living/carbon/human))
-// world << "[src] ~ [src.bodytemperature] ~ [temperature]"
- return temperature
-
-
-// ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching.
-// Stop! ... Hammertime! ~Carn
-// I touched them without asking... I'm soooo edgy ~Erro (added nodamage checks)
-
-/mob/living/proc/getBruteLoss()
- return bruteloss
-
-/mob/living/proc/getShockBruteLoss() //Only checks for things that'll actually hurt (not robolimbs)
- return bruteloss
-
-/mob/living/proc/getActualBruteLoss() // Mostly for humans with robolimbs.
- return getBruteLoss()
-
-//'include_robo' only applies to healing, for legacy purposes, as all damage typically hurts both types of organs
-/mob/living/proc/adjustBruteLoss(var/amount,var/include_robo)
- if(status_flags & GODMODE) return 0 //godmode
-
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_damage_percent))
- amount *= M.incoming_damage_percent
- if(!isnull(M.incoming_brute_damage_percent))
- amount *= M.incoming_brute_damage_percent
- else if(amount < 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_healing_percent))
- amount *= M.incoming_healing_percent
-
- bruteloss = min(max(bruteloss + amount, 0),(getMaxHealth()*2))
- updatehealth()
-
-/mob/living/proc/getOxyLoss()
- return oxyloss
-
-/mob/living/proc/adjustOxyLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
-
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_damage_percent))
- amount *= M.incoming_damage_percent
- if(!isnull(M.incoming_oxy_damage_percent))
- amount *= M.incoming_oxy_damage_percent
- else if(amount < 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_healing_percent))
- amount *= M.incoming_healing_percent
-
- oxyloss = min(max(oxyloss + amount, 0),(getMaxHealth()*2))
- updatehealth()
-
-/mob/living/proc/setOxyLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- oxyloss = amount
-
-/mob/living/proc/getToxLoss()
- return toxloss
-
-/mob/living/proc/adjustToxLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
-
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_damage_percent))
- amount *= M.incoming_damage_percent
- if(!isnull(M.incoming_tox_damage_percent))
- amount *= M.incoming_tox_damage_percent
- else if(amount < 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_healing_percent))
- amount *= M.incoming_healing_percent
-
- toxloss = min(max(toxloss + amount, 0),(getMaxHealth()*2))
- updatehealth()
-
-/mob/living/proc/setToxLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- toxloss = amount
-
-/mob/living/proc/getFireLoss()
- return fireloss
-
-/mob/living/proc/getShockFireLoss() //Only checks for things that'll actually hurt (not robolimbs)
- return fireloss
-
-/mob/living/proc/getActualFireLoss() // Mostly for humans with robolimbs.
- return getFireLoss()
-
-//'include_robo' only applies to healing, for legacy purposes, as all damage typically hurts both types of organs
-/mob/living/proc/adjustFireLoss(var/amount,var/include_robo)
- if(status_flags & GODMODE) return 0 //godmode
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_damage_percent))
- amount *= M.incoming_damage_percent
- if(!isnull(M.incoming_fire_damage_percent))
- amount *= M.incoming_fire_damage_percent
- else if(amount < 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_healing_percent))
- amount *= M.incoming_healing_percent
-
- fireloss = min(max(fireloss + amount, 0),(getMaxHealth()*2))
- updatehealth()
-
-/mob/living/proc/getCloneLoss()
- return cloneloss
-
-/mob/living/proc/adjustCloneLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
-
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_damage_percent))
- amount *= M.incoming_damage_percent
- if(!isnull(M.incoming_clone_damage_percent))
- amount *= M.incoming_clone_damage_percent
- else if(amount < 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_healing_percent))
- amount *= M.incoming_healing_percent
-
- cloneloss = min(max(cloneloss + amount, 0),(getMaxHealth()*2))
- updatehealth()
-
-/mob/living/proc/setCloneLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- cloneloss = amount
-
-/mob/living/proc/getBrainLoss()
- return brainloss
-
-/mob/living/proc/adjustBrainLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- brainloss = min(max(brainloss + amount, 0),(getMaxHealth()*2))
-
-/mob/living/proc/setBrainLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- brainloss = amount
-
-/mob/living/proc/getHalLoss()
- return halloss
-
-/mob/living/proc/adjustHalLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_damage_percent))
- amount *= M.incoming_damage_percent
- if(!isnull(M.incoming_hal_damage_percent))
- amount *= M.incoming_hal_damage_percent
- if(!isnull(M.disable_duration_percent))
- amount *= M.incoming_hal_damage_percent
- else if(amount < 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.incoming_healing_percent))
- amount *= M.incoming_healing_percent
- halloss = min(max(halloss + amount, 0),(getMaxHealth()*2))
- updatehealth()
-
-/mob/living/proc/setHalLoss(var/amount)
- if(status_flags & GODMODE) return 0 //godmode
- halloss = amount
-
-// Use this to get a mob's max health whenever possible. Reading maxHealth directly will give inaccurate results if any modifiers exist.
-/mob/living/proc/getMaxHealth()
- var/result = maxHealth
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.max_health_flat))
- result += M.max_health_flat
- // Second loop is so we can get all the flat adjustments first before multiplying, otherwise the result will be different.
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.max_health_percent))
- result *= M.max_health_percent
- return result
-
-/mob/living/proc/setMaxHealth(var/newMaxHealth)
- health = (health/maxHealth) * (newMaxHealth) //VOREStation Add - Adjust existing health
- maxHealth = newMaxHealth
-
-/mob/living/Stun(amount)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/AdjustStunned(amount)
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/Weaken(amount)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/AdjustWeakened(amount)
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/Paralyse(amount)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/AdjustParalysis(amount)
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/Sleeping(amount)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/AdjustSleeping(amount)
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/Confuse(amount)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/AdjustConfused(amount)
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/Blind(amount)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-/mob/living/AdjustBlinded(amount)
- if(amount > 0)
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.disable_duration_percent))
- amount = round(amount * M.disable_duration_percent)
- ..(amount)
-
-// ++++ROCKDTBEN++++ MOB PROCS //END
-
-/mob/proc/get_contents()
-
-
-//Recursive function to find everything a mob is holding.
-/mob/living/get_contents(var/obj/item/weapon/storage/Storage = null)
- var/list/L = list()
-
- if(Storage) //If it called itself
- L += Storage.return_inv()
-
- //Leave this commented out, it will cause storage items to exponentially add duplicate to the list
- //for(var/obj/item/weapon/storage/S in Storage.return_inv()) //Check for storage items
- // L += get_contents(S)
-
- for(var/obj/item/weapon/gift/G in Storage.return_inv()) //Check for gift-wrapped items
- L += G.gift
- if(istype(G.gift, /obj/item/weapon/storage))
- L += get_contents(G.gift)
-
- for(var/obj/item/smallDelivery/D in Storage.return_inv()) //Check for package wrapped items
- L += D.wrapped
- if(istype(D.wrapped, /obj/item/weapon/storage)) //this should never happen
- L += get_contents(D.wrapped)
- return L
-
- else
-
- L += src.contents
- for(var/obj/item/weapon/storage/S in src.contents) //Check for storage items
- L += get_contents(S)
-
- for(var/obj/item/weapon/gift/G in src.contents) //Check for gift-wrapped items
- L += G.gift
- if(istype(G.gift, /obj/item/weapon/storage))
- L += get_contents(G.gift)
-
- for(var/obj/item/smallDelivery/D in src.contents) //Check for package wrapped items
- L += D.wrapped
- if(istype(D.wrapped, /obj/item/weapon/storage)) //this should never happen
- L += get_contents(D.wrapped)
- return L
-
-/mob/living/proc/check_contents_for(A)
- var/list/L = src.get_contents()
-
- for(var/obj/B in L)
- if(B.type == A)
- return 1
- return 0
-
-
-/mob/living/proc/can_inject()
- return 1
-
-/mob/living/proc/get_organ_target()
- var/mob/shooter = src
- var/t = shooter:zone_sel.selecting
- if ((t in list( O_EYES, O_MOUTH )))
- t = BP_HEAD
- var/obj/item/organ/external/def_zone = ran_zone(t)
- return def_zone
-
-
-// heal ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/heal_organ_damage(var/brute, var/burn)
- adjustBruteLoss(-brute)
- adjustFireLoss(-burn)
- src.updatehealth()
-
-// damage ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/take_organ_damage(var/brute, var/burn, var/emp=0)
- if(status_flags & GODMODE) return 0 //godmode
- adjustBruteLoss(brute)
- adjustFireLoss(burn)
- src.updatehealth()
-
-// heal MANY external organs, in random order
-/mob/living/proc/heal_overall_damage(var/brute, var/burn)
- adjustBruteLoss(-brute)
- adjustFireLoss(-burn)
- src.updatehealth()
-
-// damage MANY external organs, in random order
-/mob/living/proc/take_overall_damage(var/brute, var/burn, var/used_weapon = null)
- if(status_flags & GODMODE) return 0 //godmode
- adjustBruteLoss(brute)
- adjustFireLoss(burn)
- src.updatehealth()
-
-/mob/living/proc/restore_all_organs()
- return
-
-
-
-/mob/living/proc/revive()
- rejuvenate()
- if(buckled)
- buckled.unbuckle_mob()
- if(iscarbon(src))
- var/mob/living/carbon/C = src
-
- if (C.handcuffed && !initial(C.handcuffed))
- C.drop_from_inventory(C.handcuffed)
- C.handcuffed = initial(C.handcuffed)
-
- if (C.legcuffed && !initial(C.legcuffed))
- C.drop_from_inventory(C.legcuffed)
- C.legcuffed = initial(C.legcuffed)
- BITSET(hud_updateflag, HEALTH_HUD)
- BITSET(hud_updateflag, STATUS_HUD)
- BITSET(hud_updateflag, LIFE_HUD)
- ExtinguishMob()
- fire_stacks = 0
-
-/mob/living/proc/rejuvenate()
- if(reagents)
- reagents.clear_reagents()
-
- // shut down various types of badness
- setToxLoss(0)
- setOxyLoss(0)
- setCloneLoss(0)
- setBrainLoss(0)
- SetParalysis(0)
- SetStunned(0)
- SetWeakened(0)
-
- // shut down ongoing problems
- radiation = 0
- nutrition = 400
- bodytemperature = T20C
- sdisabilities = 0
- disabilities = 0
-
- // fix blindness and deafness
- blinded = 0
- SetBlinded(0)
- eye_blurry = 0
- ear_deaf = 0
- ear_damage = 0
- heal_overall_damage(getBruteLoss(), getFireLoss())
-
- // fix all of our organs
- restore_all_organs()
-
- // remove the character from the list of the dead
- if(stat == DEAD)
- dead_mob_list -= src
- living_mob_list += src
- tod = null
- timeofdeath = 0
-
- // restore us to conciousness
- stat = CONSCIOUS
-
- // make the icons look correct
- regenerate_icons()
-
- BITSET(hud_updateflag, HEALTH_HUD)
- BITSET(hud_updateflag, STATUS_HUD)
- BITSET(hud_updateflag, LIFE_HUD)
-
- failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
- reload_fullscreen()
-
- return
-
-/mob/living/proc/UpdateDamageIcon()
- return
-
-
-/mob/living/proc/Examine_OOC()
- set name = "Examine Meta-Info (OOC)"
- set category = "OOC"
- set src in view()
- //VOREStation Edit Start - Making it so SSD people have prefs with fallback to original style.
- if(config.allow_Metadata)
- if(ooc_notes)
- to_chat(usr, "[src]'s Metainfo:
[ooc_notes]")
- else if(client)
- to_chat(usr, "[src]'s Metainfo:
[client.prefs.metadata]")
- else
- to_chat(usr, "[src] does not have any stored infomation!")
- else
- usr << "OOC Metadata is not supported by this server!"
- //VOREStation Edit End - Making it so SSD people have prefs with fallback to original style.
- return
-
-/mob/living/Move(a, b, flag)
-
- if (buckled && buckled.loc != a) //not updating position
- if(istype(buckled, /mob)) //If you're buckled to a mob, a la slime things, keep on rolling.
- return buckled.Move(a, b)
- else //Otherwise, no running around for you.
- return 0
-
- if (restrained())
- stop_pulling()
-
-
- var/t7 = 1
- if (restrained())
- for(var/mob/living/M in range(src, 1))
- if ((M.pulling == src && M.stat == 0 && !( M.restrained() )))
- t7 = null
- if ((t7 && (pulling && ((get_dist(src, pulling) <= 1 || pulling.loc == loc) && (client && client.moving)))))
- var/turf/T = loc
- . = ..()
-
- if (pulling && pulling.loc)
- if(!( isturf(pulling.loc) ))
- stop_pulling()
- return
-
- /////
- if(pulling && pulling.anchored)
- stop_pulling()
- return
-
- if (!restrained())
- var/diag = get_dir(src, pulling)
- if ((diag - 1) & diag)
- else
- diag = null
- if ((get_dist(src, pulling) > 1 || diag))
- if (isliving(pulling))
- var/mob/living/M = pulling
- var/atom/movable/t = M.pulling
- M.stop_pulling()
-
- if(!istype(M.loc, /turf/space))
- var/area/A = get_area(M)
- if(A.has_gravity)
- //this is the gay blood on floor shit -- Added back -- Skie
- if (M.lying && (prob(M.getBruteLoss() / 6)))
- var/bloodtrail = 1 //Checks if it's possible to even spill blood
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.species.flags & NO_BLOOD)
- bloodtrail = 0
- else
- var/blood_volume = round((H.vessel.get_reagent_amount("blood")/H.species.blood_volume)*100)
- if(blood_volume < BLOOD_VOLUME_SURVIVE)
- bloodtrail = 0 //Most of it's gone already, just leave it be
- else
- H.vessel.remove_reagent("blood", 1)
- if(bloodtrail)
- var/turf/location = M.loc
- if(istype(location, /turf/simulated))
- location.add_blood(M)
- //pull damage with injured people
- if(prob(25))
- M.adjustBruteLoss(1)
- visible_message("\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!")
- if(M.pull_damage())
- if(prob(25))
- M.adjustBruteLoss(2)
- visible_message("\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!")
- var/turf/location = M.loc
- if (istype(location, /turf/simulated))
- var/bloodtrail = 1 //Checks if it's possible to even spill blood
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.species.flags & NO_BLOOD)
- bloodtrail = 0
- else
- var/blood_volume = round((H.vessel.get_reagent_amount("blood")/H.species.blood_volume)*100)
- if(blood_volume < BLOOD_VOLUME_SURVIVE)
- bloodtrail = 0 //Most of it's gone already, just leave it be
- else
- H.vessel.remove_reagent("blood", 1)
- if(bloodtrail)
- if(istype(location, /turf/simulated))
- location.add_blood(M)
-
- step(pulling, get_dir(pulling.loc, T))
- if(t)
- M.start_pulling(t)
- else
- if (pulling)
- if (istype(pulling, /obj/structure/window))
- var/obj/structure/window/W = pulling
- if(W.is_full_window())
- for(var/obj/structure/window/win in get_step(pulling,get_dir(pulling.loc, T)))
- stop_pulling()
- if (pulling)
- step(pulling, get_dir(pulling.loc, T))
- else
- stop_pulling()
- . = ..()
-
- if (s_active && !( s_active in contents ) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much.
- s_active.close(src)
-
-/mob/living/proc/handle_footstep(turf/T)
- return FALSE
-
-/mob/living/verb/resist()
- set name = "Resist"
- set category = "IC"
-
- if(!incapacitated(INCAPACITATION_KNOCKOUT) && canClick())
- setClickCooldown(20)
- resist_grab()
- if(!weakened)
- process_resist()
-
-/mob/living/proc/process_resist()
- //Getting out of someone's inventory.
- if(istype(src.loc, /obj/item/weapon/holder))
- escape_inventory(src.loc)
- return
-
- //unbuckling yourself
- if(buckled)
- spawn() escape_buckle()
- return TRUE
-
- //Breaking out of a locker?
- if( src.loc && (istype(src.loc, /obj/structure/closet)) )
- var/obj/structure/closet/C = loc
- spawn() C.mob_breakout(src)
- return TRUE
-
- if(istype(loc,/obj/item/clothing))
- spawn() escape_clothes(loc)
-
- if(attempt_vr(src,"vore_process_resist",args)) return TRUE //VOREStation Code
-
-/mob/living/proc/escape_inventory(obj/item/weapon/holder/H)
- if(H != src.loc) return
-
- var/mob/M = H.loc //Get our mob holder (if any).
-
- if(istype(M))
- M.drop_from_inventory(H)
- to_chat(M, "\The [H] wriggles out of your grip!")
- to_chat(src, "You wriggle out of \the [M]'s grip!")
-
- // Update whether or not this mob needs to pass emotes to contents.
- for(var/atom/A in M.contents)
- if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder))
- return
-
- else if(istype(H.loc,/obj/item/clothing/accessory/holster))
- var/obj/item/clothing/accessory/holster/holster = H.loc
- if(holster.holstered == H)
- holster.clear_holster()
- to_chat(src, "You extricate yourself from \the [holster].")
- H.forceMove(get_turf(H))
- else if(istype(H.loc,/obj/item))
- to_chat(src, "You struggle free of \the [H.loc].")
- H.forceMove(get_turf(H))
-
-//TFF 2/5/19: Polaris fix for resisting out of vehicles
-/mob/living/proc/escape_buckle()
- if(buckled)
- if(istype(buckled, /obj/vehicle))
- var/obj/vehicle/vehicle = buckled
- vehicle.unload()
- else
- buckled.user_unbuckle_mob(src, src)
-
-/mob/living/proc/resist_grab()
- var/resisting = 0
- for(var/obj/item/weapon/grab/G in grabbed_by)
- resisting++
- G.handle_resist()
- if(resisting)
- visible_message("[src] resists!")
-
-/mob/living/verb/lay_down()
- set name = "Rest"
- set category = "IC"
-
- resting = !resting
- to_chat(src, "You are now [resting ? "resting" : "getting up"]")
- update_canmove()
-
-//called when the mob receives a bright flash
-/mob/living/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash)
- if(override_blindness_check || !(disabilities & BLIND))
- overlay_fullscreen("flash", type)
- spawn(25)
- if(src)
- clear_fullscreen("flash", 25)
- return 1
-
-/mob/living/proc/cannot_use_vents()
- if(mob_size > MOB_SMALL)
- return "You can't fit into that vent."
- return null
-
-/mob/living/proc/has_brain()
- return 1
-
-/mob/living/proc/has_eyes()
- return 1
-
-/mob/living/proc/slip(var/slipped_on,stun_duration=8)
- return 0
-
-/mob/living/carbon/drop_from_inventory(var/obj/item/W, var/atom/Target = null)
- if(W in internal_organs)
- return
- ..()
-
-/mob/living/touch_map_edge()
-
- //check for nuke disks
- if(client && stat != DEAD) //if they are clientless and dead don't bother, the parent will treat them as any other container
- if(ticker && istype(ticker.mode, /datum/game_mode/nuclear)) //only really care if the game mode is nuclear
- var/datum/game_mode/nuclear/G = ticker.mode
- if(G.check_mob(src))
- if(x <= TRANSITIONEDGE)
- inertia_dir = 4
- else if(x >= world.maxx -TRANSITIONEDGE)
- inertia_dir = 8
- else if(y <= TRANSITIONEDGE)
- inertia_dir = 1
- else if(y >= world.maxy -TRANSITIONEDGE)
- inertia_dir = 2
- to_chat(src, "Something you are carrying is preventing you from leaving.")
- return
-
- ..()
-
-//damage/heal the mob ears and adjust the deaf amount
-/mob/living/adjustEarDamage(var/damage, var/deaf)
- ear_damage = max(0, ear_damage + damage)
- ear_deaf = max(0, ear_deaf + deaf)
-
-//pass a negative argument to skip one of the variable
-/mob/living/setEarDamage(var/damage, var/deaf)
- if(damage >= 0)
- ear_damage = damage
- if(deaf >= 0)
- ear_deaf = deaf
-
-/mob/living/proc/vomit(var/skip_wait, var/blood_vomit)
- if(!check_has_mouth())
- return
-
- if(!lastpuke)
- lastpuke = 1
- if(isSynthetic())
- to_chat(src, "A sudden, dizzying wave of internal feedback rushes over you!")
- src.Weaken(5)
- else
- if (nutrition <= 100)
- to_chat(src, "You gag as you want to throw up, but there's nothing in your stomach!")
- src.Weaken(10)
- else
- to_chat(src, "You feel nauseous...")
-
- if(!skip_wait)
- sleep(150) //15 seconds until second warning
- to_chat(src, "You feel like you are about to throw up!")
- sleep(100) //and you have 10 more for mad dash to the bucket
-
- //Damaged livers cause you to vomit blood.
- if(!blood_vomit)
- if(ishuman(src))
- var/mob/living/carbon/human/H = src
- if(!H.isSynthetic())
- var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"]
- if(L.is_broken())
- blood_vomit = 1
-
- Stun(5)
- src.visible_message("[src] throws up!","You throw up!")
- playsound(loc, 'sound/effects/splat.ogg', 50, 1)
-
- var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs
- if(istype(T))
- if(blood_vomit)
- T.add_blood_floor(src)
- else
- T.add_vomit_floor(src, 1)
-
- if(blood_vomit)
- if(getBruteLoss() < 50)
- adjustBruteLoss(3)
- else
- nutrition -= 40
- adjustToxLoss(-3)
-
- sleep(350)
- lastpuke = 0
-
-/mob/living/update_canmove()
- if(!resting && cannot_stand() && can_stand_overridden())
- lying = 0
- canmove = 1
- else
- if(istype(buckled, /obj/vehicle))
- var/obj/vehicle/V = buckled
- if(is_physically_disabled())
- lying = 0
- canmove = 1
- if(!V.riding_datum) // If it has a riding datum, the datum handles moving the pixel_ vars.
- pixel_y = V.mob_offset_y - 5
- else
- if(buckled.buckle_lying != -1)
- lying = buckled.buckle_lying
- canmove = 1
- if(!V.riding_datum) // If it has a riding datum, the datum handles moving the pixel_ vars.
- pixel_y = V.mob_offset_y
- else if(buckled)
- anchored = 1
- canmove = 0
- if(istype(buckled))
- if(buckled.buckle_lying != -1)
- lying = buckled.buckle_lying
- if(buckled.buckle_movable)
- anchored = 0
- canmove = 1
- else
- lying = incapacitated(INCAPACITATION_KNOCKDOWN)
- canmove = !incapacitated(INCAPACITATION_DISABLED)
-
- if(lying)
- density = 0
- if(l_hand) unEquip(l_hand)
- if(r_hand) unEquip(r_hand)
- update_water() // Submerges the mob.
- else
- density = initial(density)
-
- for(var/obj/item/weapon/grab/G in grabbed_by)
- if(G.state >= GRAB_AGGRESSIVE)
- canmove = 0
- break
-
- if(lying != lying_prev)
- lying_prev = lying
- update_transform()
- //VOREStation Add
- if(lying && LAZYLEN(buckled_mobs))
- for(var/rider in buckled_mobs)
- var/mob/living/L = rider
- if(buckled_mobs[rider] != "riding")
- continue // Only boot off riders
- if(riding_datum)
- riding_datum.force_dismount(L)
- else
- unbuckle_mob(L)
- L.Stun(5)
- //VOREStation Add End
-
- return canmove
-
-// Adds overlays for specific modifiers.
-// You'll have to add your own implementation for non-humans currently, just override this proc.
-/mob/living/proc/update_modifier_visuals()
- return
-
-/mob/living/proc/update_water() // Involves overlays for humans. Maybe we'll get submerged sprites for borgs in the future?
- return
-
-/mob/living/proc/can_feel_pain(var/check_organ)
- if(isSynthetic())
- return FALSE
- return TRUE
-
-// Gets the correct icon_state for being on fire. See OnFire.dmi for the icons.
-/mob/living/proc/get_fire_icon_state()
- return "generic"
-
-// Called by job_controller.
-/mob/living/proc/equip_post_job()
- return
-
-// Used to check if something is capable of thought, in the traditional sense.
-/mob/living/proc/is_sentient()
- return TRUE
-
-
-/mob/living/update_transform()
- // First, get the correct size.
- var/desired_scale = size_multiplier //VOREStation edit
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.icon_scale_percent))
- desired_scale *= M.icon_scale_percent
-
- // Now for the regular stuff.
- var/matrix/M = matrix()
- M.Scale(desired_scale)
- M.Translate(0, 16*(desired_scale-1))
- src.transform = M
- //animate(src, transform = M, time = 10) //VOREStation edit
-
-
-// This handles setting the client's color variable, which makes everything look a specific color.
-// This proc is here so it can be called without needing to check if the client exists, or if the client relogs.
-/mob/living/update_client_color()
- if(!client)
- return
-
- var/list/colors_to_blend = list()
- for(var/datum/modifier/M in modifiers)
- if(!isnull(M.client_color))
- if(islist(M.client_color)) //It's a color matrix! Forget it. Just use that one.
- animate(client, color = M.client_color, time = 10)
- return
- colors_to_blend += M.client_color
-
- if(colors_to_blend.len)
- var/final_color
- if(colors_to_blend.len == 1) // If it's just one color we can skip all of this work.
- final_color = colors_to_blend[1]
-
- else // Otherwise we need to do some messy additive blending.
- var/R = 0
- var/G = 0
- var/B = 0
-
- for(var/C in colors_to_blend)
- var/RGB = hex2rgb(C)
- R = between(0, R + RGB[1], 255)
- G = between(0, G + RGB[2], 255)
- B = between(0, B + RGB[3], 255)
- final_color = rgb(R,G,B)
-
- if(final_color)
- var/old_color = client.color // Don't know if BYOND has an internal optimization to not care about animate() calls that effectively do nothing.
- if(final_color != old_color) // Gonna do a check just incase.
- animate(client, color = final_color, time = 10)
-
- else // No colors, so remove the client's color.
- animate(client, color = null, time = 10)
-
-/mob/living/swap_hand()
- src.hand = !( src.hand )
- if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object)
- if(hand) //This being 1 means the left hand is in use
- hud_used.l_hand_hud_object.icon_state = "l_hand_active"
- hud_used.r_hand_hud_object.icon_state = "r_hand_inactive"
- else
- hud_used.l_hand_hud_object.icon_state = "l_hand_inactive"
- hud_used.r_hand_hud_object.icon_state = "r_hand_active"
-
- // We just swapped hands, so the thing in our inactive hand will notice it's not the focus
- var/obj/item/I = get_inactive_hand()
- if(I)
- if(I.zoom)
- I.zoom()
- I.in_inactive_hand(src) //This'll do specific things, determined by the item
- return
-
-/mob/living/proc/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/throw_item(atom/target)
- src.throw_mode_off()
- if(usr.stat || !target)
- return
- if(target.type == /obj/screen) return
-
- var/atom/movable/item = src.get_active_hand()
-
- if(!item) return
-
- var/throw_range = item.throw_range
- if (istype(item, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = item
- item = G.throw_held() //throw the person instead of the grab
- if(ismob(item))
- var/mob/M = item
-
- //limit throw range by relative mob size
- throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1))
-
- var/turf/end_T = get_turf(target)
- if(end_T)
- add_attack_logs(src,M,"Thrown via grab to [end_T.x],[end_T.y],[end_T.z]")
-
- src.drop_from_inventory(item)
- if(!item || !isturf(item.loc))
- return
-
- //actually throw it!
- src.visible_message("[src] has thrown [item].")
-
- if(!src.lastarea)
- src.lastarea = get_area(src.loc)
- if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0))
- src.inertia_dir = get_dir(target, src)
- step(src, inertia_dir)
-
-
-/*
- if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction
- src.inertia_dir = get_dir(target, src)
- step(src, inertia_dir)
-*/
-
-
- item.throw_at(target, throw_range, item.throw_speed, src)
-
-/mob/living/get_sound_env(var/pressure_factor)
- if (hallucination)
- return PSYCHOTIC
- else if (druggy)
- return DRUGGED
- else if (drowsyness)
- return DIZZY
- else if (confused)
- return DIZZY
- else if (sleeping)
- return UNDERWATER
- else
- return ..()
-
-//Add an entry to overlays, assuming it exists
-/mob/living/proc/apply_hud(cache_index, var/image/I)
- hud_list[cache_index] = I
- if((. = hud_list[cache_index]))
- //underlays += .
- add_overlay(.)
-
-//Remove an entry from overlays, and from the list
-/mob/living/proc/grab_hud(cache_index)
- var/I = hud_list[cache_index]
- if(I)
- //underlays -= I
- cut_overlay(I)
- hud_list[cache_index] = null
- return I
-
-/mob/living/proc/make_hud_overlays()
- return
-
-
-/mob/living/proc/has_vision()
- return !(eye_blind || (disabilities & BLIND) || stat || blinded)
+/mob/living //for defining variables which all living mobs needs for various reasons
+ var/entangle_immunity = 0
+
+/mob/living/New()
+ ..()
+
+ //Prime this list if we need it.
+ if(has_huds)
+ add_overlay(backplane,TRUE) //Strap this on here, to block HUDs from appearing in rightclick menus: http://www.byond.com/forum/?post=2336679
+ hud_list = list()
+ hud_list.len = TOTAL_HUDS
+ make_hud_overlays()
+
+ //I'll just hang my coat up over here
+ dsoverlay = image('icons/mob/darksight.dmi',global_hud.darksight) //This is a secret overlay! Go look at the file, you'll see.
+ var/mutable_appearance/dsma = new(dsoverlay) //Changing like ten things, might as well.
+ dsma.alpha = 0
+ dsma.plane = PLANE_LIGHTING
+ dsma.blend_mode = BLEND_ADD
+ dsoverlay.appearance = dsma
+
+/mob/living/Destroy()
+ dsoverlay.loc = null //I'll take my coat with me
+ dsoverlay = null
+ if(buckled)
+ buckled.unbuckle_mob(src, TRUE)
+ return ..()
+
+//mob verbs are faster than object verbs. See mob/verb/examine.
+/mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1))
+ set name = "Pull"
+ set category = "Object"
+
+ if(AM.Adjacent(src))
+ src.start_pulling(AM)
+
+ return
+
+//mob verbs are faster than object verbs. See above.
+/mob/living/pointed(atom/A as mob|obj|turf in view())
+ if(src.stat || !src.canmove || src.restrained())
+ return 0
+ if(src.status_flags & FAKEDEATH)
+ return 0
+ if(!..())
+ return 0
+
+ usr.visible_message("[src] points to [A]")
+ return 1
+
+/*one proc, four uses
+swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive
+default behaviour is:
+ - non-passive mob passes the passive version
+ - passive mob checks to see if its mob_bump_flag is in the non-passive's mob_bump_flags
+ - if si, the proc returns
+*/
+/mob/living/proc/can_move_mob(var/mob/living/swapped, swapping = 0, passive = 0)
+ if(!swapped)
+ return 1
+ if(!passive)
+ return swapped.can_move_mob(src, swapping, 1)
+ else
+ var/context_flags = 0
+ if(swapping)
+ context_flags = swapped.mob_swap_flags
+ else
+ context_flags = swapped.mob_push_flags
+ if(!mob_bump_flag) //nothing defined, go wild
+ return 1
+ if(mob_bump_flag & context_flags)
+ return 1
+ return 0
+
+/mob/living/Bump(atom/movable/AM, yes)
+ spawn(0)
+ if ((!( yes ) || now_pushing) || !loc)
+ return
+ now_pushing = 1
+ if (istype(AM, /mob/living))
+ var/mob/living/tmob = AM
+
+ //Even if we don't push/swap places, we "touched" them, so spread fire
+ spread_fire(tmob)
+
+ for(var/mob/living/M in range(tmob, 1))
+ if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
+ if ( !(world.time % 5) )
+ to_chat(src, "[tmob] is restrained, you cannot push past")
+ now_pushing = 0
+ return
+ if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
+ if ( !(world.time % 5) )
+ to_chat(src, "[tmob] is restraining [M], you cannot push past")
+ now_pushing = 0
+ return
+
+ //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
+ var/dense = 0
+ if(loc.density)
+ dense = 1
+ for(var/atom/movable/A in loc)
+ if(A == src)
+ continue
+ if(A.density)
+ if(A.flags&ON_BORDER)
+ dense = !A.CanPass(src, src.loc)
+ else
+ dense = 1
+ if(dense) break
+
+ //Leaping mobs just land on the tile, no pushing, no anything.
+ if(status_flags & LEAPING)
+ loc = tmob.loc
+ status_flags &= ~LEAPING
+ now_pushing = 0
+ return
+
+ if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
+ var/turf/oldloc = loc
+ forceMove(tmob.loc)
+
+ //VOREstation Edit - Begin
+ if (istype(tmob, /mob/living/simple_animal)) //check bumpnom chance, if it's a simplemob that's bumped
+ tmob.Bumped(src)
+ else if(istype(src, /mob/living/simple_animal)) //otherwise, if it's a simplemob doing the bumping. Simplemob on simplemob doesn't seem to trigger but that's fine.
+ Bumped(tmob)
+ if (tmob.loc == src) //check if they got ate, and if so skip the forcemove
+ now_pushing = 0
+ return
+
+ // In case of micros, we don't swap positions; instead occupying the same square!
+ if (handle_micro_bump_helping(tmob))
+ now_pushing = 0
+ return
+ // TODO - Check if we need to do something about the slime.UpdateFeed() we are skipping below.
+ // VOREStation Edit - End
+
+ tmob.forceMove(oldloc)
+ now_pushing = 0
+ return
+
+ if(!can_move_mob(tmob, 0, 0))
+ now_pushing = 0
+ return
+ if(a_intent == I_HELP || src.restrained())
+ now_pushing = 0
+ return
+
+ // VOREStation Edit - Begin
+ // Plow that nerd.
+ if(ishuman(tmob))
+ var/mob/living/carbon/human/H = tmob
+ if(H.species.lightweight == 1 && prob(50))
+ H.visible_message("[src] bumps into [H], knocking them off balance!")
+ H.Weaken(5)
+ now_pushing = 0
+ return
+ // Handle grabbing, stomping, and such of micros!
+ if(handle_micro_bump_other(tmob)) return
+ // VOREStation Edit - End
+
+ if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
+ if(prob(40) && !(FAT in src.mutations))
+ to_chat(src, "You fail to push [tmob]'s fat ass out of the way.")
+ now_pushing = 0
+ return
+ if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot))
+ if(prob(99))
+ now_pushing = 0
+ return
+ if(tmob.l_hand && istype(tmob.l_hand, /obj/item/weapon/shield/riot))
+ if(prob(99))
+ now_pushing = 0
+ return
+ if(!(tmob.status_flags & CANPUSH))
+ now_pushing = 0
+ return
+
+ tmob.LAssailant = src
+
+ now_pushing = 0
+ spawn(0)
+ ..()
+ if (!istype(AM, /atom/movable) || AM.anchored)
+ //VOREStation Edit - object-specific proc for running into things
+ if(((confused || is_blind()) && stat == CONSCIOUS && prob(50) && m_intent=="run") || flying)
+ AM.stumble_into(src)
+ //VOREStation Edit End
+ /* VOREStation Removal - See above
+ Weaken(2)
+ playsound(loc, "punch", 25, 1, -1)
+ visible_message("[src] [pick("ran", "slammed")] into \the [AM]!")
+ src.apply_damage(5, BRUTE)
+ src << ("You just [pick("ran", "slammed")] into \the [AM]!")
+ to_chat(src, "You just [pick("ran", "slammed")] into \the [AM]!")
+ */ // VOREStation Removal End
+ return
+ if (!now_pushing)
+ if(isobj(AM))
+ var/obj/I = AM
+ if(!can_pull_size || can_pull_size < I.w_class)
+ return
+ now_pushing = 1
+
+ var/t = get_dir(src, AM)
+ if (istype(AM, /obj/structure/window))
+ for(var/obj/structure/window/win in get_step(AM,t))
+ now_pushing = 0
+ return
+ step(AM, t)
+ if(ishuman(AM) && AM:grabbed_by)
+ for(var/obj/item/weapon/grab/G in AM:grabbed_by)
+ step(G:assailant, get_dir(G:assailant, AM))
+ G.adjust_position()
+ now_pushing = 0
+ return
+ return
+
+/mob/living/verb/succumb()
+ set hidden = 1
+ if ((src.health < 0 && src.health > (5-src.getMaxHealth()))) // Health below Zero but above 5-away-from-death, as before, but variable
+ src.death()
+ to_chat(src, "You have given up life and succumbed to death.")
+ else
+ to_chat(src, "You are not injured enough to succumb to death!")
+
+/mob/living/proc/updatehealth()
+ if(status_flags & GODMODE)
+ health = 100
+ stat = CONSCIOUS
+ else
+ health = getMaxHealth() - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - halloss
+
+
+//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually
+//affects them once clothing is factored in. ~Errorage
+/mob/living/proc/calculate_affecting_pressure(var/pressure)
+ return
+
+
+//sort of a legacy burn method for /electrocute, /shock, and the e_chair
+/mob/living/proc/burn_skin(burn_amount)
+ if(istype(src, /mob/living/carbon/human))
+ //world << "DEBUG: burn_skin(), mutations=[mutations]"
+ if(mShock in src.mutations) //shockproof
+ return 0
+ if (COLD_RESISTANCE in src.mutations) //fireproof
+ return 0
+ var/mob/living/carbon/human/H = src //make this damage method divide the damage to be done among all the body parts, then burn each body part for that much damage. will have better effect then just randomly picking a body part
+ var/divided_damage = (burn_amount)/(H.organs.len)
+ var/extradam = 0 //added to when organ is at max dam
+ for(var/obj/item/organ/external/affecting in H.organs)
+ if(!affecting) continue
+ if(affecting.take_damage(0, divided_damage+extradam)) //TODO: fix the extradam stuff. Or, ebtter yet...rewrite this entire proc ~Carn
+ H.UpdateDamageIcon()
+ H.updatehealth()
+ return 1
+ else if(istype(src, /mob/living/silicon/ai))
+ return 0
+
+/mob/living/proc/adjustBodyTemp(actual, desired, incrementboost)
+ var/temperature = actual
+ var/difference = abs(actual-desired) //get difference
+ var/increments = difference/10 //find how many increments apart they are
+ var/change = increments*incrementboost // Get the amount to change by (x per increment)
+
+ // Too cold
+ if(actual < desired)
+ temperature += change
+ if(actual > desired)
+ temperature = desired
+ // Too hot
+ if(actual > desired)
+ temperature -= change
+ if(actual < desired)
+ temperature = desired
+// if(istype(src, /mob/living/carbon/human))
+// world << "[src] ~ [src.bodytemperature] ~ [temperature]"
+ return temperature
+
+
+// ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching.
+// Stop! ... Hammertime! ~Carn
+// I touched them without asking... I'm soooo edgy ~Erro (added nodamage checks)
+
+/mob/living/proc/getBruteLoss()
+ return bruteloss
+
+/mob/living/proc/getShockBruteLoss() //Only checks for things that'll actually hurt (not robolimbs)
+ return bruteloss
+
+/mob/living/proc/getActualBruteLoss() // Mostly for humans with robolimbs.
+ return getBruteLoss()
+
+//'include_robo' only applies to healing, for legacy purposes, as all damage typically hurts both types of organs
+/mob/living/proc/adjustBruteLoss(var/amount,var/include_robo)
+ if(status_flags & GODMODE) return 0 //godmode
+
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ amount *= M.incoming_damage_percent
+ if(!isnull(M.incoming_brute_damage_percent))
+ amount *= M.incoming_brute_damage_percent
+ else if(amount < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ amount *= M.incoming_healing_percent
+
+ bruteloss = min(max(bruteloss + amount, 0),(getMaxHealth()*2))
+ updatehealth()
+
+/mob/living/proc/getOxyLoss()
+ return oxyloss
+
+/mob/living/proc/adjustOxyLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ amount *= M.incoming_damage_percent
+ if(!isnull(M.incoming_oxy_damage_percent))
+ amount *= M.incoming_oxy_damage_percent
+ else if(amount < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ amount *= M.incoming_healing_percent
+
+ oxyloss = min(max(oxyloss + amount, 0),(getMaxHealth()*2))
+ updatehealth()
+
+/mob/living/proc/setOxyLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ oxyloss = amount
+
+/mob/living/proc/getToxLoss()
+ return toxloss
+
+/mob/living/proc/adjustToxLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ amount *= M.incoming_damage_percent
+ if(!isnull(M.incoming_tox_damage_percent))
+ amount *= M.incoming_tox_damage_percent
+ else if(amount < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ amount *= M.incoming_healing_percent
+
+ toxloss = min(max(toxloss + amount, 0),(getMaxHealth()*2))
+ updatehealth()
+
+/mob/living/proc/setToxLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ toxloss = amount
+
+/mob/living/proc/getFireLoss()
+ return fireloss
+
+/mob/living/proc/getShockFireLoss() //Only checks for things that'll actually hurt (not robolimbs)
+ return fireloss
+
+/mob/living/proc/getActualFireLoss() // Mostly for humans with robolimbs.
+ return getFireLoss()
+
+//'include_robo' only applies to healing, for legacy purposes, as all damage typically hurts both types of organs
+/mob/living/proc/adjustFireLoss(var/amount,var/include_robo)
+ if(status_flags & GODMODE) return 0 //godmode
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ amount *= M.incoming_damage_percent
+ if(!isnull(M.incoming_fire_damage_percent))
+ amount *= M.incoming_fire_damage_percent
+ else if(amount < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ amount *= M.incoming_healing_percent
+
+ fireloss = min(max(fireloss + amount, 0),(getMaxHealth()*2))
+ updatehealth()
+
+/mob/living/proc/getCloneLoss()
+ return cloneloss
+
+/mob/living/proc/adjustCloneLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ amount *= M.incoming_damage_percent
+ if(!isnull(M.incoming_clone_damage_percent))
+ amount *= M.incoming_clone_damage_percent
+ else if(amount < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ amount *= M.incoming_healing_percent
+
+ cloneloss = min(max(cloneloss + amount, 0),(getMaxHealth()*2))
+ updatehealth()
+
+/mob/living/proc/setCloneLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ cloneloss = amount
+
+/mob/living/proc/getBrainLoss()
+ return brainloss
+
+/mob/living/proc/adjustBrainLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ brainloss = min(max(brainloss + amount, 0),(getMaxHealth()*2))
+
+/mob/living/proc/setBrainLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ brainloss = amount
+
+/mob/living/proc/getHalLoss()
+ return halloss
+
+/mob/living/proc/adjustHalLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ amount *= M.incoming_damage_percent
+ if(!isnull(M.incoming_hal_damage_percent))
+ amount *= M.incoming_hal_damage_percent
+ if(!isnull(M.disable_duration_percent))
+ amount *= M.incoming_hal_damage_percent
+ else if(amount < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ amount *= M.incoming_healing_percent
+ halloss = min(max(halloss + amount, 0),(getMaxHealth()*2))
+ updatehealth()
+
+/mob/living/proc/setHalLoss(var/amount)
+ if(status_flags & GODMODE) return 0 //godmode
+ halloss = amount
+
+// Use this to get a mob's max health whenever possible. Reading maxHealth directly will give inaccurate results if any modifiers exist.
+/mob/living/proc/getMaxHealth()
+ var/result = maxHealth
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.max_health_flat))
+ result += M.max_health_flat
+ // Second loop is so we can get all the flat adjustments first before multiplying, otherwise the result will be different.
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.max_health_percent))
+ result *= M.max_health_percent
+ return result
+
+/mob/living/proc/setMaxHealth(var/newMaxHealth)
+ health = (health/maxHealth) * (newMaxHealth) //VOREStation Add - Adjust existing health
+ maxHealth = newMaxHealth
+
+/mob/living/Stun(amount)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/AdjustStunned(amount)
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/Weaken(amount)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/AdjustWeakened(amount)
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/Paralyse(amount)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/AdjustParalysis(amount)
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/Sleeping(amount)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/AdjustSleeping(amount)
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/Confuse(amount)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/AdjustConfused(amount)
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/Blind(amount)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+/mob/living/AdjustBlinded(amount)
+ if(amount > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.disable_duration_percent))
+ amount = round(amount * M.disable_duration_percent)
+ ..(amount)
+
+// ++++ROCKDTBEN++++ MOB PROCS //END
+
+/mob/proc/get_contents()
+
+
+//Recursive function to find everything a mob is holding.
+/mob/living/get_contents(var/obj/item/weapon/storage/Storage = null)
+ var/list/L = list()
+
+ if(Storage) //If it called itself
+ L += Storage.return_inv()
+
+ //Leave this commented out, it will cause storage items to exponentially add duplicate to the list
+ //for(var/obj/item/weapon/storage/S in Storage.return_inv()) //Check for storage items
+ // L += get_contents(S)
+
+ for(var/obj/item/weapon/gift/G in Storage.return_inv()) //Check for gift-wrapped items
+ L += G.gift
+ if(istype(G.gift, /obj/item/weapon/storage))
+ L += get_contents(G.gift)
+
+ for(var/obj/item/smallDelivery/D in Storage.return_inv()) //Check for package wrapped items
+ L += D.wrapped
+ if(istype(D.wrapped, /obj/item/weapon/storage)) //this should never happen
+ L += get_contents(D.wrapped)
+ return L
+
+ else
+
+ L += src.contents
+ for(var/obj/item/weapon/storage/S in src.contents) //Check for storage items
+ L += get_contents(S)
+
+ for(var/obj/item/weapon/gift/G in src.contents) //Check for gift-wrapped items
+ L += G.gift
+ if(istype(G.gift, /obj/item/weapon/storage))
+ L += get_contents(G.gift)
+
+ for(var/obj/item/smallDelivery/D in src.contents) //Check for package wrapped items
+ L += D.wrapped
+ if(istype(D.wrapped, /obj/item/weapon/storage)) //this should never happen
+ L += get_contents(D.wrapped)
+ return L
+
+/mob/living/proc/check_contents_for(A)
+ var/list/L = src.get_contents()
+
+ for(var/obj/B in L)
+ if(B.type == A)
+ return 1
+ return 0
+
+
+/mob/living/proc/can_inject()
+ return 1
+
+/mob/living/proc/get_organ_target()
+ var/mob/shooter = src
+ var/t = shooter:zone_sel.selecting
+ if ((t in list( O_EYES, O_MOUTH )))
+ t = BP_HEAD
+ var/obj/item/organ/external/def_zone = ran_zone(t)
+ return def_zone
+
+
+// heal ONE external organ, organ gets randomly selected from damaged ones.
+/mob/living/proc/heal_organ_damage(var/brute, var/burn)
+ adjustBruteLoss(-brute)
+ adjustFireLoss(-burn)
+ src.updatehealth()
+
+// damage ONE external organ, organ gets randomly selected from damaged ones.
+/mob/living/proc/take_organ_damage(var/brute, var/burn, var/emp=0)
+ if(status_flags & GODMODE) return 0 //godmode
+ adjustBruteLoss(brute)
+ adjustFireLoss(burn)
+ src.updatehealth()
+
+// heal MANY external organs, in random order
+/mob/living/proc/heal_overall_damage(var/brute, var/burn)
+ adjustBruteLoss(-brute)
+ adjustFireLoss(-burn)
+ src.updatehealth()
+
+// damage MANY external organs, in random order
+/mob/living/proc/take_overall_damage(var/brute, var/burn, var/used_weapon = null)
+ if(status_flags & GODMODE) return 0 //godmode
+ adjustBruteLoss(brute)
+ adjustFireLoss(burn)
+ src.updatehealth()
+
+/mob/living/proc/restore_all_organs()
+ return
+
+
+
+/mob/living/proc/revive()
+ rejuvenate()
+ if(buckled)
+ buckled.unbuckle_mob()
+ if(iscarbon(src))
+ var/mob/living/carbon/C = src
+
+ if (C.handcuffed && !initial(C.handcuffed))
+ C.drop_from_inventory(C.handcuffed)
+ C.handcuffed = initial(C.handcuffed)
+
+ if (C.legcuffed && !initial(C.legcuffed))
+ C.drop_from_inventory(C.legcuffed)
+ C.legcuffed = initial(C.legcuffed)
+ BITSET(hud_updateflag, HEALTH_HUD)
+ BITSET(hud_updateflag, STATUS_HUD)
+ BITSET(hud_updateflag, LIFE_HUD)
+ ExtinguishMob()
+ fire_stacks = 0
+
+/mob/living/proc/rejuvenate()
+ if(reagents)
+ reagents.clear_reagents()
+
+ // shut down various types of badness
+ setToxLoss(0)
+ setOxyLoss(0)
+ setCloneLoss(0)
+ setBrainLoss(0)
+ SetParalysis(0)
+ SetStunned(0)
+ SetWeakened(0)
+
+ // shut down ongoing problems
+ radiation = 0
+ nutrition = 400
+ bodytemperature = T20C
+ sdisabilities = 0
+ disabilities = 0
+
+ // fix blindness and deafness
+ blinded = 0
+ SetBlinded(0)
+ eye_blurry = 0
+ ear_deaf = 0
+ ear_damage = 0
+ heal_overall_damage(getBruteLoss(), getFireLoss())
+
+ // fix all of our organs
+ restore_all_organs()
+
+ // remove the character from the list of the dead
+ if(stat == DEAD)
+ dead_mob_list -= src
+ living_mob_list += src
+ tod = null
+ timeofdeath = 0
+
+ // restore us to conciousness
+ stat = CONSCIOUS
+
+ // make the icons look correct
+ regenerate_icons()
+
+ BITSET(hud_updateflag, HEALTH_HUD)
+ BITSET(hud_updateflag, STATUS_HUD)
+ BITSET(hud_updateflag, LIFE_HUD)
+
+ failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
+ reload_fullscreen()
+
+ return
+
+/mob/living/proc/UpdateDamageIcon()
+ return
+
+
+/mob/living/proc/Examine_OOC()
+ set name = "Examine Meta-Info (OOC)"
+ set category = "OOC"
+ set src in view()
+ //VOREStation Edit Start - Making it so SSD people have prefs with fallback to original style.
+ if(config.allow_Metadata)
+ if(ooc_notes)
+ to_chat(usr, "[src]'s Metainfo:
[ooc_notes]")
+ else if(client)
+ to_chat(usr, "[src]'s Metainfo:
[client.prefs.metadata]")
+ else
+ to_chat(usr, "[src] does not have any stored infomation!")
+ else
+ usr << "OOC Metadata is not supported by this server!"
+ //VOREStation Edit End - Making it so SSD people have prefs with fallback to original style.
+ return
+
+/mob/living/Move(a, b, flag)
+
+ if (buckled && buckled.loc != a) //not updating position
+ if(istype(buckled, /mob)) //If you're buckled to a mob, a la slime things, keep on rolling.
+ return buckled.Move(a, b)
+ else //Otherwise, no running around for you.
+ return 0
+
+ if (restrained())
+ stop_pulling()
+
+
+ var/t7 = 1
+ if (restrained())
+ for(var/mob/living/M in range(src, 1))
+ if ((M.pulling == src && M.stat == 0 && !( M.restrained() )))
+ t7 = null
+ if ((t7 && (pulling && ((get_dist(src, pulling) <= 1 || pulling.loc == loc) && (client && client.moving)))))
+ var/turf/T = loc
+ . = ..()
+
+ if (pulling && pulling.loc)
+ if(!( isturf(pulling.loc) ))
+ stop_pulling()
+ return
+
+ /////
+ if(pulling && pulling.anchored)
+ stop_pulling()
+ return
+
+ if (!restrained())
+ var/diag = get_dir(src, pulling)
+ if ((diag - 1) & diag)
+ else
+ diag = null
+ if ((get_dist(src, pulling) > 1 || diag))
+ if (isliving(pulling))
+ var/mob/living/M = pulling
+ var/atom/movable/t = M.pulling
+ M.stop_pulling()
+
+ if(!istype(M.loc, /turf/space))
+ var/area/A = get_area(M)
+ if(A.has_gravity)
+ //this is the gay blood on floor shit -- Added back -- Skie
+ if (M.lying && (prob(M.getBruteLoss() / 6)))
+ var/bloodtrail = 1 //Checks if it's possible to even spill blood
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.species.flags & NO_BLOOD)
+ bloodtrail = 0
+ else
+ var/blood_volume = round((H.vessel.get_reagent_amount("blood")/H.species.blood_volume)*100)
+ if(blood_volume < BLOOD_VOLUME_SURVIVE)
+ bloodtrail = 0 //Most of it's gone already, just leave it be
+ else
+ H.vessel.remove_reagent("blood", 1)
+ if(bloodtrail)
+ var/turf/location = M.loc
+ if(istype(location, /turf/simulated))
+ location.add_blood(M)
+ //pull damage with injured people
+ if(prob(25))
+ M.adjustBruteLoss(1)
+ visible_message("\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!")
+ if(M.pull_damage())
+ if(prob(25))
+ M.adjustBruteLoss(2)
+ visible_message("\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!")
+ var/turf/location = M.loc
+ if (istype(location, /turf/simulated))
+ var/bloodtrail = 1 //Checks if it's possible to even spill blood
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.species.flags & NO_BLOOD)
+ bloodtrail = 0
+ else
+ var/blood_volume = round((H.vessel.get_reagent_amount("blood")/H.species.blood_volume)*100)
+ if(blood_volume < BLOOD_VOLUME_SURVIVE)
+ bloodtrail = 0 //Most of it's gone already, just leave it be
+ else
+ H.vessel.remove_reagent("blood", 1)
+ if(bloodtrail)
+ if(istype(location, /turf/simulated))
+ location.add_blood(M)
+
+ step(pulling, get_dir(pulling.loc, T))
+ if(t)
+ M.start_pulling(t)
+ else
+ if (pulling)
+ if (istype(pulling, /obj/structure/window))
+ var/obj/structure/window/W = pulling
+ if(W.is_full_window())
+ for(var/obj/structure/window/win in get_step(pulling,get_dir(pulling.loc, T)))
+ stop_pulling()
+ if (pulling)
+ step(pulling, get_dir(pulling.loc, T))
+ else
+ stop_pulling()
+ . = ..()
+
+ if (s_active && !( s_active in contents ) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much.
+ s_active.close(src)
+
+/mob/living/proc/handle_footstep(turf/T)
+ return FALSE
+
+/mob/living/verb/resist()
+ set name = "Resist"
+ set category = "IC"
+
+ if(!incapacitated(INCAPACITATION_KNOCKOUT) && canClick())
+ setClickCooldown(20)
+ resist_grab()
+ if(!weakened)
+ process_resist()
+
+/mob/living/proc/process_resist()
+ //Getting out of someone's inventory.
+ if(istype(src.loc, /obj/item/weapon/holder))
+ escape_inventory(src.loc)
+ return
+
+ //unbuckling yourself
+ if(buckled)
+ spawn() escape_buckle()
+ return TRUE
+
+ //Breaking out of a locker?
+ if( src.loc && (istype(src.loc, /obj/structure/closet)) )
+ var/obj/structure/closet/C = loc
+ spawn() C.mob_breakout(src)
+ return TRUE
+
+ if(istype(loc,/obj/item/clothing))
+ spawn() escape_clothes(loc)
+
+ if(attempt_vr(src,"vore_process_resist",args)) return TRUE //VOREStation Code
+
+/mob/living/proc/escape_inventory(obj/item/weapon/holder/H)
+ if(H != src.loc) return
+
+ var/mob/M = H.loc //Get our mob holder (if any).
+
+ if(istype(M))
+ M.drop_from_inventory(H)
+ to_chat(M, "\The [H] wriggles out of your grip!")
+ to_chat(src, "You wriggle out of \the [M]'s grip!")
+
+ // Update whether or not this mob needs to pass emotes to contents.
+ for(var/atom/A in M.contents)
+ if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder))
+ return
+
+ else if(istype(H.loc,/obj/item/clothing/accessory/holster))
+ var/obj/item/clothing/accessory/holster/holster = H.loc
+ if(holster.holstered == H)
+ holster.clear_holster()
+ to_chat(src, "You extricate yourself from \the [holster].")
+ H.forceMove(get_turf(H))
+ else if(istype(H.loc,/obj/item))
+ to_chat(src, "You struggle free of \the [H.loc].")
+ H.forceMove(get_turf(H))
+
+//TFF 2/5/19: Polaris fix for resisting out of vehicles
+/mob/living/proc/escape_buckle()
+ if(buckled)
+ if(istype(buckled, /obj/vehicle))
+ var/obj/vehicle/vehicle = buckled
+ vehicle.unload()
+ else
+ buckled.user_unbuckle_mob(src, src)
+
+/mob/living/proc/resist_grab()
+ var/resisting = 0
+ for(var/obj/item/weapon/grab/G in grabbed_by)
+ resisting++
+ G.handle_resist()
+ if(resisting)
+ visible_message("[src] resists!")
+
+/mob/living/verb/lay_down()
+ set name = "Rest"
+ set category = "IC"
+
+ resting = !resting
+ to_chat(src, "You are now [resting ? "resting" : "getting up"]")
+ update_canmove()
+
+//called when the mob receives a bright flash
+/mob/living/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash)
+ if(override_blindness_check || !(disabilities & BLIND))
+ overlay_fullscreen("flash", type)
+ spawn(25)
+ if(src)
+ clear_fullscreen("flash", 25)
+ return 1
+
+/mob/living/proc/cannot_use_vents()
+ if(mob_size > MOB_SMALL)
+ return "You can't fit into that vent."
+ return null
+
+/mob/living/proc/has_brain()
+ return 1
+
+/mob/living/proc/has_eyes()
+ return 1
+
+/mob/living/proc/slip(var/slipped_on,stun_duration=8)
+ return 0
+
+/mob/living/carbon/drop_from_inventory(var/obj/item/W, var/atom/Target = null)
+ if(W in internal_organs)
+ return
+ ..()
+
+/mob/living/touch_map_edge()
+
+ //check for nuke disks
+ if(client && stat != DEAD) //if they are clientless and dead don't bother, the parent will treat them as any other container
+ if(ticker && istype(ticker.mode, /datum/game_mode/nuclear)) //only really care if the game mode is nuclear
+ var/datum/game_mode/nuclear/G = ticker.mode
+ if(G.check_mob(src))
+ if(x <= TRANSITIONEDGE)
+ inertia_dir = 4
+ else if(x >= world.maxx -TRANSITIONEDGE)
+ inertia_dir = 8
+ else if(y <= TRANSITIONEDGE)
+ inertia_dir = 1
+ else if(y >= world.maxy -TRANSITIONEDGE)
+ inertia_dir = 2
+ to_chat(src, "Something you are carrying is preventing you from leaving.")
+ return
+
+ ..()
+
+//damage/heal the mob ears and adjust the deaf amount
+/mob/living/adjustEarDamage(var/damage, var/deaf)
+ ear_damage = max(0, ear_damage + damage)
+ ear_deaf = max(0, ear_deaf + deaf)
+
+//pass a negative argument to skip one of the variable
+/mob/living/setEarDamage(var/damage, var/deaf)
+ if(damage >= 0)
+ ear_damage = damage
+ if(deaf >= 0)
+ ear_deaf = deaf
+
+/mob/living/proc/vomit(var/skip_wait, var/blood_vomit)
+ if(!check_has_mouth())
+ return
+
+ if(!lastpuke)
+ lastpuke = 1
+ if(isSynthetic())
+ to_chat(src, "A sudden, dizzying wave of internal feedback rushes over you!")
+ src.Weaken(5)
+ else
+ if (nutrition <= 100)
+ to_chat(src, "You gag as you want to throw up, but there's nothing in your stomach!")
+ src.Weaken(10)
+ else
+ to_chat(src, "You feel nauseous...")
+
+ if(!skip_wait)
+ sleep(150) //15 seconds until second warning
+ to_chat(src, "You feel like you are about to throw up!")
+ sleep(100) //and you have 10 more for mad dash to the bucket
+
+ //Damaged livers cause you to vomit blood.
+ if(!blood_vomit)
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ if(!H.isSynthetic())
+ var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"]
+ if(L.is_broken())
+ blood_vomit = 1
+
+ Stun(5)
+ src.visible_message("[src] throws up!","You throw up!")
+ playsound(loc, 'sound/effects/splat.ogg', 50, 1)
+
+ var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs
+ if(istype(T))
+ if(blood_vomit)
+ T.add_blood_floor(src)
+ else
+ T.add_vomit_floor(src, 1)
+
+ if(blood_vomit)
+ if(getBruteLoss() < 50)
+ adjustBruteLoss(3)
+ else
+ nutrition -= 40
+ adjustToxLoss(-3)
+
+ sleep(350)
+ lastpuke = 0
+
+/mob/living/update_canmove()
+ if(!resting && cannot_stand() && can_stand_overridden())
+ lying = 0
+ canmove = 1
+ else
+ if(istype(buckled, /obj/vehicle))
+ var/obj/vehicle/V = buckled
+ if(is_physically_disabled())
+ lying = 0
+ canmove = 1
+ if(!V.riding_datum) // If it has a riding datum, the datum handles moving the pixel_ vars.
+ pixel_y = V.mob_offset_y - 5
+ else
+ if(buckled.buckle_lying != -1)
+ lying = buckled.buckle_lying
+ canmove = 1
+ if(!V.riding_datum) // If it has a riding datum, the datum handles moving the pixel_ vars.
+ pixel_y = V.mob_offset_y
+ else if(buckled)
+ anchored = 1
+ canmove = 0
+ if(istype(buckled))
+ if(buckled.buckle_lying != -1)
+ lying = buckled.buckle_lying
+ if(buckled.buckle_movable)
+ anchored = 0
+ canmove = 1
+ else
+ lying = incapacitated(INCAPACITATION_KNOCKDOWN)
+ canmove = !incapacitated(INCAPACITATION_DISABLED)
+
+ if(lying)
+ density = 0
+ if(l_hand) unEquip(l_hand)
+ if(r_hand) unEquip(r_hand)
+ update_water() // Submerges the mob.
+ else
+ density = initial(density)
+
+ for(var/obj/item/weapon/grab/G in grabbed_by)
+ if(G.state >= GRAB_AGGRESSIVE)
+ canmove = 0
+ break
+
+ if(lying != lying_prev)
+ lying_prev = lying
+ update_transform()
+ //VOREStation Add
+ if(lying && LAZYLEN(buckled_mobs))
+ for(var/rider in buckled_mobs)
+ var/mob/living/L = rider
+ if(buckled_mobs[rider] != "riding")
+ continue // Only boot off riders
+ if(riding_datum)
+ riding_datum.force_dismount(L)
+ else
+ unbuckle_mob(L)
+ L.Stun(5)
+ //VOREStation Add End
+
+ return canmove
+
+// Adds overlays for specific modifiers.
+// You'll have to add your own implementation for non-humans currently, just override this proc.
+/mob/living/proc/update_modifier_visuals()
+ return
+
+/mob/living/proc/update_water() // Involves overlays for humans. Maybe we'll get submerged sprites for borgs in the future?
+ return
+
+/mob/living/proc/can_feel_pain(var/check_organ)
+ if(isSynthetic())
+ return FALSE
+ return TRUE
+
+// Gets the correct icon_state for being on fire. See OnFire.dmi for the icons.
+/mob/living/proc/get_fire_icon_state()
+ return "generic"
+
+// Called by job_controller.
+/mob/living/proc/equip_post_job()
+ return
+
+// Used to check if something is capable of thought, in the traditional sense.
+/mob/living/proc/is_sentient()
+ return TRUE
+
+
+/mob/living/update_transform()
+ // First, get the correct size.
+ var/desired_scale = size_multiplier //VOREStation edit
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.icon_scale_percent))
+ desired_scale *= M.icon_scale_percent
+
+ // Now for the regular stuff.
+ var/matrix/M = matrix()
+ M.Scale(desired_scale)
+ M.Translate(0, 16*(desired_scale-1))
+ src.transform = M
+ //animate(src, transform = M, time = 10) //VOREStation edit
+
+
+// This handles setting the client's color variable, which makes everything look a specific color.
+// This proc is here so it can be called without needing to check if the client exists, or if the client relogs.
+/mob/living/update_client_color()
+ if(!client)
+ return
+
+ var/list/colors_to_blend = list()
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.client_color))
+ if(islist(M.client_color)) //It's a color matrix! Forget it. Just use that one.
+ animate(client, color = M.client_color, time = 10)
+ return
+ colors_to_blend += M.client_color
+
+ if(colors_to_blend.len)
+ var/final_color
+ if(colors_to_blend.len == 1) // If it's just one color we can skip all of this work.
+ final_color = colors_to_blend[1]
+
+ else // Otherwise we need to do some messy additive blending.
+ var/R = 0
+ var/G = 0
+ var/B = 0
+
+ for(var/C in colors_to_blend)
+ var/RGB = hex2rgb(C)
+ R = between(0, R + RGB[1], 255)
+ G = between(0, G + RGB[2], 255)
+ B = between(0, B + RGB[3], 255)
+ final_color = rgb(R,G,B)
+
+ if(final_color)
+ var/old_color = client.color // Don't know if BYOND has an internal optimization to not care about animate() calls that effectively do nothing.
+ if(final_color != old_color) // Gonna do a check just incase.
+ animate(client, color = final_color, time = 10)
+
+ else // No colors, so remove the client's color.
+ animate(client, color = null, time = 10)
+
+/mob/living/swap_hand()
+ src.hand = !( src.hand )
+ if(hud_used.l_hand_hud_object && hud_used.r_hand_hud_object)
+ if(hand) //This being 1 means the left hand is in use
+ hud_used.l_hand_hud_object.icon_state = "l_hand_active"
+ hud_used.r_hand_hud_object.icon_state = "r_hand_inactive"
+ else
+ hud_used.l_hand_hud_object.icon_state = "l_hand_inactive"
+ hud_used.r_hand_hud_object.icon_state = "r_hand_active"
+
+ // We just swapped hands, so the thing in our inactive hand will notice it's not the focus
+ var/obj/item/I = get_inactive_hand()
+ if(I)
+ if(I.zoom)
+ I.zoom()
+ I.in_inactive_hand(src) //This'll do specific things, determined by the item
+ return
+
+/mob/living/proc/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/throw_item(atom/target)
+ src.throw_mode_off()
+ if(usr.stat || !target)
+ return
+ if(target.type == /obj/screen) return
+
+ var/atom/movable/item = src.get_active_hand()
+
+ if(!item) return
+
+ var/throw_range = item.throw_range
+ if (istype(item, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = item
+ item = G.throw_held() //throw the person instead of the grab
+ if(ismob(item))
+ var/mob/M = item
+
+ //limit throw range by relative mob size
+ throw_range = round(M.throw_range * min(src.mob_size/M.mob_size, 1))
+
+ var/turf/end_T = get_turf(target)
+ if(end_T)
+ add_attack_logs(src,M,"Thrown via grab to [end_T.x],[end_T.y],[end_T.z]")
+
+ src.drop_from_inventory(item)
+ if(!item || !isturf(item.loc))
+ return
+
+ //actually throw it!
+ src.visible_message("[src] has thrown [item].")
+
+ if(!src.lastarea)
+ src.lastarea = get_area(src.loc)
+ if((istype(src.loc, /turf/space)) || (src.lastarea.has_gravity == 0))
+ src.inertia_dir = get_dir(target, src)
+ step(src, inertia_dir)
+
+
+/*
+ if(istype(src.loc, /turf/space) || (src.flags & NOGRAV)) //they're in space, move em one space in the opposite direction
+ src.inertia_dir = get_dir(target, src)
+ step(src, inertia_dir)
+*/
+
+
+ item.throw_at(target, throw_range, item.throw_speed, src)
+
+/mob/living/get_sound_env(var/pressure_factor)
+ if (hallucination)
+ return PSYCHOTIC
+ else if (druggy)
+ return DRUGGED
+ else if (drowsyness)
+ return DIZZY
+ else if (confused)
+ return DIZZY
+ else if (sleeping)
+ return UNDERWATER
+ else
+ return ..()
+
+//Add an entry to overlays, assuming it exists
+/mob/living/proc/apply_hud(cache_index, var/image/I)
+ hud_list[cache_index] = I
+ if((. = hud_list[cache_index]))
+ //underlays += .
+ add_overlay(.)
+
+//Remove an entry from overlays, and from the list
+/mob/living/proc/grab_hud(cache_index)
+ var/I = hud_list[cache_index]
+ if(I)
+ //underlays -= I
+ cut_overlay(I)
+ hud_list[cache_index] = null
+ return I
+
+/mob/living/proc/make_hud_overlays()
+ return
+
+
+/mob/living/proc/has_vision()
+ return !(eye_blind || (disabilities & BLIND) || stat || blinded)
diff --git a/code/modules/mob/living/simple_animal/animals/tomato.dm b/code/modules/mob/living/simple_animal/animals/tomato.dm
index 59da8d5bb3..dbbcc14d83 100644
--- a/code/modules/mob/living/simple_animal/animals/tomato.dm
+++ b/code/modules/mob/living/simple_animal/animals/tomato.dm
@@ -1,215 +1,226 @@
-/mob/living/simple_animal/hostile/tomato
- name = "tomato"
- desc = "It's a horrifyingly enormous beef tomato, and it's packing extra beef!"
- tt_desc = "X Solanum abominable"
- icon_state = "tomato"
- icon_living = "tomato"
- icon_dead = "tomato_dead"
- intelligence_level = SA_PLANT
-
- faction = "plants"
- maxHealth = 15
- health = 15
- turns_per_move = 5
-
- response_help = "prods"
- response_disarm = "pushes aside"
- response_harm = "smacks"
-
- harm_intent_damage = 5
- melee_damage_upper = 15
- melee_damage_lower = 10
- attacktext = list("mauled")
-
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/tomatomeat
-
-//CHOMPEDIT PIRANHA PLANT.
-//When I stop being lazy I'll give this its own file -shark
-//Yes I'm basing this shit on the tomato, sue me. -shark
-//No longer based on tomato because evolved too far -shark
-/mob/living/simple_animal/hostile/piranhaplant
- name = "Piranha Plant"
- desc = "It's a plant, that eats people!"
- tt_desc = "Packun Flower"
-
- faction = "plants"
- intelligence_level = SA_PLANT
-
- maxHealth = 50
- health = 50
- meat_type = null
-
- //Mob icon/appearance settings
- icon = 'icons/mob/plantmobs32x32.dmi' //Thanks to vorebound mod and Estelle
- icon_living = "piranha-plant"
- icon_state = "piranha-plant"
- icon_dead = "piranha-plant_dead"
- icon_gib = "generic_gib" // The iconstate for being gibbed, optional. Defaults to a generic gib animation.
- //icon_rest = null // The iconstate for resting, optional
- attack_icon = 'icons/effects/effects.dmi' //Just the default, played like the weapon attack anim
- attack_icon_state = "slash" //Just the default //gonna have to make teeth chomping version
-
- //Vore stuff
- vore_active = 1
- vore_capacity = 1
- vore_pounce_chance = 10
- vore_standing_too = 1
- vore_ignores_undigestable = 0
- vore_default_mode = DM_DIGEST
- vore_digest_chance = 99
- vore_absorb_chance = 0
- vore_escape_chance = 5
- vore_icons = SA_ICON_LIVING
- swallowTime = 10 SECONDS //CHOMPED
-
- //Movement Stuff
- wander = 0 // Does the mob wander around when idle?
- wander_distance = 0 // How far the mob will wander before going home (assuming they are allowed to do that)
- returns_home = 1 // Mob knows how to return to wherever it started
- turns_per_move = 4 // How many life() cycles to wait between each wander mov?
- stop_when_pulled = 0 // When set to 1 this stops the animal from moving when someone is pulling it.
- follow_dist = 0 // Distance the mob tries to follow a friend
- speed = 4 // Higher speed is slower, negative speed is faster.
-
- //Talk/Emote stuff
- speak_chance = 0 // Probability that I talk (this is 'X in 200' chance since even 1/100 is pretty noisy)
- reacts = 1 // Reacts to some things being said
- speak = list() // Things I might say if I talk
- emote_hear = list("chomps","snaps at the air") // Hearable emotes I might perform
- emote_see = list() // Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps
- say_understood = list() // List of things to say when accepting an order
- say_cannot = list() // List of things to say when they cannot comply
- say_maybe_target = list() // List of things to say when they spot something barely
- say_got_target = list() // List of things to say when they engage a target
- reactions = list("chomp" = "!chomps",) // List of "string" = "reaction" and things they hear will be searched for string.
-
- //Hostility war bloodshed, RAWR
- hostile = 1 // Do I even attack?
- view_range = 2 // Scan for targets in this range.
- investigates = 1 // Do I investigate if I saw someone briefly?
- cooperative = 1 // Do I ask allies to help me?
- assist_distance = 2 // Radius in which I'll ask my comrades for help.
- grab_resist = 100 // Chance of me resisting a grab attempt.
- taser_kill = 1 // Is the mob weak to tasers
-
- //Melee behaviour
- melee_damage_lower = 1 // Lower bound of randomized melee damage
- melee_damage_upper = 25 // Upper bound of randomized melee damage
- attacktext = list("chomped","bit","hompfed","crunched","cronched") // "You are [attacktext] by the mob!"
- friendly = list("nuzzles") // "The mob [friendly] the person."
- //attack_sound = null // Sound to play when I attack
- environment_smash = 0 // How much environment damage do I do when I hit stuff?
- melee_miss_chance = 1 // percent chance to miss a melee attack.
- melee_attack_minDelay = 5 // How long between attacks at least
- melee_attack_maxDelay = 20 // How long between attacks at most
- attack_armor_type = "bio" // What armor does this check?
- attack_armor_pen = 50 // How much armor pen this attack has.
- attack_sharp = 1 // Is the attack sharp?
- attack_edge = 0 // Does the attack have an edge?
-
- //Stuff for people wanting to be a fucking plant. Weirdos
- show_stat_health = 1 // Does the percentage health show in the stat panel for the mob
- ai_inactive = 0 // Set to 1 to turn off most AI actions
- has_hands = 1 // Set to 1 to enable the use of hands and the hands hud
- humanoid_hands = 1 // Can a player in this mob use things like guns or AI cards?
- //hand_form = "hands" // Used in IsHumanoidToolUser. 'Your X are not fit-'.
- //hud_gears // Slots to show on the hud (typically none)
- //ui_icons // Icon file path to use for the HUD, otherwise generic icons are used
- //r_hand_sprite = "piranha_r" // If they have hands, //TODO make a leaf sprite for this
- //l_hand_sprite = "piranha_l" // they could use some icons.
- player_msg = "PLANT GO CHOMP" // Message to print to players about 'how' to play this mob on login.
-
-//Ranged variation
-/mob/living/simple_animal/hostile/piranhaplant/spitter
- //might snatch the code for that uranium ray for this since it should poison
- name = "Piranha Spitter"
- attack_armor_pen = 0
- //Attack ranged settings.
- ranged = 1 // Do I attack at range?
- shoot_range = 6 // How far away do I start shooting from?
- view_range = 5 //More range, more hurt, more... plant?
- rapid = 1 // Three-round-burst fire mode
- firing_lines = 0 // Avoids shooting allies
- projectiletype = /obj/item/projectile/energy/piranhaspit // The projectiles I shoot
- projectilesound = 'sound/weapons/thudswoosh.ogg' // The sound I make when I do it
- casingtype = /obj/item/weapon/reagent_containers/food/snacks/soylentgreen/piranha // What to make the hugely laggy casings pile out of
-
-//Piranha unique projectile
-/obj/item/projectile/energy/piranhaspit
- name = "piranhaspit"
- icon_state = "neurotoxin"
- damage = 4 //Reduced damage to 4 from 10, 3 fired projectiles mean might do 12 total if all 3 hit
- damage_type = TOX
- check_armour = "bio" //yup biohazard protection works here
- flash_strength = 0
- agony = 10
- combustion = FALSE
-
-/obj/item/weapon/reagent_containers/food/snacks/soylentgreen/piranha
- name = "Soylent"
- desc = "This was spat out by a strange plant that eats people."
- icon_state = "soylent_green"
- filling_color = "#B8E6B5"
- center_of_mass = list("x"=15, "y"=11)
-
-/obj/item/projectile/energy/piranhaspit/on_hit(var/atom/soyled)
- soyl(soyled)
- ..()
-
-/obj/item/projectile/energy/piranhaspit/proc/soyl(var/mob/M)
- var/location = get_turf(M)
- new /obj/item/weapon/reagent_containers/food/snacks/soylentgreen/piranha(location)
-
-//VORE FLUFF section and extended gut settings
-/mob/living/simple_animal/hostile/piranhaplant/init_vore()
- ..()
- var/obj/belly/B = vore_selected
- B.vore_verb = "chomp up"
- B.name = "stomach"
- B.desc = "You're pulled into the tight stomach of the plant. The walls knead weakly around you, coating you in thick, viscous fluids that cling to your body, that soon starts to tingle and burn..."
- B.digest_burn = 0
- B.digest_brute = 12
-
-/mob/living/simple_animal/hostile/piranhaplant/pitcher
- icon_state = "pitcher"
- icon_living = "pitcher"
- name = "Pitcher Plant"
- desc = "It's a plant! How pretty"
- tt_desc = "Brig Flower"
- health = 50
- maxHealth = 50 //starts with 50
- var/antispam = 0
-
-/mob/living/simple_animal/hostile/piranhaplant/pitcher/death()
- ..()
- new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
- new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
- new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
- new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
- qdel(src)
-
-/mob/living/simple_animal/hostile/piranhaplant/pitcher/Life()
- ..()
- if(!anchored)
- anchored=1
- if(maxHealth <= 499) //Ok maybe there are limits
- maxHealth = health //Limits are merely a suggestion
- if(vore_fullness && !antispam)
- antispam = 1
- spawn(10)
- if(maxHealth <= 499)
- maxHealth += 1
- health += 1
- antispam = !antispam
-
- if(size_multiplier!=1*health/100)
- size_multiplier=1*health/100
- update_icons()
-
-/mob/living/simple_animal/hostile/piranhaplant/pitcher/init_vore()
- ..()
- var/obj/belly/B = vore_selected
- B.digest_burn = 0.5
- B.digest_brute = 0
- B.vore_verb = "slurped up"
- B.name = "pitcher"
+/mob/living/simple_animal/hostile/tomato
+ name = "tomato"
+ desc = "It's a horrifyingly enormous beef tomato, and it's packing extra beef!"
+ tt_desc = "X Solanum abominable"
+ icon_state = "tomato"
+ icon_living = "tomato"
+ icon_dead = "tomato_dead"
+ intelligence_level = SA_PLANT
+
+ faction = "plants"
+ maxHealth = 15
+ health = 15
+ turns_per_move = 5
+
+ response_help = "prods"
+ response_disarm = "pushes aside"
+ response_harm = "smacks"
+
+ harm_intent_damage = 5
+ melee_damage_upper = 15
+ melee_damage_lower = 10
+ attacktext = list("mauled")
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/tomatomeat
+
+//CHOMPEDIT PIRANHA PLANT.
+//When I stop being lazy I'll give this its own file -shark
+//Yes I'm basing this shit on the tomato, sue me. -shark
+//No longer based on tomato because evolved too far -shark
+/mob/living/simple_animal/hostile/piranhaplant
+ name = "Piranha Plant"
+ desc = "It's a plant, that eats people!"
+ tt_desc = "Packun Flower"
+
+ faction = "plants"
+ intelligence_level = SA_PLANT
+
+ maxHealth = 50
+ health = 50
+ meat_type = null
+
+ //Mob icon/appearance settings
+ icon = 'icons/mob/plantmobs32x32.dmi' //Thanks to vorebound mod and Estelle
+ icon_living = "piranha-plant"
+ icon_state = "piranha-plant"
+ icon_dead = "piranha-plant_dead"
+ icon_gib = "generic_gib" // The iconstate for being gibbed, optional. Defaults to a generic gib animation.
+ //icon_rest = null // The iconstate for resting, optional
+ attack_icon = 'icons/effects/effects.dmi' //Just the default, played like the weapon attack anim
+ attack_icon_state = "slash" //Just the default //gonna have to make teeth chomping version
+
+ //Vore stuff
+ vore_active = 1
+ vore_capacity = 1
+ vore_pounce_chance = 10
+ vore_standing_too = 1
+ vore_ignores_undigestable = 0
+ vore_default_mode = DM_DIGEST
+ vore_digest_chance = 99
+ vore_absorb_chance = 0
+ vore_escape_chance = 5
+ vore_icons = SA_ICON_LIVING
+ swallowTime = 10 SECONDS //CHOMPED
+
+ //Movement Stuff
+ wander = 0 // Does the mob wander around when idle?
+ wander_distance = 0 // How far the mob will wander before going home (assuming they are allowed to do that)
+ returns_home = 1 // Mob knows how to return to wherever it started
+ turns_per_move = 4 // How many life() cycles to wait between each wander mov?
+ stop_when_pulled = 0 // When set to 1 this stops the animal from moving when someone is pulling it.
+ follow_dist = 0 // Distance the mob tries to follow a friend
+ speed = 4 // Higher speed is slower, negative speed is faster.
+ entangle_immunity = 1 //makes mob immune to entangle effect of vines and also wont get stabbed by vines that has thorns
+
+ //Talk/Emote stuff
+ speak_chance = 0 // Probability that I talk (this is 'X in 200' chance since even 1/100 is pretty noisy)
+ reacts = 1 // Reacts to some things being said
+ speak = list() // Things I might say if I talk
+ emote_hear = list("chomps","snaps at the air") // Hearable emotes I might perform
+ emote_see = list() // Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps
+ say_understood = list() // List of things to say when accepting an order
+ say_cannot = list() // List of things to say when they cannot comply
+ say_maybe_target = list() // List of things to say when they spot something barely
+ say_got_target = list() // List of things to say when they engage a target
+ reactions = list("chomp" = "!chomps",) // List of "string" = "reaction" and things they hear will be searched for string.
+
+ //Hostility war bloodshed, RAWR
+ hostile = 1 // Do I even attack?
+ view_range = 2 // Scan for targets in this range.
+ investigates = 1 // Do I investigate if I saw someone briefly?
+ cooperative = 1 // Do I ask allies to help me?
+ assist_distance = 2 // Radius in which I'll ask my comrades for help.
+ grab_resist = 100 // Chance of me resisting a grab attempt.
+ taser_kill = 1 // Is the mob weak to tasers
+
+ //Melee behaviour
+ melee_damage_lower = 1 // Lower bound of randomized melee damage
+ melee_damage_upper = 25 // Upper bound of randomized melee damage
+ attacktext = list("chomped","bit","hompfed","crunched","cronched") // "You are [attacktext] by the mob!"
+ friendly = list("nuzzles") // "The mob [friendly] the person."
+ //attack_sound = null // Sound to play when I attack
+ environment_smash = 0 // How much environment damage do I do when I hit stuff?
+ melee_miss_chance = 1 // percent chance to miss a melee attack.
+ melee_attack_minDelay = 5 // How long between attacks at least
+ melee_attack_maxDelay = 20 // How long between attacks at most
+ attack_armor_type = "bio" // What armor does this check?
+ attack_armor_pen = 50 // How much armor pen this attack has.
+ attack_sharp = 1 // Is the attack sharp?
+ attack_edge = 0 // Does the attack have an edge?
+
+ //Stuff for people wanting to be a fucking plant. Weirdos
+ show_stat_health = 1 // Does the percentage health show in the stat panel for the mob
+ ai_inactive = 0 // Set to 1 to turn off most AI actions
+ has_hands = 1 // Set to 1 to enable the use of hands and the hands hud
+ humanoid_hands = 1 // Can a player in this mob use things like guns or AI cards?
+ //hand_form = "hands" // Used in IsHumanoidToolUser. 'Your X are not fit-'.
+ //hud_gears // Slots to show on the hud (typically none)
+ //ui_icons // Icon file path to use for the HUD, otherwise generic icons are used
+ //r_hand_sprite = "piranha_r" // If they have hands, //TODO make a leaf sprite for this
+ //l_hand_sprite = "piranha_l" // they could use some icons.
+ player_msg = "PLANT GO CHOMP" // Message to print to players about 'how' to play this mob on login.
+
+//Ranged variation
+/mob/living/simple_animal/hostile/piranhaplant/spitter
+ //might snatch the code for that uranium ray for this since it should poison
+ name = "Piranha Spitter"
+ attack_armor_pen = 0
+ //Attack ranged settings.
+ ranged = 1 // Do I attack at range?
+ shoot_range = 6 // How far away do I start shooting from?
+ view_range = 5 //More range, more hurt, more... plant?
+ rapid = 1 // Three-round-burst fire mode
+ firing_lines = 0 // Avoids shooting allies
+ projectiletype = /obj/item/projectile/energy/piranhaspit // The projectiles I shoot
+ projectilesound = 'sound/weapons/thudswoosh.ogg' // The sound I make when I do it
+ ranged_ignore_incapitated = 1 //make it so our spitter doesnt stun lock dorks
+ ranged_cooldown_time = 90
+
+//mob/living/simple_animal/hostile/piranhaplant/spitter/proc/Shoot()
+ //TOX/HALLOSS swap code goes here //TODO
+
+//Piranha unique projectile
+/obj/item/projectile/energy/piranhaspit
+ name = "piranha spit"
+ icon_state = "neurotoxin"
+ damage = 10
+ damage_type = HALLOSS
+ check_armour = "bio" //yup biohazard protection works here
+ flash_strength = 0
+ agony = 10
+ combustion = FALSE
+
+/obj/item/weapon/reagent_containers/food/snacks/soylentgreen/piranha
+ name = "Soylent"
+ desc = "This was spat out by a strange plant that eats people."
+ icon_state = "soylent_green"
+ filling_color = "#B8E6B5"
+ center_of_mass = list("x"=15, "y"=11)
+
+/obj/item/projectile/energy/piranhaspit/on_hit(var/atom/soyled)
+ if(prob(5))
+ soyl(soyled)
+ ..()
+
+/obj/item/projectile/energy/piranhaspit/proc/soyl(var/mob/M)
+ var/location = get_turf(M)
+ new /obj/item/weapon/reagent_containers/food/snacks/soylentgreen/piranha(location)
+
+//VORE FLUFF section and extended gut settings
+/mob/living/simple_animal/hostile/piranhaplant/init_vore()
+ ..()
+ var/obj/belly/B = vore_selected
+ B.vore_verb = "chomp up"
+ B.name = "stomach"
+ B.desc = "You're pulled into the tight stomach of the plant. The walls knead weakly around you, coating you in thick, viscous fluids that cling to your body, that soon starts to tingle and burn..."
+ B.digest_burn = 0
+ B.digest_brute = 12
+
+/mob/living/simple_animal/hostile/piranhaplant/pitcher
+ icon_state = "pitcher-plant"
+ icon_living = "pitcher-plant"
+ icon_dead = "pitcher-plant_dead"
+ name = "Pitcher Plant"
+ desc = "It's a plant! How pretty"
+ tt_desc = "Brig Flower"
+ health = 500
+ maxHealth = 500
+ var/antispam = 0
+ swallowTime = 3 SECONDS //If you get to close to a pitcher, its your own fault ;p
+
+/mob/living/simple_animal/hostile/piranhaplant/pitcher/death()
+ ..()
+ new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
+ new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
+ new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
+ new /obj/item/weapon/reagent_containers/food/snacks/aesirsalad(location)
+ qdel(src)
+
+/mob/living/simple_animal/hostile/piranhaplant/pitcher/Life()
+ ..()
+ if(!anchored)
+ anchored=1
+ if(vore_fullness && !antispam)
+ antispam = 1
+ spawn(10)
+ if(bruteloss >= 1)
+ bruteloss -= 1
+ antispam = !antispam
+ if(prob(3))
+ new /obj/item/weapon/reagent_containers/food/snacks/soylentgreen/piranha(src.loc)
+
+ if(size_multiplier!=1*health/100 && health >= 50 && health <= 300)
+ size_multiplier=1*health/100
+ update_icons()
+
+/mob/living/simple_animal/hostile/piranhaplant/pitcher/New()
+ ..()
+ bruteloss = 400
+
+/mob/living/simple_animal/hostile/piranhaplant/pitcher/init_vore()
+ ..()
+ var/obj/belly/B = vore_selected
+ B.digest_burn = 0.5
+ B.digest_brute = 0
+ B.vore_verb = "slurp up"
+ B.name = "pitcher"
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index c1751ef5ba..f6a0d921ce 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -121,7 +121,8 @@
var/retreat_distance = null //If our mob runs from players when they're too close, set in tile distance. By default, mobs do not retreat.
var/minimum_distance = 1 //Minimum approach distance, so ranged mobs chase targets down, but still keep their distance set in tiles to the target, set higher to make mobs keep distance
var/move_shoot = 0
-
+ var/ranged_ignore_incapitated = 0 //Ranged mobs will by default keep shooting on unconscious targets, if set to 1 the mob will ignore unconscious victims.
+
//Mob melee settings
var/melee_damage_lower = 2 // Lower bound of randomized melee damage
var/melee_damage_upper = 6 // Upper bound of randomized melee damage
@@ -1270,19 +1271,24 @@
ai_log("AttackTarget() special",3)
if(SpecialAtkTarget()) //Might not succeed/be allowed, do something else.
return 1
-
+
//AAAAH!
if(distance <= 1)
ai_log("AttackTarget() melee",3)
PunchTarget()
return 1
-
+
//Open fire!
else if(ranged && (distance <= shoot_range) && ranged_cooldown <= world.time)
+ if(ishuman(target_mob) && ranged_ignore_incapitated)
+ var/mob/living/carbon/human/TA = target_mob
+ if(TA.stat == UNCONSCIOUS)
+ LoseTarget(TA)
+ return
ai_log("AttackTarget() ranged",3)
ShootTarget(target_mob)
return 1
-
+
else
ai_log("AttackTarget() out of range!",3)
stoplag(1) // Unfortunately this is needed to protect from ClosestDistance() sometimes not updating fast enough to prevent an infinite loop.
@@ -1777,5 +1783,5 @@
/mob/living/simple_animal/get_nametag_desc(mob/user)
return "[tt_desc]"
-
-
+
+
diff --git a/icons/mob/plantmobs32x32.dmi b/icons/mob/plantmobs32x32.dmi
index a000b245d6..83c5d1bdde 100644
Binary files a/icons/mob/plantmobs32x32.dmi and b/icons/mob/plantmobs32x32.dmi differ