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

Facehugger AI & autodoc now can extract embryos #17

Merged
merged 28 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
06e413d
facehuggers ai
xDanilcusx Oct 21, 2023
98a9e0a
Merge branch 'PvE-CMSS13:master' into facehugger-funny
xDanilcusx Oct 21, 2023
2cebba2
Merge branch 'master' into facehugger-funny
xDanilcusx Nov 1, 2023
500ad3b
nahhh next time
xDanilcusx Nov 1, 2023
1f52824
Merge branch 'master' into facehugger-funny
xDanilcusx Nov 4, 2023
73c3a2e
Merge branch 'master' into facehugger-funny
xDanilcusx Nov 27, 2023
0f1daf8
Merge branch 'PvE-CMSS13:master' into facehugger-funny
xDanilcusx Jan 15, 2024
a342db6
Merge branch 'PvE-CMSS13:master' into facehugger-funny
xDanilcusx Jan 15, 2024
9ffea68
Facehugger AI 2.0
xDanilcusx Jan 16, 2024
9cf756e
turning base hive radius down
xDanilcusx Jan 16, 2024
f057c06
proper layer for eggs
xDanilcusx Jan 16, 2024
7dd5bc0
XvX compat
xDanilcusx Jan 16, 2024
f470157
better XvX compat
xDanilcusx Jan 16, 2024
477ee4f
oh wait, this isnt used anywhere
xDanilcusx Jan 16, 2024
153d5be
facehugger has a chance to survive single shot now
xDanilcusx Jan 17, 2024
cbf2f1e
upping hugger impregnation time to 30-40 secs
xDanilcusx Jan 18, 2024
451da65
restrict facehuggers from trying to abduct people
xDanilcusx Jan 18, 2024
72382ef
useless carrier stuff so he would work with new huggers
xDanilcusx Jan 18, 2024
6365446
Merge branch 'master' into facehugger-funny
xDanilcusx Jan 22, 2024
4058a07
adds facehugger to ambush menu
xDanilcusx Jan 23, 2024
f325526
making my code more clean
xDanilcusx Jan 23, 2024
aeefbf7
Merge branch 'master' into facehugger-funny
xDanilcusx Jan 23, 2024
847794e
base larva gestation reduced (it's soul i promise)
xDanilcusx Feb 5, 2024
d76f7d8
hot and ready
xDanilcusx Feb 5, 2024
dd35014
Merge branch 'master' into facehugger-funny
xDanilcusx Feb 16, 2024
846f33d
mergeconfilcts begone
xDanilcusx Feb 16, 2024
d1406e4
Shrapnel Removal > Foreign Object Removal Surgery
xDanilcusx Feb 18, 2024
593008c
target hugger mask check bugfix
xDanilcusx Feb 18, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
if(!.)
return

if(isfacehugger(checked_xeno))
return FALSE

var/mob/parent_mob = parent

var/stat = parent_mob.stat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ GLOBAL_LIST_EMPTY(ai_hives)

max_assigned = 0

var/hive_radius = 7
var/hive_radius = 5

/datum/component/ai_behavior_override/hive/Initialize(...)
. = ..()
Expand Down
5 changes: 5 additions & 0 deletions code/game/machinery/medical_pod/autodoc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,11 @@
S.limb_ref.implants -= I
H.embedded_items -= I
qdel(I)
var/obj/item/larva_ref = locate(/obj/item/alien_embryo) in H.contents
if(S.limb_ref.name == "chest" && larva_ref)
sleep(REMOVE_OBJECT_MAX_DURATION*surgery_mod)
H.contents -= larva_ref
qdel(larva_ref)
if(S.limb_ref.name == "chest" || S.limb_ref.name == "head")
close_encased(H,S.limb_ref)
if(!surgery) break
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 @@ -29,7 +29,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_LURKER, XENO_CASTE_CRUSHER)
#define GAME_MASTER_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER, XENO_CASTE_CRUSHER, XENO_CASTE_FACEHUGGER)
#define DEFAULT_SPAWN_HIVE_STRING XENO_HIVE_NORMAL

