From eb5c82c1484b8e0ad4d43b7037cdd2722cc079b7 Mon Sep 17 00:00:00 2001
From: SabreML <57483089+SabreML@users.noreply.github.com>
Date: Sat, 6 Apr 2024 12:04:14 +0100
Subject: [PATCH] Attack logs for xeno tackling (#6061)
# About the pull request
Makes Xenomorphs tackling/disarming people show in attack logs.
Additionally, this also changes `mob/living/carbon/xenomorph/M` to
`mob/living/carbon/xenomorph/attacking_xeno` in the proc's parameters,
and merges two behavior_delegate checks that were right next to each
other.
It's being logged with `log_attack()` rather than the
`msg_admin_attack()` used by human disarming since a xeno tackling
someone is a normal part of the game loop, and not something that could
potentially need admin attention.
# Explain why it's good for the game
"Normal part of the game" or not, this is the sort of thing which should
be in attack logs.
# Testing Photographs and Procedure
Screenshots & Videos
**Xenomorph combat logs:**
![dreamseeker_egsPasjsdj](https://github.com/cmss13-devs/cmss13/assets/57483089/05482a63-045c-437c-a676-82a07d151d26)
**Human combat logs:**
![dreamseeker_UZFD8dNiYt](https://github.com/cmss13-devs/cmss13/assets/57483089/552397e5-c303-4753-aa4b-64845794fb1a)
`attack.log`:
```
[2024-03-31 21:48:27.610] ATTACK: sabreml/(Young Drone (XX-653)) unsuccessfully tackled @SabreML/(Sean Agg) in Open grounds (event P) (45,82,2).
[2024-03-31 21:48:28.684] ATTACK: sabreml/(Young Drone (XX-653)) unsuccessfully tackled @SabreML/(Sean Agg) in Open grounds (event P) (45,82,2).
[2024-03-31 21:48:29.700] ATTACK: sabreml/(Young Drone (XX-653)) successfully tackled @SabreML/(Sean Agg) in Open grounds (event P) (45,82,2).
```
# Changelog
:cl:
admin: Added attack logging for Xeno tackling.
/:cl:
---
.../living/carbon/xenomorph/attack_alien.dm | 155 +++++++++---------
1 file changed, 79 insertions(+), 76 deletions(-)
diff --git a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm
index c37a823fd0c5..7479fb356e43 100644
--- a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm
+++ b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm
@@ -7,92 +7,92 @@
* In that case, the first argument is always the attacker. For attack_alien, it should always be Xenomorph sub-types
*/
-
-/mob/living/carbon/human/attack_alien(mob/living/carbon/xenomorph/M, dam_bonus)
- if(M.fortify || HAS_TRAIT(M, TRAIT_ABILITY_BURROWED))
+// this proc could use refactoring at some point
+/mob/living/carbon/human/attack_alien(mob/living/carbon/xenomorph/attacking_xeno, dam_bonus)
+ if(attacking_xeno.fortify || HAS_TRAIT(attacking_xeno, TRAIT_ABILITY_BURROWED))
return XENO_NO_DELAY_ACTION
- var/intent = M.a_intent
+ var/intent = attacking_xeno.a_intent
- if(M.behavior_delegate)
- intent = M.behavior_delegate.override_intent(src)
+ if(attacking_xeno.behavior_delegate)
+ intent = attacking_xeno.behavior_delegate.override_intent(src)
//Reviewing the four primary intents
switch(intent)
if(INTENT_HELP)
if(on_fire)
- extinguish_mob(M)
+ extinguish_mob(attacking_xeno)
else
- M.visible_message(SPAN_NOTICE("[M] caresses [src] with its claws."), \
+ attacking_xeno.visible_message(SPAN_NOTICE("[attacking_xeno] caresses [src] with its claws."), \
SPAN_NOTICE("We caress [src] with our claws."), null, 5, CHAT_TYPE_XENO_FLUFF)
if(INTENT_GRAB)
- if(M == src || anchored || buckled)
+ if(attacking_xeno == src || anchored || buckled)
return XENO_NO_DELAY_ACTION
- if(check_shields(0, M.name)) // Blocking check
- M.visible_message(SPAN_DANGER("[M]'s grab is blocked by [src]'s shield!"), \
+ if(check_shields(0, attacking_xeno.name)) // Blocking check
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno]'s grab is blocked by [src]'s shield!"), \
SPAN_DANGER("Our grab was blocked by [src]'s shield!"), null, 5, CHAT_TYPE_XENO_COMBAT)
playsound(loc, 'sound/weapons/alien_claw_block.ogg', 25, 1) //Feedback
return XENO_ATTACK_ACTION
- if(Adjacent(M)) //Logic!
- M.start_pulling(src)
+ if(Adjacent(attacking_xeno)) //Logic!
+ attacking_xeno.start_pulling(src)
if(INTENT_HARM)
- if(M.can_not_harm(src))
- M.animation_attack_on(src)
- M.visible_message(SPAN_NOTICE("[M] nibbles [src]"), \
+ if(attacking_xeno.can_not_harm(src))
+ attacking_xeno.animation_attack_on(src)
+ attacking_xeno.visible_message(SPAN_NOTICE("[attacking_xeno] nibbles [src]"), \
SPAN_XENONOTICE("We nibble [src]"))
return XENO_ATTACK_ACTION
- if(M.behavior_delegate && M.behavior_delegate.handle_slash(src))
+ if(attacking_xeno.behavior_delegate && attacking_xeno.behavior_delegate.handle_slash(src))
return XENO_NO_DELAY_ACTION
if(stat == DEAD)
- to_chat(M, SPAN_WARNING("[src] is dead, why would we want to touch it?"))
+ to_chat(attacking_xeno, SPAN_WARNING("[src] is dead, why would we want to touch it?"))
return XENO_NO_DELAY_ACTION
- if(M.caste && !M.caste.is_intelligent)
+ if(attacking_xeno.caste && !attacking_xeno.caste.is_intelligent)
if(HAS_TRAIT(src, TRAIT_NESTED) && (status_flags & XENO_HOST))
for(var/obj/item/alien_embryo/embryo in src)
- if(HIVE_ALLIED_TO_HIVE(M.hivenumber, embryo.hivenumber))
- to_chat(M, SPAN_WARNING("We should not harm this host! It has a sister inside."))
+ if(HIVE_ALLIED_TO_HIVE(attacking_xeno.hivenumber, embryo.hivenumber))
+ to_chat(attacking_xeno, SPAN_WARNING("We should not harm this host! It has a sister inside."))
return XENO_NO_DELAY_ACTION
- if(check_shields(0, M.name)) // Blocking check
- M.visible_message(SPAN_DANGER("[M]'s slash is blocked by [src]'s shield!"), \
+ if(check_shields(0, attacking_xeno.name)) // Blocking check
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno]'s slash is blocked by [src]'s shield!"), \
SPAN_DANGER("Our slash is blocked by [src]'s shield!"), null, 5, CHAT_TYPE_XENO_COMBAT)
playsound(loc, 'sound/weapons/alien_claw_block.ogg', 25, 1) //Feedback
return XENO_ATTACK_ACTION
//From this point, we are certain a full attack will go out. Calculate damage and modifiers
- M.track_slashes(M.caste_type) //Adds to slash stat.
- var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + dam_bonus
+ attacking_xeno.track_slashes(attacking_xeno.caste_type) //Adds to slash stat.
+ var/damage = rand(attacking_xeno.melee_damage_lower, attacking_xeno.melee_damage_upper) + dam_bonus
var/acid_damage = 0
- if(M.burn_damage_lower)
- acid_damage = rand(M.burn_damage_lower, M.burn_damage_upper)
+ if(attacking_xeno.burn_damage_lower)
+ acid_damage = rand(attacking_xeno.burn_damage_lower, attacking_xeno.burn_damage_upper)
//Frenzy auras stack in a way, then the raw value is multipled by two to get the additive modifier
- if(M.frenzy_aura > 0)
- damage += (M.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER)
+ if(attacking_xeno.frenzy_aura > 0)
+ damage += (attacking_xeno.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER)
if(acid_damage)
- acid_damage += (M.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER)
+ acid_damage += (attacking_xeno.frenzy_aura * FRENZY_DAMAGE_MULTIPLIER)
- M.animation_attack_on(src)
+ attacking_xeno.animation_attack_on(src)
//Somehow we will deal no damage on this attack
if(!damage)
- playsound(M.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1)
- M.animation_attack_on(src)
- M.visible_message(SPAN_DANGER("[M] lunges at [src]!"), \
+ playsound(attacking_xeno.loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1)
+ attacking_xeno.animation_attack_on(src)
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] lunges at [src]!"), \
SPAN_DANGER("We lunge at [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT)
return XENO_ATTACK_ACTION
- M.flick_attack_overlay(src, "slash")
+ attacking_xeno.flick_attack_overlay(src, "slash")
var/obj/limb/affecting
- affecting = get_limb(rand_zone(M.zone_selected, 70))
+ affecting = get_limb(rand_zone(attacking_xeno.zone_selected, 70))
if(!affecting) //No organ, just get a random one
affecting = get_limb(rand_zone(null, 0))
if(!affecting) //Still nothing??
@@ -100,17 +100,17 @@
var/armor_block = getarmor(affecting, ARMOR_MELEE)
- if(wear_mask && check_zone(M.zone_selected) == "head")
+ if(wear_mask && check_zone(attacking_xeno.zone_selected) == "head")
if(istype(wear_mask, /obj/item/clothing/mask/gas/yautja))
var/knock_chance = 1
- if(M.frenzy_aura > 0)
- knock_chance += 2 * M.frenzy_aura
- if(M.caste && M.caste.is_intelligent)
+ if(attacking_xeno.frenzy_aura > 0)
+ knock_chance += 2 * attacking_xeno.frenzy_aura
+ if(attacking_xeno.caste && attacking_xeno.caste.is_intelligent)
knock_chance += 2
knock_chance += min(round(damage * 0.25), 10) //Maximum of 15% chance.
if(prob(knock_chance))
playsound(loc, "alien_claw_metal", 25, 1)
- M.visible_message(SPAN_DANGER("[M] smashes off [src]'s [wear_mask.name]!"), \
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] smashes off [src]'s [wear_mask.name]!"), \
SPAN_DANGER("We smash off [src]'s [wear_mask.name]!"), null, 5)
drop_inv_item_on_ground(wear_mask)
if(isyautja(src))
@@ -121,42 +121,39 @@
var/n_damage = armor_damage_reduction(GLOB.marine_melee, damage, armor_block)
- if(M.behavior_delegate)
- n_damage = M.behavior_delegate.melee_attack_modify_damage(n_damage, src)
+ if(attacking_xeno.behavior_delegate)
+ n_damage = attacking_xeno.behavior_delegate.melee_attack_modify_damage(n_damage, src)
+ attacking_xeno.behavior_delegate.melee_attack_additional_effects_target(src)
+ attacking_xeno.behavior_delegate.melee_attack_additional_effects_self()
- if(M.behavior_delegate)
- var/datum/behavior_delegate/MD = M.behavior_delegate
- MD.melee_attack_additional_effects_target(src)
- MD.melee_attack_additional_effects_self()
-
- var/slash_noise = M.slash_sound
+ var/slash_noise = attacking_xeno.slash_sound
var/list/slashdata = list("n_damage" = n_damage, "slash_noise" = slash_noise)
- SEND_SIGNAL(src, COMSIG_HUMAN_XENO_ATTACK, slashdata, M)
+ SEND_SIGNAL(src, COMSIG_HUMAN_XENO_ATTACK, slashdata, attacking_xeno)
var/f_damage = slashdata["n_damage"]
slash_noise = slashdata["slash_noise"]
//The normal attack proceeds
playsound(loc, slash_noise, 25, TRUE)
- M.visible_message(SPAN_DANGER("[M] [M.slashes_verb] [src]!"), \
- SPAN_DANGER("We [M.slash_verb] [src]!"), null, null, CHAT_TYPE_XENO_COMBAT)
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] [attacking_xeno.slashes_verb] [src]!"), \
+ SPAN_DANGER("We [attacking_xeno.slash_verb] [src]!"), null, null, CHAT_TYPE_XENO_COMBAT)
- handle_blood_splatter(get_dir(M.loc, src.loc))
+ handle_blood_splatter(get_dir(attacking_xeno.loc, src.loc))
- last_damage_data = create_cause_data(initial(M.name), M)
+ last_damage_data = create_cause_data(initial(attacking_xeno.name), attacking_xeno)
//Logging, including anti-rulebreak logging
if(status_flags & XENO_HOST && stat != DEAD)
if(HAS_TRAIT(src, TRAIT_NESTED)) //Host was buckled to nest while infected, this is a rule break
- attack_log += text("\[[time_stamp()]\] was [M.slash_verb]ed by [key_name(M)] while they were infected and nested")
- M.attack_log += text("\[[time_stamp()]\] [M.slash_verb]ed [key_name(src)] while they were infected and nested")
- message_admins("[key_name(M)] [M.slash_verb]ed [key_name(src)] while they were infected and nested.") //This is a blatant rulebreak, so warn the admins
+ attack_log += text("\[[time_stamp()]\] was [attacking_xeno.slash_verb]ed by [key_name(attacking_xeno)] while they were infected and nested")
+ attacking_xeno.attack_log += text("\[[time_stamp()]\] [attacking_xeno.slash_verb]ed [key_name(src)] while they were infected and nested")
+ message_admins("[key_name(attacking_xeno)] [attacking_xeno.slash_verb]ed [key_name(src)] while they were infected and nested.") //This is a blatant rulebreak, so warn the admins
else //Host might be rogue, needs further investigation
- attack_log += text("\[[time_stamp()]\] was [M.slash_verb]ed by [key_name(M)] while they were infected")
- M.attack_log += text("\[[time_stamp()]\] [M.slash_verb]ed [key_name(src)] while they were infected")
+ attack_log += text("\[[time_stamp()]\] was [attacking_xeno.slash_verb]ed by [key_name(attacking_xeno)] while they were infected")
+ attacking_xeno.attack_log += text("\[[time_stamp()]\] [attacking_xeno.slash_verb]ed [key_name(src)] while they were infected")
else //Normal xenomorph friendship with benefits
- attack_log += text("\[[time_stamp()]\] was [M.slash_verb]ed by [key_name(M)]")
- M.attack_log += text("\[[time_stamp()]\] [M.slash_verb]ed [key_name(src)]")
- log_attack("[key_name(M)] [M.slash_verb]ed [key_name(src)]")
+ attack_log += text("\[[time_stamp()]\] was [attacking_xeno.slash_verb]ed by [key_name(attacking_xeno)]")
+ attacking_xeno.attack_log += text("\[[time_stamp()]\] [attacking_xeno.slash_verb]ed [key_name(src)]")
+ log_attack("[key_name(attacking_xeno)] [attacking_xeno.slash_verb]ed [key_name(src)]")
//nice messages so people know that armor works
if(f_damage <= 0.34*damage)
@@ -176,23 +173,22 @@
to_chat(src, SPAN_WARNING("Your armor softens the acid!"))
apply_damage(n_acid_damage, BURN, affecting) //Burn damage
- SEND_SIGNAL(M, COMSIG_HUMAN_ALIEN_ATTACK, src)
+ SEND_SIGNAL(attacking_xeno, COMSIG_HUMAN_ALIEN_ATTACK, src)
updatehealth()
if(INTENT_DISARM)
-
- if(M.legcuffed && isyautja(src))
- to_chat(M, SPAN_XENODANGER("We don't have the dexterity to tackle the headhunter with that thing on our leg!"))
+ if(attacking_xeno.legcuffed && isyautja(src))
+ to_chat(attacking_xeno, SPAN_XENODANGER("We don't have the dexterity to tackle the headhunter with that thing on our leg!"))
return XENO_NO_DELAY_ACTION
- M.animation_attack_on(src)
- if(check_shields(0, M.name)) // Blocking check
- M.visible_message(SPAN_DANGER("[M]'s tackle is blocked by [src]'s shield!"), \
+ attacking_xeno.animation_attack_on(src)
+ if(check_shields(0, attacking_xeno.name)) // Blocking check
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno]'s tackle is blocked by [src]'s shield!"), \
SPAN_DANGER("We tackle is blocked by [src]'s shield!"), null, 5, CHAT_TYPE_XENO_COMBAT)
playsound(loc, 'sound/weapons/alien_claw_block.ogg', 25, 1) //Feedback
return XENO_ATTACK_ACTION
- M.flick_attack_overlay(src, "disarm")
+ attacking_xeno.flick_attack_overlay(src, "disarm")
var/tackle_mult = 1
var/tackle_min_offset = 0
@@ -202,22 +198,29 @@
tackle_min_offset += 2
tackle_max_offset += 2
- if(M.attempt_tackle(src, tackle_mult, tackle_min_offset, tackle_max_offset))
+ var/knocked_down
+ if(attacking_xeno.attempt_tackle(src, tackle_mult, tackle_min_offset, tackle_max_offset))
playsound(loc, 'sound/weapons/alien_knockdown.ogg', 25, 1)
- var/strength = rand(M.tacklestrength_min, M.tacklestrength_max)
+ var/strength = rand(attacking_xeno.tacklestrength_min, attacking_xeno.tacklestrength_max)
Stun(strength)
KnockDown(strength) // Purely for knockdown visuals. All the heavy lifting is done by Stun
- M.visible_message(SPAN_DANGER("[M] tackles down [src]!"), \
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] tackles down [src]!"), \
SPAN_DANGER("We tackle down [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT)
- SEND_SIGNAL(src, COMSIG_MOB_TACKLED_DOWN, M)
+ SEND_SIGNAL(src, COMSIG_MOB_TACKLED_DOWN, attacking_xeno)
+ knocked_down = TRUE
else
playsound(loc, 'sound/weapons/alien_claw_swipe.ogg', 25, 1)
if (body_position == LYING_DOWN)
- M.visible_message(SPAN_DANGER("[M] tries to tackle [src], but they are already down!"), \
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] tries to tackle [src], but they are already down!"), \
SPAN_DANGER("We try to tackle [src], but they are already down!"), null, 5, CHAT_TYPE_XENO_COMBAT)
else
- M.visible_message(SPAN_DANGER("[M] tries to tackle [src]"), \
+ attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] tries to tackle [src]"), \
SPAN_DANGER("We try to tackle [src]"), null, 5, CHAT_TYPE_XENO_COMBAT)
+ knocked_down = FALSE
+
+ attacking_xeno.attack_log += "\[[time_stamp()]\] [knocked_down ? "S" : "Uns"]uccessfully tackled [key_name(src)]"
+ attack_log += "\[[time_stamp()]\] Has been [knocked_down ? "" : "un"]successfully tackled by [key_name(attacking_xeno)]"
+ log_attack("[key_name(attacking_xeno)] [knocked_down ? "" : "un"]successfully tackled [key_name(src)] in [get_area(src)] ([loc.x],[loc.y],[loc.z]).")
return XENO_ATTACK_ACTION