diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index 50468db0008..f89f5316450 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -38,7 +38,7 @@ tameable = FALSE attack_emote = "growls at" - smart = TRUE + smart_ranged = TRUE butchering_products = list(/obj/item/stack/material/animalhide/xeno = 5) diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index e4662d1b829..52e00441e89 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -37,7 +37,8 @@ minbodytemp = 0 speed = 4 tameable = FALSE - flying = 1 + flying = TRUE + smart_melee = FALSE see_in_dark = 8 pass_flags = PASSTABLE attack_emote = "focuses on" diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 1878f135946..e223b316e41 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -27,7 +27,8 @@ var/list/target_type_validator_map = list() var/attack_emote = "stares menacingly at" - var/smart = FALSE // This makes ranged mob check for friendly fire and obstacles + var/smart_melee = TRUE // This makes melee mobs try to stay two tiles away from their target in combat, lunging in to attack only + var/smart_ranged = FALSE // This makes ranged mob check for friendly fire and obstacles /mob/living/simple_animal/hostile/Initialize() . = ..() @@ -140,10 +141,10 @@ mob/living/simple_animal/hostile/hitby(atom/movable/AM as mob|obj,var/speed = TH walk_to(src, target_mob, 6, move_to_delay) else stance = HOSTILE_STANCE_ATTACKING - walk_to(src, target_mob, 1, move_to_delay) + var/move_distance = smart_melee ? 2 : 1 + walk_to(src, target_mob, move_distance, move_to_delay) /mob/living/simple_animal/hostile/proc/AttackTarget() - stop_automated_movement = 1 if(QDELETED(target_mob) || SA_attackable(target_mob)) LoseTarget() @@ -153,6 +154,8 @@ mob/living/simple_animal/hostile/hitby(atom/movable/AM as mob|obj,var/speed = TH return 0 if(!see_target()) LoseTarget() + if(!ranged) + step_to(src, target_mob, 1) if(get_dist(src, target_mob) <= 1) //Attacking AttackingTarget() attacked_times += 1 @@ -172,22 +175,39 @@ mob/living/simple_animal/hostile/hitby(atom/movable/AM as mob|obj,var/speed = TH visible_message(SPAN_WARNING("\The [G.assailant] restrains \the [src] from attacking!")) resist_grab() return + var/atom/target if(isliving(target_mob)) var/mob/living/L = target_mob L.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext) - return L - if(istype(target_mob, /obj/machinery/bot)) + target = L + else if(istype(target_mob, /obj/machinery/bot)) var/obj/machinery/bot/B = target_mob B.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext) - return B - if(istype(target_mob, /obj/machinery/porta_turret)) + target = B + else if(istype(target_mob, /obj/machinery/porta_turret)) var/obj/machinery/porta_turret/T = target_mob if(!T.raising && !T.raised) return + face_atom(T) src.do_attack_animation(T) T.take_damage(max(melee_damage_lower, melee_damage_upper) / 2) visible_message(SPAN_DANGER("\The [src] [attacktext] \the [T]!")) - return T + return T // no need to take a step back here + if(target) + face_atom(target) + if(!ranged && smart_melee) + addtimer(CALLBACK(src, .proc/PostAttack, target), 0.6 SECONDS) + return target + +/mob/living/simple_animal/hostile/proc/PostAttack(var/atom/target) + if(stat) + return + facing_dir = get_dir(src, target) + if(ishuman(target)) + step_away(src, pick(RANGE_TURFS(2, target))) + else + step_away(src, target, 2) + facing_dir = null /mob/living/simple_animal/hostile/proc/LoseTarget() stance = HOSTILE_STANCE_IDLE @@ -238,7 +258,7 @@ mob/living/simple_animal/hostile/hitby(atom/movable/AM as mob|obj,var/speed = TH LoseTarget() var/target = target_mob // This code checks if we are not going to hit our target - if(smart && !check_fire(target_mob)) + if(smart_ranged && !check_fire(target_mob)) return visible_message(SPAN_DANGER("[capitalize_first_letters(src.name)] fires at \the [target]!")) diff --git a/code/modules/mob/living/simple_animal/hostile/pra.dm b/code/modules/mob/living/simple_animal/hostile/pra.dm index 9f6269b58e0..d8c90dc9078 100644 --- a/code/modules/mob/living/simple_animal/hostile/pra.dm +++ b/code/modules/mob/living/simple_animal/hostile/pra.dm @@ -54,7 +54,7 @@ tameable = FALSE - smart = TRUE + smart_ranged = TRUE mob_bump_flag = ROBOT mob_swap_flags = ROBOT|MONKEY|SLIME|SIMPLE_ANIMAL diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm index 60ca9c88068..3e3ae53e3b2 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/cavern.dm @@ -7,7 +7,7 @@ icon_living = "dweller" icon_dead = "dweller_dead" ranged = 1 - smart = TRUE + smart_ranged = TRUE turns_per_move = 3 organ_names = list("head", "central segment", "tail") response_help = "pets" @@ -85,7 +85,7 @@ maxHealth = 60 harm_intent_damage = 5 ranged = 1 - smart = TRUE + smart_ranged = TRUE organ_names = list("core", "right fore wheel", "left fore wheel", "right rear wheel", "left rear wheel") melee_damage_lower = 0 melee_damage_upper = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm index bb5cd098342..a636590d297 100644 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -47,7 +47,7 @@ projectiletype = /obj/item/projectile/bullet projectilesound = 'sound/weapons/gunshot/gunshot1.ogg' casingtype = /obj/item/ammo_casing/a357 - smart = TRUE + smart_ranged = TRUE /mob/living/simple_animal/hostile/russian/death() ..() diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index 45061dc0f86..fe98c807a3e 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -109,7 +109,7 @@ /mob/living/simple_animal/hostile/syndicate/ranged ranged = 1 rapid = 1 - smart = TRUE + smart_ranged = TRUE icon_state = "syndicateranged" icon_living = "syndicateranged" casingtype = /obj/item/ammo_casing/c10mm diff --git a/code/modules/mob/living/simple_animal/hostile/viscerator.dm b/code/modules/mob/living/simple_animal/hostile/viscerator.dm index 5623d20a424..3cd9fd57397 100644 --- a/code/modules/mob/living/simple_animal/hostile/viscerator.dm +++ b/code/modules/mob/living/simple_animal/hostile/viscerator.dm @@ -25,6 +25,7 @@ minbodytemp = 0 tameable = FALSE + smart_melee = FALSE flying = TRUE attack_emote = "buzzes at" diff --git a/html/changelogs/geeves-combat_ai.yml b/html/changelogs/geeves-combat_ai.yml new file mode 100644 index 00000000000..abcb67d27fa --- /dev/null +++ b/html/changelogs/geeves-combat_ai.yml @@ -0,0 +1,6 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "Smart hostile mobs will now attempt to dodge around the player after making an attack." \ No newline at end of file