Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lurker's scary AI #23

Merged
merged 27 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
55ce775
scary lurker (wip)
xDanilcusx Oct 22, 2023
8da6592
Merge branch 'PvE-CMSS13:master' into lurker-scary
xDanilcusx Oct 22, 2023
0d85ef1
the last thing left to do is signals
xDanilcusx Oct 22, 2023
3de531d
alright lurkers ready
xDanilcusx Oct 22, 2023
2d2ec3c
oopsie garbage code removed
xDanilcusx Oct 22, 2023
371454d
Merge branch 'PvE-CMSS13:master' into lurker-scary
xDanilcusx Oct 22, 2023
348fc7a
MINOR SPELLING MISTAKE
xDanilcusx Oct 22, 2023
407189d
another rookie mistake ughh sorry
xDanilcusx Oct 22, 2023
714ad2b
some minor fixes and lurker pounce knockdown nerf
xDanilcusx Oct 22, 2023
39ac21f
stop lurking on crit and small handle_ai_shot refactor
xDanilcusx Oct 23, 2023
70af3d3
added *hiss to bait emotes list
xDanilcusx Oct 24, 2023
c8d1723
made a /var for stalking feature (disabled by default)
xDanilcusx Oct 26, 2023
593ea10
Merge branch 'master' into lurker-scary
morrowwolf Oct 27, 2023
654dc3e
first pass
morrowwolf Oct 27, 2023
00f10ff
OK changed signs and some values
morrowwolf Oct 27, 2023
0576916
some more changes
morrowwolf Oct 27, 2023
089b8b6
Blocking yourself moment
morrowwolf Oct 27, 2023
21a2468
OK this time for sure
morrowwolf Oct 28, 2023
2c21820
light
morrowwolf Oct 28, 2023
97126a0
Revert "light"
morrowwolf Oct 28, 2023
94fc314
remove invis before pounce
xDanilcusx Oct 28, 2023
4801c11
Maybe this?
morrowwolf Oct 28, 2023
98a293e
less baits before push and no lingering corpses in invis
xDanilcusx Oct 28, 2023
e036032
do not bait while current target is in sight and home locating tweaks
xDanilcusx Oct 28, 2023
4a4c0f6
Merge branch 'PvE-CMSS13:master' into lurker-scary
xDanilcusx Oct 28, 2023
82c968a
bam
morrowwolf Oct 28, 2023
d4a464c
makes this atom movable because I'm paranoid
morrowwolf Oct 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/living/signals_xeno.dm
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,12 @@

/// For any additional things that should happen when a xeno's melee_attack_additional_effects_self() proc is called
#define COMSIG_XENO_SLASH_ADDITIONAL_EFFECTS_SELF "xeno_slash_additional_effects_self"

/// From /mob/living/carbon/xenomorph/proc/handle_crit()
#define COMSIG_XENO_HANDLE_CRIT "xeno_handle_crit"

/// From /datum/action/xeno_action/activable/pounce/use_ability()
#define COMSIG_XENO_USED_POUNCE "xeno_used_pounce"

/// From /mob/living/carbon/xenomorph/proc/handle_ai_shot()
#define COMSIG_XENO_HANDLE_AI_SHOT "xeno_handle_ai_shot"
2 changes: 2 additions & 0 deletions code/__DEFINES/xeno_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ PROBABILITY CALCULATIONS ARE HERE
#define RETREAT_AT_PLASMA_LEVEL 0.2
#define RETREAT_AT_HEALTH_LEVEL 0.4

#define LURKING_IGNORE_SHOT_CHANCE 75

// Warrior

/// How likely should it be that you lunge when off cooldown?
Expand Down
2 changes: 1 addition & 1 deletion code/modules/admin/game_master/game_master.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100)

// Spawn stuff
#define DEFAULT_SPAWN_XENO_STRING XENO_CASTE_DRONE
#define GAME_MASTER_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_CRUSHER)
#define GAME_MASTER_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER, XENO_CASTE_CRUSHER)

