diff --git a/code/__DEFINES/basic_mobs.dm b/code/__DEFINES/basic_mobs.dm index a12b4e4c2ed..c1a713aa858 100644 --- a/code/__DEFINES/basic_mobs.dm +++ b/code/__DEFINES/basic_mobs.dm @@ -2,4 +2,6 @@ ///Basic mob flags #define DEL_ON_DEATH (1<<0) +#define FLIP_ON_DEATH (1<<1) +#define UNDENSIFY_ON_DEATH (1<<2) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 4b92fca5c50..b8f71595308 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -157,10 +157,16 @@ /atom/proc/attack_animal_secondary(mob/user, list/modifiers) return SECONDARY_ATTACK_CALL_NORMAL -///Apparently this is only used by AI datums for basic mobs. A player controlling a basic mob will call attack_animal() when clicking another atom. +///When a basic mob attacks something, either by AI or user. /atom/proc/attack_basic_mob(mob/user, list/modifiers) SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_BASIC_MOB, user) + return handle_basic_attack(user, modifiers) //return value of attack animal, this is how much damage was dealt to the attacked thing + +///This exists so stuff can override the default call of attack_animal for attack_basic_mob +///Remove this when simple animals are removed and everything can be handled on attack basic mob. +/atom/proc/handle_basic_attack(user, modifiers) + return attack_animal(user, modifiers) ///Attacked by monkey. It doesn't need its own *_secondary proc as it just uses attack_hand_secondary instead. /atom/proc/attack_paw(mob/user, list/modifiers) @@ -180,7 +186,7 @@ return target.attack_alien_secondary(src, modifiers) /atom/proc/attack_alien(mob/living/carbon/alien/user, list/modifiers) - attack_paw(user, modifiers) + return attack_paw(user, modifiers) /** * Called when an alien right clicks an atom. diff --git a/code/datums/ai/dog/dog_behaviors.dm b/code/datums/ai/dog/dog_behaviors.dm index 8c16ca5e52f..2424299510a 100644 --- a/code/datums/ai/dog/dog_behaviors.dm +++ b/code/datums/ai/dog/dog_behaviors.dm @@ -141,7 +141,7 @@ controller.blackboard[BB_DOG_PLAYING_DEAD] = TRUE simple_pawn.emote("deathgasp", intentional=FALSE) simple_pawn.icon_state = simple_pawn.icon_dead - if(simple_pawn.flip_on_death) + if(simple_pawn.basic_mob_flags & FLIP_ON_DEATH) simple_pawn.transform = simple_pawn.transform.Turn(180) simple_pawn.set_density(FALSE) @@ -156,7 +156,7 @@ controller.blackboard[BB_DOG_PLAYING_DEAD] = FALSE simple_pawn.visible_message(span_notice("[simple_pawn] springs to [simple_pawn.p_their()] feet, panting excitedly!")) simple_pawn.icon_state = simple_pawn.icon_living - if(simple_pawn.flip_on_death) + if(simple_pawn.basic_mob_flags & FLIP_ON_DEATH) simple_pawn.transform = simple_pawn.transform.Turn(180) simple_pawn.set_density(initial(simple_pawn.density)) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b5b9861eec5..fb33d5b566e 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -928,11 +928,6 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e return ..() return 0 -/obj/item/attack_basic_mob(mob/living/basic/user, list/modifiers) - if (obj_flags & CAN_BE_HIT) - return ..() - return 0 - /obj/item/burn() if(!QDELETED(src)) var/turf/T = get_turf(src) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index bacd813ba68..2cde9cee4c9 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -53,34 +53,20 @@ if(attack_generic(user, 60, BRUTE, MELEE, 0)) playsound(src.loc, 'sound/weapons/slash.ogg', 100, TRUE) -/obj/attack_basic_mob(mob/living/basic/user, list/modifiers) - . = ..() - if(!user.melee_damage_upper && !user.obj_damage) //No damage - user.emote("custom", message = "[user.friendly_verb_continuous] [src].") - return FALSE - else - if(user.obj_damage) - . = attack_generic(user, user.obj_damage, user.melee_damage_type, MELEE, TRUE, user.armour_penetration) - else - . = attack_generic(user, rand(user.melee_damage_lower,user.melee_damage_upper), user.melee_damage_type, MELEE,TRUE, user.armour_penetration) - if(.) - playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) - /obj/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() if(!user.melee_damage_upper && !user.obj_damage) user.emote("custom", message = "[user.friendly_verb_continuous] [src].") return FALSE else - var/play_soundeffect = TRUE - if(user.environment_smash) - play_soundeffect = FALSE + var/turf/current_turf = get_turf(src) //we want to save the turf to play the sound there, cause being destroyed deletes us! + var/play_soundeffect = user.environment_smash if(user.obj_damage) . = attack_generic(user, user.obj_damage, user.melee_damage_type, MELEE, play_soundeffect, user.armour_penetration) else . = attack_generic(user, rand(user.melee_damage_lower,user.melee_damage_upper), user.melee_damage_type, MELEE, play_soundeffect, user.armour_penetration) - if(. && !play_soundeffect) - playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE) + if(. && play_soundeffect) + playsound(current_turf, 'sound/effects/meteorimpact.ogg', 100, TRUE) if(user.client) log_combat(user, src, "attacked") diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 37135332bca..5a9bc4cd1cf 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -183,7 +183,7 @@ /obj/structure/window/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) //used by attack_alien, attack_animal, and attack_slime if(!can_be_reached(user)) return - ..() + return ..() /obj/structure/window/tool_act(mob/living/user, obj/item/tool, tool_type, is_right_clicking) if(!can_be_reached(user)) diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index f20e5cf3b4b..40ec3beba53 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -38,8 +38,10 @@ ///What kind of objects this mob can smash. var/environment_smash = ENVIRONMENT_SMASH_NONE - /// 1 for full damage , 0 for none , -1 for 1:1 heal from that source. + /// 1 for full damage, 0 for none, -1 for 1:1 heal from that source. var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + ///Minimum force required to deal any damage. + var/force_threshold = 0 ///Verbs used for speaking e.g. "Says" or "Chitters". This can be elementized var/list/speak_emote = list() @@ -75,10 +77,6 @@ var/icon_dead = "" ///We only try to show a gibbing animation if this exists. var/icon_gib = null - ///Flip the sprite upside down on death. Mostly here for things lacking custom dead sprites. - var/flip_on_death = FALSE - ///Removes density upon death, restores the original state if alive. - var/become_passable_on_death = TRUE ///If the mob can be spawned with a gold slime core. HOSTILE_SPAWN are spawned with plasma, FRIENDLY_SPAWN are spawned with blood. var/gold_core_spawnable = NO_SPAWN @@ -139,32 +137,35 @@ . = ..() if(basic_mob_flags & DEL_ON_DEATH) qdel(src) - else - health = 0 - icon_state = icon_dead - if(flip_on_death) - transform = transform.Turn(180) - if (become_passable_on_death) - set_density(FALSE) + return + health = 0 + icon_state = icon_dead + if(basic_mob_flags & FLIP_ON_DEATH) + transform = transform.Turn(180) + if(basic_mob_flags & UNDENSIFY_ON_DEATH) + set_density(FALSE) /mob/living/basic/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE) . = ..() if (!.) return icon_state = icon_living - if (flip_on_death) + if(basic_mob_flags & FLIP_ON_DEATH) transform = transform.Turn(180) - if (become_passable_on_death) + if(basic_mob_flags & UNDENSIFY_ON_DEATH) set_density(initial(density)) -/mob/living/basic/proc/melee_attack(atom/target) - src.face_atom(target) +/mob/living/basic/proc/melee_attack(atom/target, list/modifiers) + face_atom(target) if(SEND_SIGNAL(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, target) & COMPONENT_HOSTILE_NO_ATTACK) return FALSE //but more importantly return before attack_animal called - var/result = target.attack_basic_mob(src) + var/result = target.attack_basic_mob(src, modifiers) SEND_SIGNAL(src, COMSIG_HOSTILE_POST_ATTACKINGTARGET, target, result) return result +/mob/living/basic/resolve_unarmed_attack(atom/attack_target, list/modifiers) + melee_attack(attack_target, modifiers) + /mob/living/basic/vv_edit_var(vname, vval) . = ..() if(vname == NAMEOF(src, speed)) diff --git a/code/modules/mob/living/basic/basic_defense.dm b/code/modules/mob/living/basic/basic_defense.dm index 149fc1c6bec..d22ae01c2d4 100644 --- a/code/modules/mob/living/basic/basic_defense.dm +++ b/code/modules/mob/living/basic/basic_defense.dm @@ -70,36 +70,31 @@ /mob/living/basic/attack_alien(mob/living/carbon/alien/adult/user, list/modifiers) - if(..()) //if harm or disarm intent. - 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") - else - var/damage = rand(15, 30) - 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") - return 1 + . = ..() + 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/L, list/modifiers) +/mob/living/basic/attack_larva(mob/living/carbon/alien/larva/attacking_larva, list/modifiers) . = ..() if(. && stat != DEAD) //successful larva bite - var/damage = rand(5, 10) + var/damage = rand(attacking_larva.melee_damage_lower, attacking_larva.melee_damage_upper) . = attack_threshold_check(damage) if(.) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - -/mob/living/basic/attack_basic_mob(mob/living/basic/user, list/modifiers) - . = ..() - if(.) - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - return attack_threshold_check(damage, user.melee_damage_type) + 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) . = ..() @@ -114,13 +109,13 @@ damage = rand(20, 35) return attack_threshold_check(damage) -/mob/living/basic/attack_drone(mob/living/simple_animal/drone/M) - if(M.combat_mode) //No kicking dogs even as a rogue drone. Use a weapon. +/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/M) - if(M.combat_mode) +/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 ..() @@ -130,23 +125,23 @@ temp_damage = 0 else temp_damage *= damage_coeff[damagetype] - - if(actuallydamage) - apply_damage(damage, damagetype, null, getarmor(null, armorcheck)) - return TRUE + 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(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) - return FALSE - . = ..() - if(QDELETED(src)) + if(!. || QDELETED(src)) return var/bomb_armor = getarmor(null, BOMB) - switch (severity) + switch(severity) if (EXPLODE_DEVASTATE) if(prob(bomb_armor)) apply_damage(500, damagetype = BRUTE) @@ -166,13 +161,12 @@ bloss = bloss / 1.5 apply_damage(bloss, damagetype = BRUTE) -/mob/living/basic/blob_act(obj/structure/blob/B) +/mob/living/basic/blob_act(obj/structure/blob/attacking_blob) apply_damage(20, damagetype = BRUTE) - return -/mob/living/basic/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect) +/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(A)) // override the standard visual effect. + 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 @@ -180,7 +174,6 @@ visual_effect_icon = ATTACK_EFFECT_SMASH ..() - /mob/living/basic/update_stat() if(status_flags & GODMODE) return @@ -194,11 +187,14 @@ /mob/living/basic/emp_act(severity) . = ..() if(mob_biotypes & MOB_ROBOTIC) - switch (severity) - if (EMP_LIGHT) - visible_message(span_danger("[src] shakes violently, its parts coming loose!")) - apply_damage(maxHealth * 0.6) - Shake(5, 5, 1 SECONDS) - if (EMP_HEAVY) - visible_message(span_danger("[src] suddenly bursts apart!")) - apply_damage(maxHealth) + 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(5, 5, 1 SECONDS) + if(EMP_HEAVY) + visible_message(span_danger("[src] suddenly bursts apart!")) + apply_damage(maxHealth) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 6b6a760a983..b3440c97448 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -332,23 +332,6 @@ var/armor_block = run_armor_check(affecting, MELEE) apply_damage(damage, BRUTE, affecting, armor_block) - -/mob/living/carbon/human/attack_basic_mob(mob/living/basic/user, list/modifiers) - . = ..() - if(!.) - return - var/damage = rand(user.melee_damage_lower, user.melee_damage_upper) - if(check_shields(user, damage, "the [user.name]", MELEE_ATTACK, user.armour_penetration)) - return FALSE - var/dam_zone = dismembering_strike(user, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) - if(!dam_zone) //Dismemberment successful - return TRUE - var/obj/item/bodypart/affecting = get_bodypart(get_random_valid_zone(dam_zone)) - var/armor = run_armor_check(affecting, MELEE, armour_penetration = user.armour_penetration) - var/attack_direction = get_dir(user, src) - apply_damage(damage, user.melee_damage_type, affecting, armor, wound_bonus = user.wound_bonus, bare_wound_bonus = user.bare_wound_bonus, sharpness = user.sharpness, attack_direction = attack_direction) - - /mob/living/carbon/human/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() if(!.) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index b0be9bda7b2..ec61f5c64c5 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -242,27 +242,6 @@ to_chat(M, span_danger("You glomp [src]!")) return TRUE -/mob/living/attack_basic_mob(mob/living/basic/user, list/modifiers) - . = ..() - if(user.melee_damage_upper == 0) - if(user != src) - visible_message(span_notice("\The [user] [user.friendly_verb_continuous] [src]!"), \ - span_notice("\The [user] [user.friendly_verb_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_notice("You [user.friendly_verb_simple] [src]!")) - return FALSE - if(HAS_TRAIT(user, TRAIT_PACIFISM)) - to_chat(user, span_warning("You don't want to hurt anyone!")) - return FALSE - - if(user.attack_sound) - playsound(loc, user.attack_sound, 50, TRUE, TRUE) - user.do_attack_animation(src) - visible_message(span_danger("\The [user] [user.attack_verb_continuous] [src]!"), \ - span_userdanger("\The [user] [user.attack_verb_continuous] you!"), null, COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You [user.attack_verb_simple] [src]!")) - log_combat(user, src, "attacked") - return TRUE - /mob/living/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() user.face_atom(src) diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index 16b6d02bc89..c51b2c644b9 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -92,12 +92,6 @@ if(.) L.amount_grown = min(L.amount_grown + damage, L.max_grown) -/mob/living/simple_animal/attack_basic_mob(mob/living/basic/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/simple_animal/attack_animal(mob/living/simple_animal/user, list/modifiers) . = ..() if(.) diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm index a3cdeb6ab9b..7667f2fc95a 100644 --- a/code/modules/vehicles/mecha/combat/durand.dm +++ b/code/modules/vehicles/mecha/combat/durand.dm @@ -113,9 +113,8 @@ Expects a turf. Returns true if the attack should be blocked, false if not.*/ /obj/vehicle/sealed/mecha/durand/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0) if(defense_check(user.loc)) log_message("Attack absorbed by defense field. Attacker - [user].", LOG_MECHA, color="orange") - shield.attack_generic(user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration) - else - . = ..() + return shield.attack_generic(user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration) + return ..() /obj/vehicle/sealed/mecha/durand/blob_act(obj/structure/blob/B) if(defense_check(B.loc))