#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_AMBUSH_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER)
#define GAME_MASTER_AMBUSH_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER, XENO_CASTE_FACEHUGGER)
#define DEFAULT_SPAWN_HIVE_STRING XENO_HIVE_NORMAL

#define DEFAULT_XENO_AMOUNT_TO_SPAWN 1
Expand Down
39 changes: 8 additions & 31 deletions code/modules/cm_aliens/structures/egg.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@
icon_state = "Egg Growing"
density = FALSE
anchored = TRUE
layer = LYING_BETWEEN_MOB_LAYER //to stop hiding eggs under corpses
layer = RESIN_STRUCTURE_LAYER //so facehuggers will be above the eggs
health = 80
plane = GAME_PLANE
var/list/egg_triggers = list()
var/status = EGG_GROWING //can be EGG_GROWING, EGG_GROWN, EGG_BURST, EGG_BURSTING, or EGG_DESTROYED; all mutually exclusive
var/on_fire = FALSE
var/hivenumber = XENO_HIVE_NORMAL
var/flags_embryo = NO_FLAGS
var/trigger_radius = 2

/obj/effect/alien/egg/Initialize(mapload, hive)
. = ..()
create_egg_triggers()
if (hive)
hivenumber = hive

Expand Down Expand Up @@ -93,21 +93,10 @@
update_icon()
deploy_egg_triggers()

/obj/effect/alien/egg/proc/create_egg_triggers()
for(var/i in 1 to 8)
egg_triggers += new /obj/effect/egg_trigger(src, src)

/obj/effect/alien/egg/proc/deploy_egg_triggers()
var/i = 1
var/x_coords = list(-1,-1,-1,0,0,1,1,1)
var/y_coords = list(1,0,-1,1,-1,1,0,-1)
var/turf/target_turf
for(var/trigger in egg_triggers)
var/obj/effect/egg_trigger/ET = trigger
target_turf = locate(x+x_coords[i],y+y_coords[i], z)
if(target_turf)
ET.forceMove(target_turf)
i++
var/list/observed_turfs = orange(trigger_radius, src)
for(var/target_turf in observed_turfs)
egg_triggers += new /obj/effect/egg_trigger(target_turf, src)

/obj/effect/alien/egg/proc/hide_egg_triggers()
for(var/trigger in egg_triggers)
Expand Down Expand Up @@ -136,20 +125,8 @@
status = EGG_BURST
if(is_hugger_player_controlled)
return //Don't need to spawn a hugger, a player controls it already!
var/obj/item/clothing/mask/facehugger/child = new(loc, hivenumber)

child.flags_embryo = flags_embryo
flags_embryo = NO_FLAGS // Lose the embryo flags when passed on

if(X && X.caste.can_hold_facehuggers && (!X.l_hand || !X.r_hand)) //sanity checks
X.put_in_hands(child)
return

if(instant_trigger)
if(!child.leap_at_nearest_target())
child.return_to_egg(src)
else
child.go_idle()
new /mob/living/carbon/xenomorph/facehugger(loc, null, hivenumber)

/obj/effect/alien/egg/bullet_act(obj/projectile/P)
..()
Expand Down Expand Up @@ -286,9 +263,9 @@
/obj/effect/egg_trigger/Crossed(atom/movable/AM)
if(!linked_egg && !linked_eggmorph) //something went very wrong.
qdel(src)
else if(linked_egg && (get_dist(src, linked_egg) != 1 || !isturf(linked_egg.loc))) //something went wrong
else if(linked_egg && (get_dist(src, linked_egg) > linked_egg.trigger_radius || !isturf(linked_egg.loc))) //something went wrong
forceMove(linked_egg)
else if(linked_eggmorph && (get_dist(src, linked_eggmorph) != 1 || !isturf(linked_eggmorph.loc))) //something went wrong
else if(linked_eggmorph && (get_dist(src, linked_eggmorph) > linked_egg.trigger_radius || !isturf(linked_eggmorph.loc))) //something went wrong
forceMove(linked_eggmorph)
else if(iscarbon(AM))
var/mob/living/carbon/C = AM
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/carbon/xenomorph/Facehuggers.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#define MIN_IMPREGNATION_TIME 10 SECONDS //Time it takes to impregnate someone
#define MAX_IMPREGNATION_TIME 15 SECONDS
#define MIN_IMPREGNATION_TIME 30 SECONDS //Time it takes to impregnate someone
#define MAX_IMPREGNATION_TIME 40 SECONDS