#define DEFAULT_XENO_AMOUNT_TO_SPAWN 1

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

#define DEFAULT_SPAWN_XENO_STRING XENO_CASTE_DRONE
#define GAME_MASTER_VENT_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER)
#define GAME_MASTER_VENT_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER)

#define DEFAULT_XENO_AMOUNT_TO_SPAWN 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@
LM.pass_flags = pounce_pass_flags
LM.collision_callbacks = pounce_callbacks

SEND_SIGNAL(owner, COMSIG_XENO_USED_POUNCE, A)

X.launch_towards(LM)

X.update_icons()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// Config options
distance = 6
knockdown = FALSE
knockdown_duration = 2.5
knockdown_duration = 1.5
freeze_self = TRUE
freeze_time = 15
can_be_shield_blocked = TRUE
Expand Down
269 changes: 269 additions & 0 deletions code/modules/mob/living/carbon/xenomorph/ai/movement/lurking.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
/datum/xeno_ai_movement/linger/lurking

// Are we currently hiding?
var/ai_lurking = FALSE

// Gradually increases the chance of AI to try and bait marines, annoyance accumulate when we lurk (stand invisible) and aware of our target
var/annoyance = 0

// Total baits this xeno has made
var/total_baits = 0

// Distance at which we want to stay from our spotted target
var/stalking_distance = 12

// List of turfs we see and register while lurking
var/list/registered_turfs = list()

// Let's lower this a little bit cause we do some heavy checks while finding our "home"
home_locate_range = 10

max_distance_from_home = 10

#define AI_CHECK_ANNOYANCE_COOLDOWN 2.5 SECONDS

/datum/xeno_ai_movement/linger/lurking/New(mob/living/carbon/xenomorph/parent)
. = ..()

RegisterSignal(parent, COMSIG_XENO_HANDLE_AI_SHOT, PROC_REF(stop_lurking))
RegisterSignal(parent, COMSIG_XENO_HANDLE_CRIT, PROC_REF(stop_lurking))
RegisterSignal(parent, COMSIG_XENO_USED_POUNCE, PROC_REF(stop_lurking))

addtimer(CALLBACK(src, PROC_REF(check_annoyance)), AI_CHECK_ANNOYANCE_COOLDOWN, TIMER_UNIQUE|TIMER_LOOP|TIMER_DELETE_ME)

#undef AI_CHECK_ANNOYANCE_COOLDOWN

/datum/xeno_ai_movement/linger/lurking/ai_move_idle(delta_time)
var/mob/living/carbon/xenomorph/idle_xeno = parent
if(idle_xeno.throwing)
return

if(home_turf)
if(get_dist(home_turf, idle_xeno) <= 0)
start_lurking()
return

if(!idle_xeno.move_to_next_turf(home_turf))
home_turf = null
return

return

if(next_home_search > world.time)
return

var/turf/current_turf = get_turf(idle_xeno)

if(!current_turf)
return

next_home_search = world.time + home_search_delay
var/shortest_distance = INFINITY
var/turf/non_preferred_turf
for(var/turf/potential_home as anything in shuffle(RANGE_TURFS(home_locate_range, current_turf)))
if(potential_home.density)
continue

var/blocked = FALSE
for(var/atom/potential_blocker as anything in potential_home)
if(potential_blocker != idle_xeno && (potential_blocker.can_block_movement || potential_blocker.density))
blocked = TRUE
break

if(blocked)
continue

var/preferred = FALSE
for(var/turf/closed/touching_turf in orange(1, potential_home))
preferred = TRUE
break

var/atom/movable/our_target = idle_xeno.current_target
if(our_target)
var/potential_home_dir = get_dir(idle_xeno, potential_home)
var/current_target_dir = get_dir(idle_xeno, our_target)

if(current_target_dir == potential_home_dir || current_target_dir == turn(potential_home_dir, 45) || current_target_dir == turn(potential_home_dir, -45))
continue

