[MIRROR] Allows for hostile mobs to perform charge attacks, and adds a giant tackling lobster. (#651)

* Allows for hostile mobs to perform charge attacks, and adds a giant tackling lobster.  (#52692)

Example video: https://youtu.be/EAVuPtJ_kFM

This adds a new mob, the lobstrosity. It's a upper-caves level icemoon mob, created as a genetic combination of a lobster, a crab, and a shrimp, let loose on the horrific Alaskan hellscape that is the icemoon. It's best feature, however, is that it makes use of a new feature of simplemobs, charging. Any hostile simplemob can be configured and customized in a uniform way in order to become a charger, giving it a basic leap attack, that will disable the user if they find themselves crashing into an unpassable turf, but otherwise lands a knockdown on the attacking target. Compensate of this, charging mobs will also gain a very noticable tell, where they shake a moment before they actually perform the charge to better signify that they're rearing up for a melee charge.
I'm not exactly sold on using Shake() for the visual tell, but I'm not quite sold on a visual to showcase that it's happening, so I'm looking for feedback on that specifically.
Additionally, there is a bit of weird movement that I've yet to really get ironed out first but for the most part it's completely functional.

After some feedback, there's now a reddish, lavaland-colored lobster, as well as an arctic themed, Alaskan lobster

So on a massive tangential leap of logic, one thing ActionNinja brought up in a recent discord rant was that there are so many mechanical parts of SS13 combat that completely lack a tell whatsoever, or the tell is so quick you can blink and you'll miss it in a heartbeat. So I turned to the greatest enemy attack feedback mechanic that any game has ever seen: the Legend of Zelda Bull.

...also I've been looking for a tasteful way to get this sprite in-game for awhile now but wanted to really iron out a unique mechanic to go alongside it that would make it feel a little less bullshit to fight against.

ArcaneMusic + Kryson on Sprites

* Allows for hostile mobs to perform charge attacks, and adds a giant tackling lobster.

Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
This commit is contained in:
SkyratBot
2020-09-06 05:38:38 +02:00
committed by GitHub
co-authored by ArcaneMusic
parent 8b1d92ebf9
commit 878c232010
5 changed files with 119 additions and 2 deletions
@@ -48,10 +48,22 @@
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction
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
var/attack_all_objects = FALSE //if true, equivalent to having a wanted_objects list containing ALL objects.
var/lose_patience_timer_id //id for a timer to call LoseTarget(), used to stop mobs fixating on a target they can't reach
var/lose_patience_timeout = 300 //30 seconds by default, so there's no major changes to AI behaviour, beyond actually bailing if stuck forever
///When a target is found, will the mob attempt to charge at it's target?
var/charger = FALSE
///Tracks if the target is actively charging.
var/charge_state = FALSE
///In a charge, how many tiles will the charger travel?
var/charge_distance = 3
///How often can the charging mob actually charge? Effects the cooldown between charges.
var/charge_frequency = 6 SECONDS
///If the mob is charging, how long will it stun it's target on success, and itself on failure?
var/knockdown_time = 3 SECONDS
///Declares a cooldown for potential charges right off the bat.
COOLDOWN_DECLARE(charge_cooldown)
/mob/living/simple_animal/hostile/Initialize()
. = ..()
@@ -274,6 +286,9 @@
if(ranged) //We ranged? Shoot at em
if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
if(charger && (target_distance > minimum_distance) && (target_distance <= charge_distance))//Attempt to close the distance with a charge.
enter_charge(target)
return TRUE
if(!Process_Spacemove()) //Drifting
walk(src,0)
return 1
@@ -577,3 +592,61 @@
friends = fren
faction = fren.faction.Copy()
return ..()
/**
* Proc that handles a charge attack windup for a mob.
*/
/mob/living/simple_animal/hostile/proc/enter_charge(var/atom/target)
if((mobility_flags & (MOBILITY_MOVE | MOBILITY_STAND)) != (MOBILITY_MOVE | MOBILITY_STAND) || charge_state)
return FALSE
if(!(COOLDOWN_FINISHED(src, charge_cooldown)) || !has_gravity() || !target.has_gravity())
return FALSE
Shake(15, 15, 1 SECONDS)
addtimer(CALLBACK(src, .proc/handle_charge_target, target), 1.5 SECONDS, TIMER_STOPPABLE)
/**
* Proc that throws the mob at the target after the windup.
*/
/mob/living/simple_animal/hostile/proc/handle_charge_target(var/atom/target)
charge_state = TRUE
throw_at(target, charge_distance, 1, src, FALSE, TRUE, callback = CALLBACK(src, .proc/charge_end))
COOLDOWN_START(src, charge_cooldown, charge_frequency)
return TRUE
/**
* Proc that handles a charge attack after it's concluded.
*/
/mob/living/simple_animal/hostile/proc/charge_end()
charge_state = FALSE
/**
* Proc that handles the charge impact of the charging mob.
*/
/mob/living/simple_animal/hostile/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!charge_state)
return ..()
if(hit_atom)
if(isliving(hit_atom))
var/mob/living/L = hit_atom
var/blocked = FALSE
if(ishuman(hit_atom))
var/mob/living/carbon/human/H = hit_atom
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
blocked = TRUE
if(!blocked)
L.visible_message("<span class='danger'>[src] charges on [L]!</span>", "<span class='userdanger'>[src] charges into you!</span>")
L.Knockdown(knockdown_time)
else
Stun((knockdown_time * 2), 1, 1)
charge_end()
else if(hit_atom.density && !hit_atom.CanPass(src))
visible_message("<span class='danger'>[src] smashes into [hit_atom]!</span>")
Stun((knockdown_time * 2), 1, 1)
if(charge_state)
charge_state = FALSE
update_icons()
update_mobility()
@@ -0,0 +1,42 @@
/**
* Lobstrosities, the poster boy of charging AI mobs. Drops crab meat and bones.
* Outside of charging, it's intended behavior is that it is generally slow moving, but makes up for that with a knockdown attack to score additional hits.
*/
/mob/living/simple_animal/hostile/asteroid/lobstrosity
name = "arctic lobstrosity"
desc = "A marvel of evolution gone wrong, the frosty ice produces underground lakes where these ill tempered seafood gather. Beware its charge."
icon = 'icons/mob/icemoon/icemoon_monsters.dmi'
icon_state = "arctic_lobstrosity"
icon_living = "arctic_lobstrosity"
icon_dead = "arctic_lobstrosity_dead"
mob_biotypes = MOB_ORGANIC|MOB_BEAST
mouse_opacity = MOUSE_OPACITY_ICON
friendly_verb_continuous = "chitters at"
friendly_verb_simple = "chits at"
speak_emote = list("chitters")
speed = 3
move_to_delay = 20
maxHealth = 150
health = 150
obj_damage = 15
melee_damage_lower = 15
melee_damage_upper = 19
attack_verb_continuous = "snips"
attack_verb_simple = "snip"
attack_sound = 'sound/weapons/bite.ogg'
weather_immunities = list("snow")
vision_range = 5
aggro_vision_range = 7
charger = TRUE
charge_distance = 4
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/crab = 2, /obj/item/stack/sheet/bone = 2)
robust_searching = TRUE
footstep_type = FOOTSTEP_MOB_CLAW
gold_core_spawnable = HOSTILE_SPAWN
/mob/living/simple_animal/hostile/asteroid/lobstrosity/lava
name = "tropical lobstrosity"
desc = "A marvel of evolution gone wrong, the sulfur lakes of lavaland have given them a vibrant, red hued shell. Beware its charge."
icon_state = "lobstrosity"
icon_living = "lobstrosity"
icon_dead = "lobstrosity_dead"