#define MIN_ACTIVE_TIME 5 SECONDS //Time between being dropped and going idle
#define MAX_ACTIVE_TIME 15 SECONDS
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/xenomorph/Xenomorph.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@
to_chat(src, SPAN_WARNING("[current_airlock] is locked down tight. You can't squeeze underneath!"))
return FALSE
visible_message(SPAN_WARNING("[src] scuttles underneath [current_structure]!"), \
SPAN_WARNING("You squeeze and scuttle underneath [current_structure]."), max_distance = 5)
SPAN_WARNING("You squeeze and scuttle underneath [current_structure]."), max_distance = 2)
forceMove(current_structure.loc)
return TRUE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
action_type = XENO_ACTION_CLICK
ability_primacy = XENO_PRIMARY_ACTION_3

default_ai_action = TRUE

/datum/action/xeno_action/activable/throw_hugger/action_cooldown_check()
if(owner)
var/mob/living/carbon/xenomorph/carrier/X = owner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
X.throw_hugger(A)
return ..()

/datum/action/xeno_action/activable/throw_hugger/process_ai(mob/living/carbon/xenomorph/X, delta_time)
var/distance = get_dist(X, X.current_target)
if(!DT_PROB(ai_prob_chance, delta_time) || distance < 3 || distance > 8)
return

use_ability_async(X.current_target)

/datum/action/xeno_action/activable/retrieve_egg/use_ability(atom/A)
var/mob/living/carbon/xenomorph/carrier/X = owner
X.retrieve_egg(A)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@
freeze_time = 5
freeze_play_sound = FALSE
can_be_shield_blocked = TRUE

ai_prob_chance = 45
130 changes: 130 additions & 0 deletions code/modules/mob/living/carbon/xenomorph/ai/movement/facehugger.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/datum/xeno_ai_movement/linger/facehugger/New(mob/living/carbon/xenomorph/parent)
. = ..()
var/turf/current_turf = get_turf(parent)
if(. != INITIALIZE_HINT_QDEL && (locate(/obj/effect/alien/egg) in current_turf))
home_turf = current_turf

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

if(next_home_search < world.time && (!home_turf || !valid_shelter(home_turf) || get_dist(home_turf, idle_xeno) > max_distance_from_home))
var/turf/T = get_turf(idle_xeno.loc)
next_home_search = world.time + home_search_delay
if(valid_shelter(T))
home_turf = T
else
var/shortest_distance = INFINITY
for(var/i in RANGE_TURFS(home_locate_range, T))
var/turf/potential_home = i
if(valid_shelter(potential_home) && get_dist(idle_xeno, potential_home) < shortest_distance)
home_turf = potential_home
shortest_distance = get_dist(idle_xeno, potential_home)

if(!home_turf)
return

if(idle_xeno.move_to_next_turf(home_turf, home_locate_range))
var/shelter = valid_shelter(home_turf)
if(get_dist(home_turf, idle_xeno) <= 0 && shelter)
idle_xeno.climb_in(shelter)
return
home_turf = null

/datum/xeno_ai_movement/linger/facehugger/proc/valid_shelter(turf/checked_turf)
var/mob/living/carbon/xenomorph/carrier/carrier = locate(/mob/living/carbon/xenomorph/carrier) in checked_turf
if(carrier && carrier.huggers_cur < carrier.huggers_max)
return carrier
var/obj/effect/alien/egg/eggy = locate(/obj/effect/alien/egg) in checked_turf
if(eggy && eggy.status == EGG_BURST)
return eggy

