diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm index 566fe0eaea..cbc2163dfe 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_abilities.dm @@ -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 diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_powers.dm index 1ee32225a4..da85b94502 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/carrier/carrier_powers.dm @@ -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) diff --git a/code/modules/mob/living/carbon/xenomorph/ai/movement/facehugger.dm b/code/modules/mob/living/carbon/xenomorph/ai/movement/facehugger.dm index 3fe30af6e8..4bb037e599 100644 --- a/code/modules/mob/living/carbon/xenomorph/ai/movement/facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/ai/movement/facehugger.dm @@ -9,30 +9,36 @@ if(idle_xeno.throwing) return - if(next_home_search < world.time && (!home_turf || !(locate(/obj/effect/alien/egg) in home_turf) || get_dist(home_turf, idle_xeno) > max_distance_from_home)) + 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 - var/obj/effect/alien/egg/possible_egg = locate(/obj/effect/alien/egg) in T - if(possible_egg && possible_egg.status == EGG_BURST) + 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 - possible_egg = locate(/obj/effect/alien/egg) in potential_home - if(possible_egg && possible_egg.status == EGG_BURST && get_dist(idle_xeno, potential_home) < shortest_distance) + 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 - var/obj/effect/alien/egg/eggy = locate(/obj/effect/alien/egg) in home_turf - if(idle_xeno.move_to_next_turf(home_turf, home_locate_range) && eggy && eggy.status == EGG_BURST) - if(get_dist(home_turf, idle_xeno) <= 0) - idle_xeno.climb_in_egg(eggy) - else - home_turf = null + 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 @@ -95,13 +101,28 @@ return TRUE -/mob/living/carbon/xenomorph/facehugger/proc/climb_in_egg(obj/effect/alien/egg/eggy) +/mob/living/carbon/xenomorph/facehugger/proc/climb_in(shelter) set waitfor = FALSE - if(do_after(src, 10, INTERRUPT_ALL, BUSY_ICON_GENERIC, eggy)) - visible_message(SPAN_XENOWARNING("[src] crawls back into [eggy]!")) - eggy.status = EGG_GROWN - eggy.icon_state = "Egg" - eggy.deploy_egg_triggers() - qdel(src) + if(do_after(src, 10, INTERRUPT_ALL, BUSY_ICON_GENERIC, shelter, INTERRUPT_NONE)) + 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) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index c13555cba1..018b79227e 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -17,7 +17,7 @@ evolution_allowed = FALSE deevolves_to = list(XENO_CASTE_DRONE) - throwspeed = SPEED_AVERAGE + throwspeed = SPEED_FAST can_hold_facehuggers = 1 can_hold_eggs = CAN_HOLD_ONE_HAND weed_level = WEED_LEVEL_STANDARD @@ -176,6 +176,8 @@ . = ..() hugger_overlays_icon = mutable_appearance('icons/mob/xenos/overlay_effects64x64.dmi',"empty") eggsac_overlays_icon = mutable_appearance('icons/mob/xenos/overlay_effects64x64.dmi',"empty") + huggers_cur = rand(3,16) + update_hugger_overlays() /mob/living/carbon/xenomorph/carrier/death(cause, gibbed) . = ..(cause, gibbed) @@ -187,11 +189,13 @@ if(huggers_cur) //Hugger explosion, like an egg morpher - var/obj/item/clothing/mask/facehugger/hugger + var/mob/living/carbon/xenomorph/facehugger/hugger visible_message(SPAN_XENOWARNING("The chittering mass of tiny aliens is trying to escape [src]!")) for(var/i in 1 to huggers_cur) if(prob(chance)) - hugger = new(loc, hivenumber) + hugger = new(loc) + if(hivenumber != XENO_HIVE_NORMAL) + hugger.set_hive_and_update(hivenumber) step_away(hugger, src, 1) var/eggs_dropped = FALSE @@ -255,6 +259,8 @@ if(!check_state()) return + face_atom(T) + //target a hugger on the ground to store it directly if(istype(T, /obj/item/clothing/mask/facehugger)) var/obj/item/clothing/mask/facehugger/F = T @@ -282,42 +288,42 @@ store_huggers_from_egg_morpher(morpher) return - var/obj/item/clothing/mask/facehugger/F = get_active_hand() - if(!F) //empty active hand - //if no hugger in active hand, we take one from our storage - if(huggers_cur <= 0) - to_chat(src, SPAN_WARNING("You don't have any facehuggers to use!")) - return - - if(on_fire) - to_chat(src, SPAN_WARNING("Retrieving a stored facehugger while you're on fire would burn it!")) - return + //We throw a hugger from our storage + if(huggers_cur <= 0) + to_chat(src, SPAN_WARNING("You don't have any facehuggers to use!")) + return - F = new(src, hivenumber) - huggers_cur-- - put_in_active_hand(F) - to_chat(src, SPAN_XENONOTICE("You grab one of the facehugger in your storage. Now sheltering: [huggers_cur] / [huggers_max].")) - update_icons() + if(threw_a_hugger) return - if(!istype(F)) //something else in our hand - to_chat(src, SPAN_WARNING("You need a facehugger in your hand to throw one!")) + threw_a_hugger = TRUE + for(var/X in actions) + var/datum/action/A = X + A.update_button_icon() + + if(!do_after(src, 10, INTERRUPT_INCAPACITATED, BUSY_ICON_HOSTILE)) return - if(!threw_a_hugger) - threw_a_hugger = TRUE + var/turf/target_turf = get_turf(T) + + var/mob/living/carbon/xenomorph/facehugger/child = new(loc) + if(hivenumber != XENO_HIVE_NORMAL) + child.set_hive_and_update(hivenumber) + + visible_message(SPAN_XENOWARNING("\The [src] throws something towards \the [target_turf]!"), \ + SPAN_XENOWARNING("You throw a facehugger towards \the [target_turf]!")) + + huggers_cur-- + update_icons() + + playsound(loc, get_sfx("alien_tail_swipe"), 120, 1) + child.throw_atom(target_turf, 6, caste.throwspeed) + + spawn(caste.hugger_delay) + threw_a_hugger = 0 for(var/X in actions) var/datum/action/A = X A.update_button_icon() - drop_inv_item_on_ground(F) - F.throw_atom(T, 4, caste.throwspeed) - visible_message(SPAN_XENOWARNING("\The [src] throws something towards \the [T]!"), \ - SPAN_XENOWARNING("You throw a facehugger towards \the [T]!")) - spawn(caste.hugger_delay) - threw_a_hugger = 0 - for(var/X in actions) - var/datum/action/A = X - A.update_button_icon() /mob/living/carbon/xenomorph/carrier/proc/store_egg(obj/item/xeno_egg/E) if(E.hivenumber != hivenumber)