diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index 5ce90a76319..a42a780bd58 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -95,8 +95,6 @@ #define BB_WHELP_STRAIGHTLINE_FIRE "BB_whelp_straightline_fire" ///whelp's secondary enraged ability #define BB_WHELP_WIDESPREAD_FIRE "BB_whelp_widespread_fire" -///how enraged the whelp is -#define BB_WHELP_ENRAGED "BB_whelp_enraged" ///the target rock we will attempt to create a sculpture out of #define BB_TARGET_ROCK "BB_target_rock" ///the cannibal target we shall consume diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm index 33cc871fddc..1e438ea0979 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm @@ -5,7 +5,7 @@ /datum/ai_behavior/targeted_mob_ability /datum/ai_behavior/targeted_mob_ability/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key) - var/datum/action/cooldown/ability = get_ability_to_use(controller, ability_key) + var/datum/action/cooldown/ability = controller.blackboard[ability_key] var/mob/living/target = controller.blackboard[target_key] if(QDELETED(ability) || QDELETED(target)) return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED @@ -16,9 +16,6 @@ return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED -/datum/ai_behavior/targeted_mob_ability/proc/get_ability_to_use(datum/ai_controller/controller, ability_key) - return controller.blackboard[ability_key] - /** * # Try Mob Ability and plan execute * Attempts to use a mob's cooldown ability on a target and then move the target into a special target blackboard datum diff --git a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm index cd809804ba3..010dd04a425 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm @@ -19,10 +19,16 @@ var/datum/action/cooldown/using_action = controller.blackboard[ability_key] if (!using_action?.IsAvailable()) return + if (!additional_ability_checks(controller, using_action)) + return controller.queue_behavior(use_ability_behaviour, ability_key, target_key) if (finish_planning) return SUBTREE_RETURN_FINISH_PLANNING +/// Any additional checks before we queue the behaviour +/datum/ai_planning_subtree/targeted_mob_ability/proc/additional_ability_checks(datum/ai_controller/controller, datum/action/cooldown/using_action) + return TRUE + /datum/ai_planning_subtree/targeted_mob_ability/continue_planning finish_planning = FALSE diff --git a/code/datums/components/telegraph_ability.dm b/code/datums/components/telegraph_ability.dm deleted file mode 100644 index bff2ea7ea8f..00000000000 --- a/code/datums/components/telegraph_ability.dm +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Component given to creatures to telegraph their abilities! - */ -/datum/component/basic_mob_ability_telegraph - /// how long before we use our attack - var/telegraph_time - /// sound to play, if any - var/sound_path - /// are we currently telegraphing - var/currently_telegraphing = FALSE - -/datum/component/basic_mob_ability_telegraph/Initialize(telegraph_time = 1 SECONDS, sound_path) - - if(!isliving(parent)) - return COMPONENT_INCOMPATIBLE - src.telegraph_time = telegraph_time - src.sound_path = sound_path - -/datum/component/basic_mob_ability_telegraph/RegisterWithParent() - RegisterSignal(parent, COMSIG_MOB_ABILITY_STARTED, PROC_REF(on_ability_activate)) - -/datum/component/basic_mob_ability_telegraph/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_MOB_ABILITY_STARTED) - -///delay the ability -/datum/component/basic_mob_ability_telegraph/proc/on_ability_activate(mob/living/source, datum/action/cooldown/activated, atom/target) - SIGNAL_HANDLER - - if(currently_telegraphing) - return COMPONENT_BLOCK_ABILITY_START - - if(!activated.IsAvailable()) - return - - currently_telegraphing = TRUE - generate_tell_signs(source) - addtimer(CALLBACK(src, PROC_REF(use_ability), source, activated, target), telegraph_time) - return COMPONENT_BLOCK_ABILITY_START - -///generates the telegraph signs to inform the player we're about to launch an attack -/datum/component/basic_mob_ability_telegraph/proc/generate_tell_signs(mob/living/source) - if(sound_path) - playsound(source, sound_path, 50, FALSE) - source.Shake(duration = telegraph_time) - -///use the ability -/datum/component/basic_mob_ability_telegraph/proc/use_ability(mob/living/source, datum/action/cooldown/activated, atom/target) - if(!QDELETED(target) && source.stat != DEAD) //target is gone or we died - activated.Activate(target) - currently_telegraphing = FALSE diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm index e30a2910ca0..83624b7423c 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp.dm @@ -43,15 +43,14 @@ ADD_TRAIT(src, TRAIT_NO_GLIDE, INNATE_TRAIT) AddElement(/datum/element/footstep, FOOTSTEP_MOB_HEAVY) - AddComponent(/datum/component/basic_mob_ability_telegraph) var/static/list/innate_actions = list( /datum/action/cooldown/mob_cooldown/fire_breath/ice = BB_WHELP_STRAIGHTLINE_FIRE, - /datum/action/cooldown/mob_cooldown/fire_breath/ice/cross = BB_WHELP_WIDESPREAD_FIRE, + /datum/action/cooldown/mob_cooldown/fire_breath/ice/eruption = BB_WHELP_WIDESPREAD_FIRE, ) grant_actions_by_list(innate_actions) - + ai_controller.set_blackboard_key(BB_TARGETED_ACTION, ai_controller.blackboard[BB_WHELP_STRAIGHTLINE_FIRE]) /mob/living/basic/mining/ice_whelp/early_melee_attack(atom/target, list/modifiers, ignore_cooldown) . = ..() diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_abilities.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_abilities.dm index 617295ef6ba..f0c5c23cb1c 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_abilities.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_abilities.dm @@ -4,9 +4,45 @@ desc = "Fire a cold line of fire towards the enemy!" button_icon = 'icons/effects/magic.dmi' button_icon_state = "fireball" - cooldown_time = 3 SECONDS - fire_range = 4 + cooldown_time = 6 SECONDS + fire_range = 7 fire_damage = 10 + fire_delay = 0.75 DECISECONDS + /// Time to warn people about what we are doing + var/forecast_delay = 0.5 SECONDS + /// What turf are we aiming at? + var/turf/target_turf + /// Overlay we show when we're about to fire + var/image/forecast_overlay + /// Icon state used for overlay + var/forecast_overlay_state = "ice_whelp_telegraph_dir" + +/datum/action/cooldown/mob_cooldown/fire_breath/ice/New(Target, original) + . = ..() + forecast_overlay = image('icons/mob/simple/icemoon/icemoon_monsters.dmi', forecast_overlay_state) + +/// Apply our specific fire breathing shape, in proc form so we can override it in subtypes +/datum/action/cooldown/mob_cooldown/fire_breath/ice/attack_sequence(atom/target) + target_turf = get_turf(target) + INVOKE_ASYNC(src, PROC_REF(attack_forecast)) + +/// Charge up before we breathe fire +/datum/action/cooldown/mob_cooldown/fire_breath/ice/proc/attack_forecast() + owner.face_atom(target_turf) + owner.Shake(pixelshiftx = 1, pixelshifty = 0, duration = forecast_delay) + forecast_overlay.setDir(get_dir(owner, target_turf)) + owner.add_overlay(forecast_overlay) + var/succeeded = do_after(owner, delay = forecast_delay, target = owner, hidden = TRUE) + owner.cut_overlay(forecast_overlay) + if (succeeded) + playsound(owner.loc, fire_sound, 200, TRUE) + breath_attack() + +/// Actually breathe fire +/datum/action/cooldown/mob_cooldown/fire_breath/ice/proc/breath_attack() + owner.face_atom(target_turf) + fire_line(target_turf) + target_turf = null /datum/action/cooldown/mob_cooldown/fire_breath/ice/burn_turf(turf/fire_turf, list/hit_list, atom/source) var/obj/effect/hotspot/fire_hotspot = ..() @@ -19,17 +55,32 @@ barbecued.adjustFireLoss(fire_damage) /// Breathe really cold fire in a plus shape, like bomberman -/datum/action/cooldown/mob_cooldown/fire_breath/ice/cross - name = "Fire all directions" - desc = "Unleash lines of cold fire in all directions" +/datum/action/cooldown/mob_cooldown/fire_breath/ice/eruption + name = "Ice Eruption" + desc = "Unleash cold fire in all directions" button_icon = 'icons/effects/fire.dmi' button_icon_state = "light" - cooldown_time = 4 SECONDS + cooldown_time = 6 SECONDS click_to_activate = FALSE - fire_range = 6 + fire_range = 3 + forecast_delay = 1 SECONDS + fire_delay = 1.5 DECISECONDS + forecast_overlay_state = "ice_whelp_telegraph_all" -/datum/action/cooldown/mob_cooldown/fire_breath/ice/cross/attack_sequence(atom/target) - playsound(owner.loc, fire_sound, 200, TRUE) - for(var/direction in GLOB.cardinals) - var/turf/target_fire_turf = get_ranged_target_turf(owner, direction, fire_range) - fire_line(target_fire_turf) +/datum/action/cooldown/mob_cooldown/fire_breath/ice/eruption/breath_attack() + target_turf = null + + var/list/hit_list = list(owner) + var/list/nearby_turfs = list() + for (var/turf/open/target_turf in circle_range(owner, fire_range)) + if (target_turf.is_blocked_turf(exclude_mobs = TRUE)) + continue + var/turf_dist = get_dist(owner, target_turf) + if (turf_dist == 0) + continue + LAZYADDASSOCLIST(nearby_turfs, "[turf_dist]", target_turf) + + for (var/i in 1 to fire_range) + for (var/turf/open/kindling as anything in nearby_turfs["[i]"]) + burn_turf(kindling, hit_list, owner) + sleep(fire_delay) diff --git a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm index 33d091db4e4..55f6181374d 100644 --- a/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm +++ b/code/modules/mob/living/basic/icemoon/ice_whelp/ice_whelp_ai.dm @@ -1,9 +1,7 @@ -#define ENRAGE_ADDITION 25 /datum/ai_controller/basic_controller/ice_whelp blackboard = list( BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, BB_TARGET_MINIMUM_STAT = HARD_CRIT, - BB_WHELP_ENRAGED = 0, ) ai_movement = /datum/ai_movement/basic_avoidance @@ -12,12 +10,29 @@ /datum/ai_planning_subtree/simple_find_target, /datum/ai_planning_subtree/targeted_mob_ability/ice_whelp, /datum/ai_planning_subtree/attack_obstacle_in_path, - /datum/ai_planning_subtree/basic_melee_attack_subtree, + /datum/ai_planning_subtree/basic_melee_attack_subtree/ice_whelp, /datum/ai_planning_subtree/sculpt_statues, /datum/ai_planning_subtree/find_and_hunt_target/corpses/ice_whelp, /datum/ai_planning_subtree/burn_trees, ) +/// Cancel melee attacks when we have our breath weapon +/datum/ai_planning_subtree/basic_melee_attack_subtree + +/datum/ai_planning_subtree/basic_melee_attack_subtree/ice_whelp + melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/ice_whelp + +/// Cancel melee attacks when we have our breath weapon +/datum/ai_behavior/basic_melee_attack/ice_whelp + +/datum/ai_behavior/basic_melee_attack/ice_whelp/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) + var/datum/action/cooldown/breath_weapon = controller.blackboard[BB_TARGETED_ACTION] + if (breath_weapon?.IsAvailable()) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED + + return ..() + +/// Find other tasty dragons /datum/ai_planning_subtree/find_and_hunt_target/corpses/ice_whelp target_key = BB_TARGET_CANNIBAL finding_behavior = /datum/ai_behavior/find_hunt_target/corpses/dragon_corpse @@ -32,6 +47,7 @@ return FALSE return ..() +/// Eat other dragons /datum/ai_behavior/hunt_target/interact_with_target/dragon_cannibalise behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION @@ -74,28 +90,31 @@ . = ..() controller.clear_blackboard_key(target_key) -//subtree to use our attacks on the victim +/// Only use ability if we are within range /datum/ai_planning_subtree/targeted_mob_ability/ice_whelp - ability_key = BB_WHELP_STRAIGHTLINE_FIRE use_ability_behaviour = /datum/ai_behavior/targeted_mob_ability/ice_whelp - finish_planning = FALSE +/datum/ai_planning_subtree/targeted_mob_ability/ice_whelp/additional_ability_checks(datum/ai_controller/controller, datum/action/cooldown/using_action) + var/atom/target = controller.blackboard[target_key] + var/range_to_target = get_dist(controller.pawn, target) + return range_to_target < /datum/action/cooldown/mob_cooldown/fire_breath/ice::fire_range +/// Select appropriate ability based on range /datum/ai_behavior/targeted_mob_ability/ice_whelp - ///key that stores how enraged we are - var/enraged_key = BB_WHELP_ENRAGED - ///key that stores the ability we will use instead if we are fully enraged - var/secondary_ability_key = BB_WHELP_WIDESPREAD_FIRE -/datum/ai_behavior/targeted_mob_ability/ice_whelp/get_ability_to_use(datum/ai_controller/controller, ability_key) - var/enraged_value = controller.blackboard[enraged_key] +/datum/ai_behavior/targeted_mob_ability/ice_whelp/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key) + var/mob/living/target = controller.blackboard[target_key] + if (isnull(target)) + return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED - if(prob(enraged_value)) - controller.set_blackboard_key(enraged_key, 0) - return controller.blackboard[secondary_ability_key] + var/dist_to_target = get_dist(controller.pawn, target) + var/datum/action/cooldown/mob_cooldown/fire_breath/ice/short_range_ability = controller.blackboard[BB_WHELP_WIDESPREAD_FIRE] + if (isnull(short_range_ability) || dist_to_target > short_range_ability.fire_range) + controller.set_blackboard_key(BB_TARGETED_ACTION, controller.blackboard[BB_WHELP_STRAIGHTLINE_FIRE]) + return ..() - controller.set_blackboard_key(enraged_key, enraged_value + ENRAGE_ADDITION) - return controller.blackboard[ability_key] + controller.set_blackboard_key(BB_TARGETED_ACTION, controller.blackboard[BB_WHELP_WIDESPREAD_FIRE]) + return ..() ///subtree to look for trees and burn them with our flamethrower /datum/ai_planning_subtree/burn_trees @@ -138,5 +157,3 @@ if(QDELETED(target)) return FALSE set_movement_target(controller, target) - -#undef ENRAGE_ADDITION diff --git a/icons/mob/simple/icemoon/icemoon_monsters.dmi b/icons/mob/simple/icemoon/icemoon_monsters.dmi index 739092d63ad..9439e504d6e 100644 Binary files a/icons/mob/simple/icemoon/icemoon_monsters.dmi and b/icons/mob/simple/icemoon/icemoon_monsters.dmi differ diff --git a/tgstation.dme b/tgstation.dme index ff5e9cb0231..c9c2613425c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1307,7 +1307,6 @@ #include "code\datums\components\tattoo.dm" #include "code\datums\components\technointrovert.dm" #include "code\datums\components\technoshy.dm" -#include "code\datums\components\telegraph_ability.dm" #include "code\datums\components\temporary_body.dm" #include "code\datums\components\temporary_description.dm" #include "code\datums\components\temporary_glass_shatter.dm"