/datum/xeno_ai_movement/linger/facehugger/ai_move_target(delta_time)
var/mob/living/carbon/xenomorph/moving_xeno = parent

if(moving_xeno.action_busy)
return

return ..()

#define REENGAGE_COOLDOWN (7 SECONDS)
xDanilcusx marked this conversation as resolved.
Show resolved Hide resolved
#define FIND_NEW_TRAVEL_TURF_LIMIT 5
#define FIND_NEW_TRAVEL_RADIUS_MAX 10

/datum/xeno_ai_movement/linger/facehugger/check_for_travelling_turf_change(mob/living/carbon/xenomorph/moving_xeno)
if(!(moving_xeno in view(FIND_NEW_TRAVEL_RADIUS_MAX, moving_xeno.current_target)) && COOLDOWN_FINISHED(src, reengage_cooldown))
travelling_turf = get_turf(moving_xeno.current_target)
COOLDOWN_START(src, reengage_cooldown, REENGAGE_COOLDOWN)
moving_xeno.emote("growl")
return

if(!travelling_turf || get_dist(travelling_turf, moving_xeno) <= 0)
for(var/i = 0 to FIND_NEW_TRAVEL_TURF_LIMIT)
travelling_turf = get_random_turf_in_range_unblocked(moving_xeno.current_target, linger_range + linger_deviation, linger_range - linger_deviation)

if(!travelling_turf)
continue

if(get_dist(travelling_turf, moving_xeno.current_target) <= 4)
xDanilcusx marked this conversation as resolved.
Show resolved Hide resolved
continue

var/travelling_turf_dir = get_dir(moving_xeno, travelling_turf)
var/current_target_dir = get_dir(moving_xeno, moving_xeno.current_target)

if(current_target_dir != travelling_turf_dir && current_target_dir != turn(travelling_turf_dir, 45) && current_target_dir != turn(travelling_turf_dir, -45))
break

if(!travelling_turf)
travelling_turf = get_turf(moving_xeno.current_target)
return

#undef REENGAGE_COOLDOWN
#undef FIND_NEW_TRAVEL_TURF_LIMIT
#undef FIND_NEW_TRAVEL_RADIUS_MAX

/mob/living/carbon/xenomorph/facehugger/check_mob_target(mob/living/carbon/checked_target)
if(!ishuman(checked_target))
return FALSE // We don't wanna to attack anyone except humans

if(istype(checked_target.wear_mask, /obj/item/clothing/mask/facehugger))
return FALSE

if(checked_target.status_flags & XENO_HOST)
return FALSE

if(can_not_harm(checked_target))
return FALSE

if(checked_target.stat == DEAD)
return FALSE

return TRUE

/mob/living/carbon/xenomorph/facehugger/proc/climb_in(shelter)
set waitfor = FALSE

if(!do_after(src, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, shelter, INTERRUPT_NONE))
return

if(!shelter)
return

if(iscarrier(shelter))
var/mob/living/carbon/xenomorph/carrier/horsey = shelter
if(horsey.huggers_cur >= horsey.huggers_max)
return
visible_message(SPAN_XENOWARNING("[src] crawls onto [horsey]!"))
horsey.huggers_cur = min(horsey.huggers_max, horsey.huggers_cur + 1)
horsey.update_hugger_overlays()

else
var/obj/effect/alien/egg/eggy = shelter
if(eggy.status != EGG_BURST)
return
visible_message(SPAN_XENOWARNING("[src] crawls back into [eggy]!"))
eggy.status = EGG_GROWN
eggy.icon_state = "Egg"
eggy.deploy_egg_triggers()

qdel(src)
1 change: 1 addition & 0 deletions code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@
var/list/viable_targets = list()
var/atom/movable/closest_target
var/smallest_distance = INFINITY

for(var/mob/living/carbon/human/potential_alive_human_target as anything in GLOB.alive_human_list)
if(z != potential_alive_human_target.z)
continue
Expand Down
Loading