if(get_dist(potential_home, our_target) > stalking_distance)
continue

var/xeno_to_potential_home_distance = get_dist(idle_xeno, potential_home)
if(xeno_to_potential_home_distance > shortest_distance)
continue

if(preferred)
home_turf = potential_home
shortest_distance = xeno_to_potential_home_distance
continue

if(xeno_to_potential_home_distance < get_dist(idle_xeno, non_preferred_turf))
non_preferred_turf = potential_home
continue

if(!home_turf)
home_turf = non_preferred_turf
return

/datum/xeno_ai_movement/linger/lurking/ai_move_target(delta_time)
var/mob/living/carbon/xenomorph/moving_xeno = parent
if(moving_xeno.throwing)
return

var/incapacitated_check = TRUE
if(istype(moving_xeno.current_target, /mob))
var/mob/current_target_mob = moving_xeno.current_target
incapacitated_check = current_target_mob.is_mob_incapacitated()

if(incapacitated_check)
return ..()

var/turf/target_turf = get_turf(moving_xeno.current_target)
if(ai_lurking || get_dist(moving_xeno, target_turf) > world.view + 1)
if(get_dist(moving_xeno, target_turf) > stalking_distance)
home_turf = null
return moving_xeno.move_to_next_turf(target_turf)
return ai_move_idle(delta_time)

annoyance = 0
check_for_travelling_turf_change(moving_xeno)

if(!moving_xeno.move_to_next_turf(travelling_turf))
travelling_turf = target_turf
return TRUE

/datum/xeno_ai_movement/linger/lurking/proc/check_annoyance()
var/mob/living/carbon/xenomorph/annoyed_xeno = parent
if(!annoyed_xeno.current_target || !ai_lurking)
return

var/target_distance = get_dist(annoyed_xeno, annoyed_xeno.current_target)

if(target_distance < world.view)
return

if(target_distance > 10)
annoyance = 0
total_baits = 0
return

annoyance++

if(prob(annoyance))
try_bait()

#define LURKER_BAIT_TYPES list("Taunt","Emote","Interact")
#define LURKER_BAIT_EMOTES list("growl","roar","hiss","needshelp")
#define LURKER_BAIT_TAUNTS list("Come here, little host","I won't bite","I see you","Safe to go, little one")
#define LURKER_BAITS_BEFORE_AMBUSH 3

/datum/xeno_ai_movement/linger/lurking/proc/try_bait(no_interact)
var/mob/living/carbon/xenomorph/baiting_xeno = parent
if(baiting_xeno.throwing)
return

if(total_baits >= LURKER_BAITS_BEFORE_AMBUSH)
stop_lurking()
total_baits = 0
return

var/bait_types = LURKER_BAIT_TYPES
if(no_interact)
bait_types -= "Interact"

var/bait = pick(bait_types)
switch(bait)
if("Emote")
baiting_xeno.emote(pick(LURKER_BAIT_EMOTES))
if("Taunt")
baiting_xeno.say(pick(LURKER_BAIT_TAUNTS))
if("Interact")
if(!interact_random(baiting_xeno))
return try_bait(no_interact = TRUE)

total_baits++
annoyance = 0
return bait

#undef LURKER_BAIT_TYPES
#undef LURKER_BAIT_EMOTES
#undef LURKER_BAIT_TAUNTS
#undef LURKER_BAITS_BEFORE_AMBUSH

/datum/xeno_ai_movement/linger/lurking/proc/interact_random(mob/living/carbon/xenomorph/X)
for(var/obj/potential_interaction in orange(1, X))
if(istype(potential_interaction, /obj/structure/window_frame))
continue
if(istype(potential_interaction, /obj/structure/pipes))
continue
if(istype(potential_interaction, /obj/structure/sign))
continue
if(!potential_interaction.xeno_ai_act(X))
continue
return TRUE
return FALSE

