mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-07-19 20:22:38 +01:00
Readd some AI features
Like calling for help and investigating the last known position of enemies
This commit is contained in:
@@ -149,3 +149,39 @@
|
||||
// Simple mobs that retaliate and support others in their faction who get attacked.
|
||||
/datum/ai_holder/simple_mob/retaliate/cooperative
|
||||
cooperative = TRUE
|
||||
|
||||
// With all the bells and whistles
|
||||
/datum/ai_holder/simple_mob/humanoid
|
||||
intelligence_level = AI_SMART //Purportedly
|
||||
retaliate = TRUE //If attacked, attack back
|
||||
threaten = TRUE //Verbal threats
|
||||
firing_lanes = TRUE //Avoid shooting allies
|
||||
conserve_ammo = TRUE //Don't shoot when it can't hit target
|
||||
can_breakthrough = TRUE //Can break through doors
|
||||
violent_breakthrough = FALSE //Won't try to break through walls (humans can, but usually don't)
|
||||
speak_chance = 2 //Babble chance
|
||||
cooperative = TRUE //Assist each other
|
||||
wander = TRUE //Wander around
|
||||
returns_home = TRUE //But not too far
|
||||
use_astar = TRUE //Path smartly
|
||||
|
||||
// The hostile subtype is implied to be trained combatants who use ""tactics""
|
||||
/datum/ai_holder/simple_mob/humanoid/hostile
|
||||
var/run_if_this_close = 4 // If anything gets within this range, it'll try to move away.
|
||||
hostile = TRUE //Attack!
|
||||
|
||||
// Juke
|
||||
/datum/ai_holder/simple_mob/humanoid/hostile/post_melee_attack(atom/A)
|
||||
holder.IMove(get_step(holder, pick(alldirs)))
|
||||
holder.face_atom(A)
|
||||
|
||||
/datum/ai_holder/simple_mob/humanoid/hostile/post_ranged_attack(atom/A)
|
||||
//Pick a random turf to step into
|
||||
var/turf/T = get_step(holder, pick(alldirs))
|
||||
if(check_trajectory(A, T)) // Can we even hit them from there?
|
||||
holder.IMove(T)
|
||||
holder.face_atom(A)
|
||||
|
||||
if(get_dist(holder, A) < run_if_this_close)
|
||||
holder.IMove(get_step_away(holder, A))
|
||||
holder.face_atom(A)
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
if(rabid)
|
||||
return
|
||||
var/justified = my_slime.is_justified_to_discipline() // This will also consider the AI-side of that proc.
|
||||
lost_target() // Stop attacking.
|
||||
remove_target() // Stop attacking.
|
||||
|
||||
if(justified)
|
||||
obedience++
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||
// Called when using a pacification agent (or it's Kendrick being initalized).
|
||||
/datum/ai_holder/simple_mob/xenobio_slime/proc/pacify()
|
||||
lost_target() // So it stops trying to kill them.
|
||||
remove_target() // So it stops trying to kill them.
|
||||
rabid = FALSE
|
||||
hostile = FALSE
|
||||
retaliate = FALSE
|
||||
@@ -247,7 +247,7 @@
|
||||
else
|
||||
delayed_say("Fine...", speaker)
|
||||
adjust_discipline(1, TRUE) // This must come before losing the target or it will be unjustified.
|
||||
lost_target()
|
||||
remove_target()
|
||||
|
||||
|
||||
if(leader) // We're being asked to stop following someone.
|
||||
|
||||
@@ -93,9 +93,7 @@
|
||||
/datum/ai_holder/proc/forget_everything()
|
||||
// Some of these might be redundant, but hopefully this prevents future bugs if that changes.
|
||||
lose_follow()
|
||||
lose_target()
|
||||
lose_target_position()
|
||||
give_up_movement()
|
||||
remove_target()
|
||||
|
||||
// 'Tactical' processes such as moving a step, meleeing an enemy, firing a projectile, and other fairly cheap actions that need to happen quickly.
|
||||
/datum/ai_holder/proc/handle_tactics()
|
||||
@@ -116,33 +114,6 @@
|
||||
|
||||
/datum/ai_holder/proc/handle_special_strategical()
|
||||
|
||||
/*
|
||||
//AI Actions
|
||||
if(!ai_inactive)
|
||||
//Stanceyness
|
||||
handle_stance()
|
||||
|
||||
//Movement
|
||||
if(!stop_automated_movement && wander && !anchored) //Allowed to move?
|
||||
handle_wander_movement()
|
||||
|
||||
//Speaking
|
||||
if(speak_chance && stance == STANCE_IDLE) // Allowed to chatter?
|
||||
handle_idle_speaking()
|
||||
|
||||
//Resisting out buckles
|
||||
if(stance != STANCE_IDLE && incapacitated(INCAPACITATION_BUCKLED_PARTIALLY))
|
||||
handle_resist()
|
||||
|
||||
//Resisting out of closets
|
||||
if(istype(loc,/obj/structure/closet))
|
||||
var/obj/structure/closet/C = loc
|
||||
if(C.welded)
|
||||
resist()
|
||||
else
|
||||
C.open()
|
||||
*/
|
||||
|
||||
// For setting the stance WITHOUT processing it
|
||||
/datum/ai_holder/proc/set_stance(var/new_stance)
|
||||
ai_log("set_stance() : Setting stance from [stance] to [new_stance].", AI_LOG_INFO)
|
||||
@@ -221,7 +192,8 @@
|
||||
|
||||
if(STANCE_REPOSITION) // This is the same as above but doesn't stop if an enemy is visible since its an 'in-combat' move order.
|
||||
ai_log("handle_stance_tactical() : STANCE_REPOSITION, going to walk_to_destination().", AI_LOG_TRACE)
|
||||
walk_to_destination()
|
||||
if(!target && !find_target())
|
||||
walk_to_destination()
|
||||
|
||||
if(STANCE_FOLLOW)
|
||||
ai_log("handle_stance_tactical() : STANCE_FOLLOW, going to walk_to_leader().", AI_LOG_TRACE)
|
||||
@@ -247,12 +219,18 @@
|
||||
ai_log("++++++++++ Slow Process Beginning ++++++++++", AI_LOG_TRACE)
|
||||
ai_log("handle_stance_strategical() : Called.", AI_LOG_TRACE)
|
||||
|
||||
ai_log("handle_stance_strategical() : LTT=[lose_target_time]", AI_LOG_TRACE)
|
||||
if(lose_target_time && (lose_target_time + lose_target_timeout < world.time)) // We were tracking an enemy but they are gone.
|
||||
ai_log("handle_stance_strategical() : Giving up a chase.", AI_LOG_DEBUG)
|
||||
remove_target()
|
||||
|
||||
if(stance in STANCES_COMBAT)
|
||||
request_help() // Call our allies.
|
||||
|
||||
switch(stance)
|
||||
if(STANCE_IDLE)
|
||||
|
||||
if(speak_chance) // In the long loop since otherwise it wont shut up.
|
||||
handle_idle_speaking()
|
||||
|
||||
if(hostile)
|
||||
ai_log("handle_stance_strategical() : STANCE_IDLE, going to find_target().", AI_LOG_TRACE)
|
||||
find_target()
|
||||
@@ -260,6 +238,7 @@
|
||||
if(target)
|
||||
ai_log("handle_stance_strategical() : STANCE_APPROACH, going to calculate_path([target]).", AI_LOG_TRACE)
|
||||
calculate_path(target)
|
||||
walk_to_target()
|
||||
if(STANCE_MOVE)
|
||||
if(hostile && find_target()) // This will switch its stance.
|
||||
ai_log("handle_stance_strategical() : STANCE_MOVE, found target and was inturrupted.", AI_LOG_TRACE)
|
||||
@@ -269,6 +248,7 @@
|
||||
else if(leader)
|
||||
ai_log("handle_stance_strategical() : STANCE_FOLLOW, going to calculate_path([leader]).", AI_LOG_TRACE)
|
||||
calculate_path(leader)
|
||||
walk_to_leader()
|
||||
|
||||
ai_log("handle_stance_strategical() : Exiting.", AI_LOG_TRACE)
|
||||
ai_log("++++++++++ Slow Process Ending ++++++++++", AI_LOG_TRACE)
|
||||
|
||||
@@ -9,47 +9,23 @@
|
||||
var/violent_breakthrough = TRUE // If false, the AI is not allowed to destroy things like windows or other structures in the way. Requires above var to be true.
|
||||
|
||||
var/stand_ground = FALSE // If true, the AI won't try to get closer to an enemy if out of range.
|
||||
|
||||
|
||||
|
||||
// This does the actual attacking.
|
||||
/datum/ai_holder/proc/engage_target()
|
||||
ai_log("engage_target() : Entering.", AI_LOG_DEBUG)
|
||||
|
||||
// Can we still see them?
|
||||
// if(!target || !can_attack(target) || (!(target in list_targets())) )
|
||||
if(!target || !can_attack(target))
|
||||
ai_log("engage_target() : Lost sight of target.", AI_LOG_TRACE)
|
||||
lose_target() // We lost them.
|
||||
|
||||
if(!find_target()) // If we can't get a new one, then wait for a bit and then time out.
|
||||
set_stance(STANCE_IDLE)
|
||||
lost_target()
|
||||
ai_log("engage_target() : No more targets. Exiting.", AI_LOG_DEBUG)
|
||||
if(lose_target()) // We lost them (returns TRUE if we found something else to do)
|
||||
ai_log("engage_target() : Pursuing other options (last seen, or a new target).", AI_LOG_TRACE)
|
||||
return
|
||||
// if(lose_target_time + lose_target_timeout < world.time)
|
||||
// ai_log("engage_target() : Unseen enemy timed out.", AI_LOG_TRACE)
|
||||
// set_stance(STANCE_IDLE) // It must've been the wind.
|
||||
// lost_target()
|
||||
// ai_log("engage_target() : Exiting.", AI_LOG_DEBUG)
|
||||
// return
|
||||
|
||||
// // But maybe we do one last ditch effort.
|
||||
// if(!target_last_seen_turf || intelligence_level < AI_SMART)
|
||||
// ai_log("engage_target() : No last known position or is too dumb to fight unseen enemies.", AI_LOG_TRACE)
|
||||
// set_stance(STANCE_IDLE)
|
||||
// else
|
||||
// ai_log("engage_target() : Fighting unseen enemy.", AI_LOG_TRACE)
|
||||
// engage_unseen_enemy()
|
||||
else
|
||||
ai_log("engage_target() : Got new target ([target]).", AI_LOG_TRACE)
|
||||
|
||||
var/distance = get_dist(holder, target)
|
||||
ai_log("engage_target() : Distance to target ([target]) is [distance].", AI_LOG_TRACE)
|
||||
holder.face_atom(target)
|
||||
last_conflict_time = world.time
|
||||
|
||||
request_help() // Call our allies.
|
||||
|
||||
// Do a 'special' attack, if one is allowed.
|
||||
// if(prob(special_attack_prob) && (distance >= special_attack_min_range) && (distance <= special_attack_max_range))
|
||||
if(holder.ICheckSpecialAttack(target))
|
||||
@@ -198,12 +174,8 @@
|
||||
// Make sure we can still chase/attack them.
|
||||
if(!target || !can_attack(target))
|
||||
ai_log("walk_to_target() : Lost target.", AI_LOG_INFO)
|
||||
if(!find_target())
|
||||
lost_target()
|
||||
ai_log("walk_to_target() : Exiting.", AI_LOG_DEBUG)
|
||||
return
|
||||
else
|
||||
ai_log("walk_to_target() : Found new target ([target]).", AI_LOG_INFO)
|
||||
lose_target()
|
||||
return
|
||||
|
||||
// Find out where we're going.
|
||||
var/get_to = closest_distance(target)
|
||||
@@ -220,7 +192,6 @@
|
||||
ai_log("walk_to_target() : Exiting.", AI_LOG_DEBUG)
|
||||
return
|
||||
|
||||
|
||||
// Otherwise keep walking.
|
||||
if(!stand_ground)
|
||||
walk_path(target, get_to)
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
// Used when a target is out of sight or invisible.
|
||||
/datum/ai_holder/proc/engage_unseen_enemy()
|
||||
ai_log("engage_unseen_enemy() : Entering.", AI_LOG_TRACE)
|
||||
// Lets do some last things before giving up.
|
||||
if(!ranged)
|
||||
if(get_dist(holder, target_last_seen_turf > 1)) // We last saw them over there.
|
||||
if(conserve_ammo || !holder.ICheckRangedAttack(target_last_seen_turf))
|
||||
if(get_dist(holder, target_last_seen_turf) > 1) // We last saw them over there.
|
||||
// Go to where you last saw the enemy.
|
||||
give_destination(target_last_seen_turf, 1, TRUE) // This will set it to STANCE_REPOSITION.
|
||||
else // We last saw them next to us, so do a blind attack on that tile.
|
||||
give_destination(target_last_seen_turf, 1, TRUE) // Sets stance as well
|
||||
else if(lose_target_time == world.time) // We last saw them next to us, so do a blind attack on that tile.
|
||||
melee_on_tile(target_last_seen_turf)
|
||||
|
||||
else if(!conserve_ammo)
|
||||
else
|
||||
find_target()
|
||||
else
|
||||
shoot_near_turf(target_last_seen_turf)
|
||||
|
||||
// This shoots semi-randomly near a specific turf.
|
||||
/datum/ai_holder/proc/shoot_near_turf(turf/targeted_turf)
|
||||
if(!ranged)
|
||||
return // Can't shoot.
|
||||
if(get_dist(holder, targeted_turf) > max_range(targeted_turf))
|
||||
return // Too far to shoot.
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
// Attempts to attack something on a specific tile.
|
||||
// TODO: Put on mob/living?
|
||||
/datum/ai_holder/proc/melee_on_tile(turf/T)
|
||||
ai_log("melee_on_tile() : Entering.", AI_LOG_TRACE)
|
||||
var/mob/living/L = locate() in T
|
||||
if(!L)
|
||||
T.visible_message("\The [holder] attacks nothing around \the [T].")
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
/datum/ai_holder/proc/should_threaten()
|
||||
if(!threaten)
|
||||
return FALSE // We don't negotiate.
|
||||
if(target in attackers)
|
||||
if(check_attacker(target))
|
||||
return FALSE // They (or someone like them) attacked us before, escalate immediately.
|
||||
if(!will_threaten(target))
|
||||
return FALSE // Pointless to threaten an animal, a mindless drone, or an object.
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
ai_log("request_help() : Exiting.", AI_LOG_DEBUG)
|
||||
|
||||
// What allies receive when someone else is calling for help.
|
||||
// What allies receive when someone else is calling for help.1
|
||||
/datum/ai_holder/proc/help_requested(mob/living/friend)
|
||||
ai_log("help_requested() : Entering.", AI_LOG_DEBUG)
|
||||
if(stance == STANCE_SLEEP)
|
||||
@@ -92,24 +92,26 @@
|
||||
if(!holder.IIsAlly(friend)) // Extra sanity.
|
||||
ai_log("help_requested() : Help requested by [friend] but we hate them.", AI_LOG_INFO)
|
||||
return
|
||||
if(friend.ai_holder && friend.ai_holder.target && !can_attack(friend.ai_holder.target))
|
||||
ai_log("help_requested() : Help requested by [friend] but we don't want to fight their target.", AI_LOG_INFO)
|
||||
return
|
||||
if(get_dist(holder, friend) <= follow_distance)
|
||||
ai_log("help_requested() : Help requested by [friend] but we're already here.", AI_LOG_INFO)
|
||||
return
|
||||
if(get_dist(holder, friend) <= vision_range) // Within our sight.
|
||||
ai_log("help_requested() : Help requested by [friend], and within target sharing range.", AI_LOG_INFO)
|
||||
if(friend.ai_holder) // AI calling for help.
|
||||
if(friend.ai_holder.target && can_attack(friend.ai_holder.target)) // Friend wants us to attack their target.
|
||||
last_conflict_time = world.time // So we attack immediately and not threaten.
|
||||
give_target(friend.ai_holder.target) // This will set us to the appropiate stance.
|
||||
ai_log("help_requested() : Given target [target] by [friend]. Exiting", AI_LOG_DEBUG)
|
||||
return
|
||||
var/their_target = friend?.ai_holder?.target
|
||||
if(their_target) // They have a target and aren't just shouting for no reason
|
||||
if(!can_attack(their_target, vision_required = FALSE))
|
||||
ai_log("help_requested() : Help requested by [friend] but we don't want to fight their target.", AI_LOG_INFO)
|
||||
return
|
||||
if(get_dist(holder, friend) <= follow_distance)
|
||||
ai_log("help_requested() : Help requested by [friend] but we're already here.", AI_LOG_INFO)
|
||||
return
|
||||
if(get_dist(holder, friend) <= vision_range) // Within our sight.
|
||||
ai_log("help_requested() : Help requested by [friend], and within target sharing range.", AI_LOG_INFO)
|
||||
last_conflict_time = world.time // So we attack immediately and not threaten.
|
||||
give_target(their_target, urgent = TRUE) // This will set us to the appropiate stance.
|
||||
ai_log("help_requested() : Given target [target] by [friend]. Exiting", AI_LOG_DEBUG)
|
||||
return
|
||||
|
||||
// Otherwise they're outside our sight, lack a target, or aren't AI controlled, but within call range.
|
||||
// So assuming we're AI controlled, we'll go to them and see whats wrong.
|
||||
ai_log("help_requested() : Help requested by [friend], going to go to friend.", AI_LOG_INFO)
|
||||
if(their_target)
|
||||
add_attacker(their_target) // We won't wait and 'warn' them while they're stabbing our ally
|
||||
set_follow(friend, 10 SECONDS)
|
||||
ai_log("help_requested() : Exiting.", AI_LOG_DEBUG)
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
// Step 1, find out what we can see.
|
||||
/datum/ai_holder/proc/list_targets()
|
||||
. = hearers(vision_range, holder) - holder // Remove ourselves to prevent suicidal decisions. ~ SRC is the ai_holder.
|
||||
. -= dview_mob // Not the dview mob either, nerd.
|
||||
|
||||
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha))
|
||||
|
||||
@@ -35,6 +36,7 @@
|
||||
|
||||
// Step 2, filter down possible targets to things we actually care about.
|
||||
/datum/ai_holder/proc/find_target(var/list/possible_targets, var/has_targets_list = FALSE)
|
||||
ai_log("find_target() : Entered.", AI_LOG_TRACE)
|
||||
if(!hostile) // So retaliating mobs only attack the thing that hit it.
|
||||
return null
|
||||
. = list()
|
||||
@@ -70,13 +72,17 @@
|
||||
return chosen_target
|
||||
|
||||
// Step 4, give us our selected target.
|
||||
/datum/ai_holder/proc/give_target(new_target)
|
||||
/datum/ai_holder/proc/give_target(new_target, urgent = FALSE)
|
||||
ai_log("give_target() : Given '[new_target]', urgent=[urgent].", AI_LOG_TRACE)
|
||||
target = new_target
|
||||
|
||||
if(target != null)
|
||||
if(should_threaten())
|
||||
lose_target_time = 0
|
||||
track_target_position()
|
||||
if(should_threaten() && !urgent)
|
||||
set_stance(STANCE_ALERT)
|
||||
else
|
||||
set_stance(STANCE_APPROACH)
|
||||
set_stance(STANCE_FIGHT)
|
||||
last_target_time = world.time
|
||||
return TRUE
|
||||
|
||||
@@ -109,8 +115,8 @@
|
||||
sorted_targets += A
|
||||
return sorted_targets
|
||||
|
||||
/datum/ai_holder/proc/can_attack(atom/movable/the_target)
|
||||
if(!can_see_target(the_target))
|
||||
/datum/ai_holder/proc/can_attack(atom/movable/the_target, vision_required = TRUE)
|
||||
if(!can_see_target(the_target) && vision_required)
|
||||
return FALSE
|
||||
|
||||
if(istype(the_target, /mob/zshadow))
|
||||
@@ -157,21 +163,38 @@
|
||||
/datum/ai_holder/proc/found(atom/movable/the_target)
|
||||
return FALSE
|
||||
|
||||
//We can't see the target, go look or attack where they were last seen.
|
||||
// 'Soft' loss of target. They may still exist, we still have some info about them maybe.
|
||||
/datum/ai_holder/proc/lose_target()
|
||||
ai_log("lose_target() : Entering.", AI_LOG_TRACE)
|
||||
if(target)
|
||||
ai_log("lose_target() : Had a target, setting to null and LTT.", AI_LOG_DEBUG)
|
||||
target = null
|
||||
lose_target_time = world.time
|
||||
|
||||
give_up_movement()
|
||||
|
||||
if(target_last_seen_turf && intelligence_level >= AI_SMART)
|
||||
ai_log("lose_target() : Going into 'engage unseen enemy' mode.", AI_LOG_INFO)
|
||||
engage_unseen_enemy()
|
||||
return TRUE //We're still working on it
|
||||
else
|
||||
ai_log("lose_target() : Can't chase target, so giving up.", AI_LOG_INFO)
|
||||
remove_target()
|
||||
return find_target() //Returns if we found anything else to do
|
||||
|
||||
//Target is no longer valid (?)
|
||||
/datum/ai_holder/proc/lost_target()
|
||||
set_stance(STANCE_IDLE)
|
||||
return FALSE //Nothing new to do
|
||||
|
||||
// 'Hard' loss of target. Clean things up and return to idle.
|
||||
/datum/ai_holder/proc/remove_target()
|
||||
ai_log("remove_target() : Entering.", AI_LOG_TRACE)
|
||||
if(target)
|
||||
target = null
|
||||
|
||||
lose_target_time = 0
|
||||
give_up_movement()
|
||||
lose_target_position()
|
||||
lose_target()
|
||||
|
||||
set_stance(STANCE_IDLE)
|
||||
|
||||
// Check if target is visible to us.
|
||||
/datum/ai_holder/proc/can_see_target(atom/movable/the_target, view_range = vision_range)
|
||||
ai_log("can_see_target() : Entering.", AI_LOG_TRACE)
|
||||
@@ -235,7 +258,7 @@
|
||||
ai_log("react_to_attack() : Was attacked by [attacker], but we already have a target.", AI_LOG_TRACE)
|
||||
on_attacked(attacker) // So we attack immediately and not threaten.
|
||||
return FALSE
|
||||
else if(attacker in attackers && world.time > last_target_time + 3 SECONDS) // Otherwise, let 'er rip
|
||||
else if(check_attacker(attacker) && world.time > last_target_time + 3 SECONDS) // Otherwise, let 'er rip
|
||||
ai_log("react_to_attack() : Was attacked by [attacker]. Can retaliate, waited 3 seconds.", AI_LOG_INFO)
|
||||
on_attacked(attacker) // So we attack immediately and not threaten.
|
||||
return give_target(attacker) // Also handles setting the appropiate stance.
|
||||
@@ -246,16 +269,25 @@
|
||||
|
||||
ai_log("react_to_attack() : Was attacked by [attacker].", AI_LOG_INFO)
|
||||
on_attacked(attacker) // So we attack immediately and not threaten.
|
||||
return give_target(attacker) // Also handles setting the appropiate stance.
|
||||
return give_target(attacker, urgent = TRUE) // Also handles setting the appropiate stance.
|
||||
|
||||
// Sets a few vars so mobs that threaten will react faster to an attacker or someone who attacked them before.
|
||||
/datum/ai_holder/proc/on_attacked(atom/movable/AM)
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(!(L.name in attackers))
|
||||
attackers |= L.name
|
||||
last_conflict_time = world.time
|
||||
last_conflict_time = world.time
|
||||
add_attacker(AM)
|
||||
|
||||
// Checks to see if an atom attacked us lately
|
||||
/datum/ai_holder/proc/check_attacker(var/atom/movable/A)
|
||||
return (A in attackers)
|
||||
|
||||
// We were attacked by this thing recently
|
||||
/datum/ai_holder/proc/add_attacker(var/atom/movable/A)
|
||||
attackers |= A.name
|
||||
|
||||
// Forgive this attacker
|
||||
/datum/ai_holder/proc/remove_attacker(var/atom/movable/A)
|
||||
attackers -= A.name
|
||||
|
||||
// Causes targeting to prefer targeting the taunter if possible.
|
||||
// This generally occurs if more than one option is within striking distance, including the taunter.
|
||||
// Otherwise the default filter will prefer the closest target.
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
to_chat(user, "<span class='notice'>You feed \the [SM] the agent, calming it.</span>")
|
||||
|
||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||
AI.lost_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||
AI.remove_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||
var/newname = copytext(sanitize(input(user, "Would you like to give \the [M] a name?", "Name your new pet", M.name) as null|text),1,MAX_NAME_LEN)
|
||||
|
||||
if(newname)
|
||||
@@ -202,7 +202,7 @@
|
||||
to_chat(user, "<span class='notice'>You feed \the [M] the agent. It will now try to murder things that want to murder you instead.</span>")
|
||||
to_chat(M, "<span class='notice'>\The [user] feeds you \the [src], and feel that the others will regard you as an outsider now.</span>")
|
||||
M.faction = user.faction
|
||||
AI.lost_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||
AI.remove_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||
qdel(src)
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
to_chat(user, "<span class='notice'>You feed \the [M] the agent. It will now be your best friend.</span>")
|
||||
to_chat(M, "<span class='notice'>\The [user] feeds you \the [src], and feel that \the [user] wants to be best friends with you.</span>")
|
||||
M.friends.Add(user)
|
||||
AI.lost_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||
AI.remove_target() // So hostile things stop attacking people even if not hostile anymore.
|
||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -1359,6 +1359,7 @@
|
||||
#include "code\modules\ai\_defines.dm"
|
||||
#include "code\modules\ai\ai_holder.dm"
|
||||
#include "code\modules\ai\ai_holder_combat.dm"
|
||||
#include "code\modules\ai\ai_holder_combat_unseen.dm"
|
||||
#include "code\modules\ai\ai_holder_communication.dm"
|
||||
#include "code\modules\ai\ai_holder_cooperation.dm"
|
||||
#include "code\modules\ai\ai_holder_debug.dm"
|
||||
|
||||
Reference in New Issue
Block a user