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