/datum/xeno_ai_movement/linger/lurking/proc/start_lurking()
SIGNAL_HANDLER
if(ai_lurking)
return

var/mob/living/carbon/xenomorph/lurking_xeno = parent
animate(lurking_xeno, alpha = 20, time = 0.5 SECONDS, easing = QUAD_EASING)
lurking_xeno.set_movement_intent(MOVE_INTENT_WALK)
register_turf_signals()
ai_lurking = TRUE

RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(lurking_parent_moved))

var/datum/action/xeno_action/activable/pounce/lurker/LPA = get_xeno_action_by_type(lurking_xeno, /datum/action/xeno_action/activable/pounce/lurker)
if(LPA && istype(LPA))
LPA.knockdown = TRUE
LPA.freeze_self = TRUE

INVOKE_ASYNC(lurking_xeno, TYPE_PROC_REF(/mob, stop_pulling))

/datum/xeno_ai_movement/linger/lurking/proc/stop_lurking()
SIGNAL_HANDLER
if(!ai_lurking)
return

var/mob/living/carbon/xenomorph/lurking_xeno = parent
animate(lurking_xeno, alpha = initial(lurking_xeno.alpha), time = 0.2 SECONDS, easing = QUAD_EASING)
lurking_xeno.set_movement_intent(MOVE_INTENT_RUN)
unregister_turf_signals()
ai_lurking = FALSE

UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)

INVOKE_ASYNC(lurking_xeno, TYPE_PROC_REF(/mob, stop_pulling))

/datum/xeno_ai_movement/linger/lurking/proc/register_turf_signals()
for(var/turf/open/cycled_open_turf in view(world.view, parent))
RegisterSignal(cycled_open_turf, COMSIG_TURF_ENTERED, PROC_REF(set_target))
registered_turfs += cycled_open_turf

var/mob/living/carbon/human/possible_target = locate() in cycled_open_turf
if(possible_target && (!parent.current_target || get_dist(parent, possible_target) < get_dist(parent, parent.current_target)))
parent.current_target = possible_target

/datum/xeno_ai_movement/linger/lurking/proc/unregister_turf_signals()
for(var/turf/open/cycled_open_turf in registered_turfs)
UnregisterSignal(cycled_open_turf, COMSIG_TURF_ENTERED)
registered_turfs.Cut()

/datum/xeno_ai_movement/linger/lurking/proc/set_target(turf/hooked, atom/movable/entering_atom)
SIGNAL_HANDLER

if(!istype(entering_atom, /mob/living/carbon/human))
return

if(!parent.current_target || get_dist(parent, entering_atom) < get_dist(parent, parent.current_target))
parent.current_target = entering_atom

/datum/xeno_ai_movement/linger/lurking/proc/lurking_parent_moved(atom/movable/moving_atom, atom/oldloc, direction, Forced)
SIGNAL_HANDLER

unregister_turf_signals()
register_turf_signals()
14 changes: 9 additions & 5 deletions code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ GLOBAL_LIST_INIT(ai_target_limbs, list(
return new /datum/xeno_ai_movement(src)

/mob/living/carbon/xenomorph/proc/handle_ai_shot(obj/projectile/P)
if(!current_target && P.firer)
var/distance = get_dist(src, P.firer)
if(distance > max_travel_distance)
return
SEND_SIGNAL(src, COMSIG_XENO_HANDLE_AI_SHOT, P)

SSxeno_pathfinding.calculate_path(src, P.firer, distance, src, CALLBACK(src, PROC_REF(set_path)), list(src, P.firer))
if(current_target || !P.firer)
return

var/distance = get_dist(src, P.firer)
if(distance > max_travel_distance)
return

SSxeno_pathfinding.calculate_path(src, P.firer, distance, src, CALLBACK(src, PROC_REF(set_path)), list(src, P.firer))

/mob/living/carbon/xenomorph/proc/register_ai_action(datum/action/xeno_action/XA)
if(XA.owner != src)
Expand Down
Loading