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 all 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
2 changes: 1 addition & 1 deletion code/__DEFINES/xeno.dm
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@
#define XENO_EXPLOSIVE_ARMOR_TIER_10 100

// Health bands
#define XENO_HEALTH_LARVA 35 * XENO_UNIVERSAL_HPMULT
#define XENO_HEALTH_LARVA 45 * XENO_UNIVERSAL_HPMULT
#define XENO_HEALTH_LESSER_DRONE 160 * XENO_UNIVERSAL_HPMULT
#define XENO_HEALTH_RUNNER 230 * XENO_UNIVERSAL_HPMULT // Killed by 1 PB
#define XENO_HEALTH_TIER_1 250 * XENO_UNIVERSAL_HPMULT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
if(!.)
return

if(isfacehugger(checked_xeno))
return FALSE

var/mob/parent_mob = parent

var/captee_stat = parent_mob.stat
Expand Down
38 changes: 27 additions & 11 deletions code/game/machinery/medical_pod/autodoc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@
if(H.disfigured)
surgery_list += create_autodoc_surgery(L,LIMB_SURGERY,"facial")

if(istype(L,/obj/limb/chest))
var/obj/limb/chest/C = L
if(M.status_flags & XENO_HOST)
surgery_list += create_autodoc_surgery(C,LIMB_SURGERY,"object")

if(L.status & LIMB_BROKEN)
surgery_list += create_autodoc_surgery(L,LIMB_SURGERY,"broken")
if(L.status & LIMB_DESTROYED)
Expand All @@ -256,7 +261,7 @@
if(L.implants.len)
for(var/I in L.implants)
if(!is_type_in_list(I,known_implants))
surgery_list += create_autodoc_surgery(L,LIMB_SURGERY,"shrapnel")
surgery_list += create_autodoc_surgery(L,LIMB_SURGERY,"object")
if(M.incision_depths[L.name] != SURGERY_DEPTH_SURFACE)
surgery_list += create_autodoc_surgery(L,LIMB_SURGERY,"open")
var/datum/internal_organ/I = M.internal_organs_by_name["eyes"]
Expand Down Expand Up @@ -481,8 +486,8 @@
H.updatehealth()
H.UpdateDamageIcon()

if("shrapnel")
if(prob(30)) visible_message("[icon2html(src, viewers(src))] \The <b>[src]</b> speaks: Beginning shrapnel removal.");
if("object")
if(prob(30)) visible_message("[icon2html(src, viewers(src))] \The <b>[src]</b> speaks: Beginning foreign object removal.");
if(S.unneeded)
sleep(UNNEEDED_DELAY)
visible_message("[icon2html(src, viewers(src))] \The <b>[src]</b> speaks: Procedure has been deemed unnecessary.");
Expand All @@ -500,6 +505,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 Expand Up @@ -716,9 +726,9 @@
if("missing")
surgeryqueue["missing"] = 1
dat += "Limb Replacement Surgery"
if("shrapnel")
surgeryqueue["shrapnel"] = 1
dat += "Shrapnel Removal Surgery"
if("object")
surgeryqueue["object"] = 1
dat += "Foreign Object Removal Surgery"
if("facial")
surgeryqueue["facial"] = 1
dat += "Facial Reconstruction Surgery"
Expand All @@ -743,8 +753,8 @@
dat += "<a href='?src=\ref[src];internal=1'>Internal Bleeding Surgery</a><br>"
if(isnull(surgeryqueue["open"]))
dat += "<a href='?src=\ref[src];open=1'>Close Open Incisions</a><br>"
if(isnull(surgeryqueue["shrapnel"]))
dat += "<a href='?src=\ref[src];shrapnel=1'>Shrapnel Removal Surgery</a><br>"
if(isnull(surgeryqueue["object"]))
dat += "<a href='?src=\ref[src];object=1'>Foreign Object Removal Surgery</a><br>"
dat += "<b>Organ Surgeries</b>"
dat += "<br>"
if(isnull(surgeryqueue["eyes"]))
Expand Down Expand Up @@ -852,17 +862,23 @@
N.fields["autodoc_manual"] += create_autodoc_surgery(null,LIMB_SURGERY,"missing",1)
updateUsrDialog()

if(href_list["shrapnel"])
if(href_list["object"])
var/known_implants = list(/obj/item/implant/chem, /obj/item/implant/death_alarm, /obj/item/implant/loyalty, /obj/item/implant/tracking, /obj/item/implant/neurostim)
for(var/obj/limb/L in connected.occupant.limbs)
if(L)
if(istype(L,/obj/limb/chest))
var/obj/limb/chest/C = L
if(connected.occupant.status_flags & XENO_HOST)
N.fields["autodoc_manual"] += create_autodoc_surgery(C,LIMB_SURGERY,"object")
needed++
continue
if(L.implants.len)
for(var/I in L.implants)
if(!is_type_in_list(I,known_implants))
N.fields["autodoc_manual"] += create_autodoc_surgery(L,LIMB_SURGERY,"shrapnel")
N.fields["autodoc_manual"] += create_autodoc_surgery(L,LIMB_SURGERY,"object")
needed++
if(!needed)
N.fields["autodoc_manual"] += create_autodoc_surgery(null,LIMB_SURGERY,"shrapnel",1)
N.fields["autodoc_manual"] += create_autodoc_surgery(null,LIMB_SURGERY,"object",1)
updateUsrDialog()

if(href_list["facial"])
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
81 changes: 81 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,81 @@
/datum/xeno_ai_movement/linger/facehugger
linger_range = 8
reengage_interval = (12 SECONDS)

/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 ..()

/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)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
/// The cooldown for how long the xeno will wait out of view before attempting to re-engage
COOLDOWN_DECLARE(reengage_cooldown)

var/reengage_interval = (2 SECONDS)

/datum/xeno_ai_movement/linger/ai_move_target(delta_time)
var/mob/living/carbon/xenomorph/moving_xeno = parent
if(moving_xeno.throwing)
Expand All @@ -32,13 +34,12 @@
travelling_turf = get_turf(moving_xeno.current_target)
return TRUE

#define REENGAGE_COOLDOWN (2 SECONDS)
#define FIND_NEW_TRAVEL_TURF_LIMIT 5

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

Expand All @@ -59,5 +60,4 @@
travelling_turf = get_turf(moving_xeno.current_target)
return

#undef REENGAGE_COOLDOWN
#undef FIND_NEW_TRAVEL_TURF_LIMIT
4 changes: 2 additions & 2 deletions code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@
var/smallest_distance = INFINITY

for(var/mob/living/carbon/potential_target as anything in GLOB.alive_mob_list)
if(!iscarbon(potential_target))
if(!istype(potential_target))
continue

if(z != potential_target.z)
Expand Down Expand Up @@ -339,7 +339,7 @@
#undef EXTRA_CHECK_DISTANCE_MULTIPLIER

/mob/living/carbon/proc/ai_can_target(mob/living/carbon/xenomorph/ai_xeno)
if(!ai_check_stat())
if(!ai_check_stat(ai_xeno))
return FALSE

if(ai_xeno.can_not_harm(src))
Expand Down
Loading
Loading