Files
Bubberstation/code/modules/mob/living/basic/basic_defense.dm
SkyratBot 35e28a5b4a [MIRROR] Goliath basic mob [MDB IGNORE] (#22412)
* Goliath basic mob (#76754)

## About The Pull Request

Converts Goliaths to the basic mob framework and gives them some new
moves because I can't leave things well enough alone.
I am planning on touching all the lavaland fauna and then maybe even the
icebox ones if I haven't got bored. The Golaith is the first because it
is iconic.

https://www.youtube.com/watch?v=JNcKvMwT4-Q
Here's me getting killed by one as a demonstration. Despite my poor
performance I would contend that they aren't a _lot_ more dangerous, but
they are a little more dangerous.

The chief difference here is that they have two new attacks which they
will only use in response to being attacked.
If fired at from range, they will target the attacker with a line of
tentacles (it doesn't track you, so is easily sidestepped).
If attacked in melee, they will surround _themselves_ with tentacles, on
a longer cooldown.

Something else you may notice in this video: I discovered that basic
mobs are actually _too smart_ to be Lavaland fauna.
Typically (unlike their old form) a mob on our new AI system is smart
enough to attack someone _the moment they come into range_ rather than
only checking on predictable ticks, which would make using the Crusher
an essentially unviable prospect.
To counteract this, Goliaths now have a delayed attack component which
gives you a visual warning and short duration to get out of range before
they swing at you. I will probably put this on all mining fauna that get
reworked, it wouldn't be a terrible thing to put on other mobs to be
honest.

Other changes: The goliath stun is now a status effect with _buckles_
you to the tentacle as if grabbed, as well as its previous effects.
While this seems purely worse, any nearby helpers can now help-click on
you to instantly remove the debuff.
Experiencing the effect of a Lobstrosity Rush Gland makes you immune to
being grabbed by tentacles and an implanted one will automatically
trigger and free you if you are hit, and the explosive effect of
Brimdust also causes the tentacle to retract (although you'd need to
take damage for this to happen). Using the tools of the land, you can
make these creatures less threatening.

The ability for a Goliath to chain-apply the ability has now also been
reduced, it won't refresh its duration if you are hit when already
buckled.

When not occupied hounding miners, Goliaths will intermittently dig up
the asteroid sand and eat any worms that this produces.
I also made some new sprites for riding a Goliath because they've been
broken since the Lavaland mob update and also kind of were ugly before
then anyway:

![image](https://github.com/tgstation/tgstation/assets/7483112/90580403-d82f-4c29-b3e1-6c462e01edda)

Other code changes:
- I made an element which only lets an attached object move every x
seconds. This is because Goliaths are far too slow to use the speed
system (the glide just looks bugged as hell) but one thing I am invested
in when converting these is to make sure that they share the same
behaviour when player or AI controlled. This is disabled while you're
riding them because it was interminably slow.
- The Goliath tentacle trail uses a supertype object now shared with the
Meteor Heart which did something kind of similar.

## Why It's Good For The Game

It begins the process of moving one of our larger subsets of NPCs onto
the newer framework for NPC behaviour.
It adds a little bit more life to an iconic but slightly uninteresting
foe which mostly just walked at you slowly.
This PR contains a few components I expect to apply more widely to other
mobs in the future.

## Changelog

🆑
refactor: Goliaths now use the Basic Mob framework, please report any
unusual behaviour.
add: Goliaths learned a couple of new attacks which they will use in
self-defence.
balance: Help-clicking a miner grabbed by Goliath tentacles will
immediately free them, as will the effect of several items you can
scavenge from around Lavaland.
image: New sprites for the Goliath saddle.
/🆑

* Goliath basic mob

* Update ash_rituals.dm

* fixes icon diff

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>
Co-authored-by: Pinta <68373373+softcerv@users.noreply.github.com>
Co-authored-by: Giz <vinylspiders@gmail.com>
2023-07-14 03:10:50 +00:00

204 lines
7.4 KiB
Plaintext

/mob/living/basic/attack_hand(mob/living/carbon/human/user, list/modifiers)
// so that martial arts don't double dip
if (..())
return TRUE
if(LAZYACCESS(modifiers, RIGHT_CLICK))
if(user.move_force < move_resist)
return
user.do_attack_animation(src, ATTACK_EFFECT_DISARM)
playsound(src, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
var/shove_dir = get_dir(user, src)
if(!Move(get_step(src, shove_dir), shove_dir))
log_combat(user, src, "shoved", "failing to move it")
user.visible_message(span_danger("[user.name] shoves [src]!"),
span_danger("You shove [src]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src))
to_chat(src, span_userdanger("You're shoved by [user.name]!"))
return TRUE
log_combat(user, src, "shoved", "pushing it")
user.visible_message(span_danger("[user.name] shoves [src], pushing [p_them()]!"),
span_danger("You shove [src], pushing [p_them()]!"), span_hear("You hear aggressive shuffling!"), COMBAT_MESSAGE_RANGE, list(src))
to_chat(src, span_userdanger("You're pushed by [user.name]!"))
return TRUE
if(!user.combat_mode)
if (stat == DEAD)
return
visible_message(span_notice("[user] [response_help_continuous] [src]."), \
span_notice("[user] [response_help_continuous] you."), null, null, user)
to_chat(user, span_notice("You [response_help_simple] [src]."))
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
else
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, span_warning("You don't want to hurt [src]!"))
return
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
visible_message(span_danger("[user] [response_harm_continuous] [src]!"),\
span_userdanger("[user] [response_harm_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user)
to_chat(user, span_danger("You [response_harm_simple] [src]!"))
playsound(loc, attacked_sound, 25, TRUE, -1)
var/obj/item/bodypart/arm/active_arm = user.get_active_hand()
var/damage = (basic_mob_flags & IMMUNE_TO_FISTS) ? 0 : rand(active_arm.unarmed_damage_low, active_arm.unarmed_damage_high)
attack_threshold_check(damage)
log_combat(user, src, "attacked")
updatehealth()
return TRUE
/mob/living/basic/attack_hulk(mob/living/carbon/human/user)
. = ..()
if(!.)
return
playsound(loc, SFX_PUNCH, 25, TRUE, -1)
visible_message(span_danger("[user] punches [src]!"), \
span_userdanger("You're punched by [user]!"), null, COMBAT_MESSAGE_RANGE, user)
to_chat(user, span_danger("You punch [src]!"))
apply_damage(15, damagetype = BRUTE)
/mob/living/basic/attack_paw(mob/living/carbon/human/user, list/modifiers)
if(..()) //successful monkey bite.
if(stat != DEAD)
var/damage = rand(1, 3)
attack_threshold_check(damage)
return 1
if (!user.combat_mode)
if (health > 0)
visible_message(span_notice("[user.name] [response_help_continuous] [src]."), \
span_notice("[user.name] [response_help_continuous] you."), null, COMBAT_MESSAGE_RANGE, user)
to_chat(user, span_notice("You [response_help_simple] [src]."))
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
/mob/living/basic/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers)
. = ..()
if(!.)
return
if(LAZYACCESS(modifiers, RIGHT_CLICK))
playsound(loc, 'sound/weapons/pierce.ogg', 25, TRUE, -1)
visible_message(span_danger("[user] [response_disarm_continuous] [name]!"), \
span_userdanger("[user] [response_disarm_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user)
to_chat(user, span_danger("You [response_disarm_simple] [name]!"))
log_combat(user, src, "disarmed")
return
var/damage = rand(user.melee_damage_lower, user.melee_damage_upper)
visible_message(span_danger("[user] slashes at [src]!"), \
span_userdanger("You're slashed at by [user]!"), null, COMBAT_MESSAGE_RANGE, user)
to_chat(user, span_danger("You slash at [src]!"))
playsound(loc, 'sound/weapons/slice.ogg', 25, TRUE, -1)
attack_threshold_check(damage)
log_combat(user, src, "attacked")
/mob/living/basic/attack_larva(mob/living/carbon/alien/larva/attacking_larva, list/modifiers)
. = ..()
if(. && stat != DEAD) //successful larva bite
var/damage = rand(attacking_larva.melee_damage_lower, attacking_larva.melee_damage_upper)
. = attack_threshold_check(damage)
if(.)
attacking_larva.amount_grown = min(attacking_larva.amount_grown + damage, attacking_larva.max_grown)
/mob/living/basic/attack_animal(mob/living/simple_animal/user, list/modifiers)
. = ..()
if(.)
var/damage = rand(user.melee_damage_lower, user.melee_damage_upper)
return attack_threshold_check(damage, user.melee_damage_type)
/mob/living/basic/attack_slime(mob/living/simple_animal/slime/M, list/modifiers)
if(..()) //successful slime attack
var/damage = rand(15, 25)
if(M.is_adult)
damage = rand(20, 35)
return attack_threshold_check(damage)
/mob/living/basic/attack_drone(mob/living/simple_animal/drone/attacking_drone)
if(attacking_drone.combat_mode) //No kicking dogs even as a rogue drone. Use a weapon.
return
return ..()
/mob/living/basic/attack_drone_secondary(mob/living/simple_animal/drone/attacking_drone)
if(attacking_drone.combat_mode)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ..()
/mob/living/basic/proc/attack_threshold_check(damage, damagetype = BRUTE, armorcheck = MELEE, actuallydamage = TRUE)
var/temp_damage = damage
if(!damage_coeff[damagetype])
temp_damage = 0
else
temp_damage *= damage_coeff[damagetype]
if(temp_damage >= 0 && temp_damage <= force_threshold)
visible_message(span_warning("[src] looks unharmed!"))
return FALSE
else
if(actuallydamage)
apply_damage(damage, damagetype, blocked = getarmor(null, armorcheck))
return TRUE
/mob/living/basic/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent)
return 0
/mob/living/basic/ex_act(severity, target, origin)
. = ..()
if(!. || QDELETED(src))
return FALSE
var/bomb_armor = getarmor(null, BOMB)
switch(severity)
if (EXPLODE_DEVASTATE)
if(prob(bomb_armor))
apply_damage(500, damagetype = BRUTE)
else
investigate_log("has been gibbed by an explosion.", INVESTIGATE_DEATHS)
gib()
if (EXPLODE_HEAVY)
var/bloss = 60
if(prob(bomb_armor))
bloss = bloss / 1.5
apply_damage(bloss, damagetype = BRUTE)
if (EXPLODE_LIGHT)
var/bloss = 30
if(prob(bomb_armor))
bloss = bloss / 1.5
apply_damage(bloss, damagetype = BRUTE)
return TRUE
/mob/living/basic/blob_act(obj/structure/blob/attacking_blob)
apply_damage(20, damagetype = BRUTE)
/mob/living/basic/do_attack_animation(atom/attacked_atom, visual_effect_icon, used_item, no_effect)
if(!no_effect && !visual_effect_icon && melee_damage_upper)
if(attack_vis_effect && !iswallturf(attacked_atom)) // override the standard visual effect.
visual_effect_icon = attack_vis_effect
else if(melee_damage_upper < 10)
visual_effect_icon = ATTACK_EFFECT_PUNCH
else
visual_effect_icon = ATTACK_EFFECT_SMASH
..()
/mob/living/basic/update_stat()
if(status_flags & GODMODE)
return
if(stat != DEAD)
if(health <= 0)
death()
else
set_stat(CONSCIOUS)
med_hud_set_status()
/mob/living/basic/emp_act(severity)
. = ..()
if(mob_biotypes & MOB_ROBOTIC)
emp_reaction(severity)
/mob/living/basic/proc/emp_reaction(severity)
switch(severity)
if(EMP_LIGHT)
visible_message(span_danger("[src] shakes violently, its parts coming loose!"))
apply_damage(maxHealth * 0.6)
Shake(duration = 1 SECONDS)
if(EMP_HEAVY)
visible_message(span_danger("[src] suddenly bursts apart!"))
apply_damage(maxHealth)