Adds limb destroyer behavior to hostile mobs. (#19451)

* Adds limb destroyer behavior to hostile mobs. Mobs with this behavior will (usually [thanks proc/ran_zone]) attack the weakest limb of a mob until it gets dismembered

Adds ishostile() for this pretty specific situation

Behavior added to viscerators

* Generalizes the ability to dismember with an unarmed strike to living

* Gives xenos limb_destroyer at WJohn consultation

If a monkey or a human is var edited to have destroyer, that works now

fixes a potential runtime
This commit is contained in:
Incoming5643
2016-07-25 21:14:28 +12:00
committed by oranges
parent 3d034ed54e
commit c3f5870df5
11 changed files with 43 additions and 6 deletions
@@ -3,6 +3,7 @@
icon_state = "alien_s"
pass_flags = PASSTABLE
butcher_results = list(/obj/item/weapon/reagent_containers/food/snacks/meat/slab/xeno = 5, /obj/item/stack/sheet/animalhide/xeno = 1)
limb_destroyer = 1
var/obj/item/r_store = null
var/obj/item/l_store = null
var/caste = ""
@@ -103,4 +103,26 @@
"<span class='userdanger'>[src] devours you!</span>")
C.forceMove(src)
stomach_contents.Add(C)
add_logs(src, C, "devoured")
add_logs(src, C, "devoured")
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
if(!attacker.limb_destroyer || !has_limbs)
return dam_zone
var/obj/item/bodypart/affecting
if(dam_zone && attacker.client)
affecting = get_bodypart(ran_zone(dam_zone))
else
var/list/things_to_ruin = shuffle(bodyparts.Copy())
for(var/B in things_to_ruin)
var/obj/item/bodypart/bodypart = B
if(bodypart.body_zone == "head" || bodypart.body_zone == "chest")
continue
if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage)))
affecting = bodypart
if(affecting)
dam_zone = affecting.body_zone
if(affecting.get_damage() >= affecting.max_damage)
affecting.dismember()
return null
return affecting.body_zone
return dam_zone
@@ -19,7 +19,8 @@
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
"<span class='userdanger'>[M] has slashed at [src]!</span>")
if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
return 1
apply_damage(damage, BRUTE, affecting, armor_block)
if (prob(30))
visible_message("<span class='danger'>[M] has wounded [src]!</span>", \
@@ -6,6 +6,9 @@
..() //shaking
return 0
if(M.limb_destroyer)
dismembering_strike(M, affecting.body_zone)
if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites.
if(..()) //successful monkey bite, this handles disease contraction.
var/damage = rand(1, 3)
@@ -271,7 +271,9 @@
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration))
return 0
var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
if(!dam_zone) //Dismemberment successful
return 1
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration)
apply_damage(damage, M.melee_damage_type, affecting, armor)
@@ -301,7 +303,9 @@
if(check_shields(damage, "the [M.name]"))
return 0
var/dam_zone = pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg", "groin")
var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg"))
if(!dam_zone) //Dismemberment successful
return 1
var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
var/armor_block = run_armor_check(affecting, "melee")
@@ -970,6 +970,8 @@
H.visible_message("<span class='danger'>[M] has [atk_verb]ed [H]!</span>", \
"<span class='userdanger'>[M] has [atk_verb]ed [H]!</span>")
if(M.limb_destroyer)
H.dismembering_strike(M, affecting.body_zone)
H.apply_damage(damage, BRUTE, affecting, armor_block)
add_logs(M, H, "punched")
if((H.stat != DEAD) && damage >= M.dna.species.punchstunthreshold)
@@ -41,6 +41,8 @@
var/bloodcrawl = 0 //0 No blood crawling, BLOODCRAWL for bloodcrawling, BLOODCRAWL_EAT for crawling+mob devour
var/holder = null //The holder for blood crawling
var/ventcrawler = 0 //0 No vent crawling, 1 vent crawling in the nude, 2 vent crawling always
var/limb_destroyer = 0 //1 Sets AI behavior that allows mobs to target and dismember limbs with their basic attack.
var/floating = 0
var/mob_size = MOB_SIZE_HUMAN
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
@@ -41,7 +41,6 @@
var/stat_attack = 0 //Mobs with stat_attack to 1 will attempt to attack things that are unconscious, Mobs with stat_attack set to 2 will attempt to attack the dead.
var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
@@ -161,6 +161,7 @@
minbodytemp = 0
mob_size = MOB_SIZE_TINY
flying = 1
limb_destroyer = 1
speak_emote = list("states")
bubble_icon = "syndibot"
gold_core_spawnable = 1
@@ -596,7 +596,7 @@
/obj/effect/timestop/proc/unfreeze_mob(mob/living/M)
M.AdjustStunned(-10, 1, 1)
M.anchored = 0
if(istype(M, /mob/living/simple_animal/hostile))
if(ishostile(M))
var/mob/living/simple_animal/hostile/H = M
H.AIStatus = initial(H.AIStatus)