mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
basic ice whelps (#77493)
## About The Pull Request i have refactored ice whelps into basic mobs. They are now the artistic sort as theyll mark their territory by seeking out icy rocks and carve out statues of theirselves using their claws to serve as a warning to players/animals that this is dragon turf and theyll also go out of their way to burn any trees in vicinity just for the hell of it. they are now gruesome cannibals if they find a corpse of one of their kin near them theyll go eat it for nurishment. AS for combat, they have a new ability which allows them to release fire in all directions however theyll only use this ability once their enraged meter is full. to make it fair ive given them a new component which allows them to telegraph abilities and only do them after a delay so players can react in time for it. ## Why It's Good For The Game basic mob refactor ## Changelog 🆑 refactor: ice whelps have been refactored to basic mobs add: ice whelps have a new dangerous ability which theyll use once their enraged meter is full /🆑
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
/mob/living/basic/mining/ice_whelp
|
||||
name = "ice whelp"
|
||||
desc = "The offspring of an ice drake, weak in comparison but still terrifying."
|
||||
icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
|
||||
icon_state = "ice_whelp"
|
||||
icon_living = "ice_whelp"
|
||||
icon_dead = "ice_whelp_dead"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
butcher_results = list(
|
||||
/obj/item/stack/ore/diamond = 3,
|
||||
/obj/item/stack/sheet/animalhide/ashdrake = 1,
|
||||
/obj/item/stack/sheet/bone = 10,
|
||||
/obj/item/stack/sheet/sinew = 2,
|
||||
)
|
||||
crusher_loot = /obj/item/crusher_trophy/tail_spike
|
||||
speed = 12
|
||||
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
obj_damage = 40
|
||||
armour_penetration = 20
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
|
||||
attack_verb_continuous = "chomps"
|
||||
attack_verb_simple = "chomp"
|
||||
death_message = "collapses on its side."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
|
||||
attack_sound = 'sound/magic/demon_attack1.ogg'
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
|
||||
ai_controller = /datum/ai_controller/basic_controller/ice_whelp
|
||||
///how much we will heal when cannibalizing a target
|
||||
var/heal_on_cannibalize = 5
|
||||
|
||||
/mob/living/basic/mining/ice_whelp/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NO_GLIDE, INNATE_TRAIT)
|
||||
AddElement(/datum/element/footstep, FOOTSTEP_MOB_HEAVY)
|
||||
AddComponent(/datum/component/basic_mob_ability_telegraph)
|
||||
AddComponent(/datum/component/basic_mob_attack_telegraph, telegraph_duration = 0.6 SECONDS)
|
||||
var/datum/action/cooldown/mob_cooldown/ice_breath/flamethrower = new(src)
|
||||
var/datum/action/cooldown/mob_cooldown/ice_breathe_all_directions/wide_flames = new(src)
|
||||
flamethrower.Grant(src)
|
||||
wide_flames.Grant(src)
|
||||
ai_controller.set_blackboard_key(BB_WHELP_WIDESPREAD_FIRE, wide_flames)
|
||||
ai_controller.set_blackboard_key(BB_WHELP_STRAIGHTLINE_FIRE, flamethrower)
|
||||
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
|
||||
|
||||
|
||||
/mob/living/basic/mining/ice_whelp/proc/pre_attack(mob/living/sculptor, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(istype(target, /obj/structure/flora/rock/icy))
|
||||
INVOKE_ASYNC(src, PROC_REF(create_sculpture), target)
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
if(!istype(target, src.type))
|
||||
return
|
||||
|
||||
var/mob/living/victim = target
|
||||
if(victim.stat != DEAD)
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(cannibalize_victim), victim)
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
/mob/living/basic/mining/ice_whelp/proc/create_sculpture(atom/target)
|
||||
balloon_alert(src, "sculpting...")
|
||||
if(!do_after(src, 5 SECONDS, target = target))
|
||||
return
|
||||
var/obj/structure/statue/custom/dragon_statue = new(get_turf(target))
|
||||
dragon_statue.set_visuals(src)
|
||||
dragon_statue.name = "statue of [src]"
|
||||
dragon_statue.desc = "Let this serve as a warning."
|
||||
dragon_statue.set_anchored(TRUE)
|
||||
qdel(target)
|
||||
|
||||
/mob/living/basic/mining/ice_whelp/proc/cannibalize_victim(mob/living/target)
|
||||
balloon_alert(src, "devouring...")
|
||||
if(!do_after(src, 5 SECONDS, target))
|
||||
return
|
||||
target.gib()
|
||||
adjustBruteLoss(-1 * heal_on_cannibalize)
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/action/cooldown/mob_cooldown/ice_breath
|
||||
name = "Ice Breath"
|
||||
desc = "Fire a cold line of fire towards the enemy!"
|
||||
button_icon = 'icons/effects/magic.dmi'
|
||||
button_icon_state = "fireball"
|
||||
cooldown_time = 3 SECONDS
|
||||
melee_cooldown_time = 0 SECONDS
|
||||
click_to_activate = TRUE
|
||||
///the range of fire
|
||||
var/fire_range = 4
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/ice_breath/Activate(atom/target_atom)
|
||||
var/turf/target_fire_turf = get_ranged_target_turf_direct(owner, target_atom, fire_range)
|
||||
var/list/burn_turfs = get_line(owner, target_fire_turf) - get_turf(owner)
|
||||
dragon_fire_line(owner, burn_turfs, frozen = TRUE)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/ice_breathe_all_directions
|
||||
name = "Fire all directions"
|
||||
desc = "Unleash lines of cold fire in all directions"
|
||||
button_icon = 'icons/effects/fire.dmi'
|
||||
button_icon_state = "1"
|
||||
cooldown_time = 4 SECONDS
|
||||
melee_cooldown_time = 0 SECONDS
|
||||
click_to_activate = FALSE
|
||||
///the range of fire
|
||||
var/fire_range = 6
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/ice_breathe_all_directions/Activate(atom/target_atom)
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/turf/target_fire_turf = get_ranged_target_turf(owner, direction, fire_range)
|
||||
var/list/burn_turfs = get_line(owner, target_fire_turf) - get_turf(owner)
|
||||
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(dragon_fire_line), owner, burn_turfs, frozen = TRUE)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
@@ -0,0 +1,182 @@
|
||||
#define ENRAGE_ADDITION 25
|
||||
/datum/ai_controller/basic_controller/ice_whelp
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/goliath,
|
||||
BB_WHELP_ENRAGED = 0,
|
||||
)
|
||||
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk
|
||||
planning_subtrees = list(
|
||||
/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/sculpt_statues,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/cannibalize,
|
||||
/datum/ai_planning_subtree/burn_trees,
|
||||
)
|
||||
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/cannibalize
|
||||
target_key = BB_TARGET_CANNIBAL
|
||||
hunting_behavior = /datum/ai_behavior/cannibalize
|
||||
finding_behavior = /datum/ai_behavior/find_hunt_target/dragon_corpse
|
||||
hunt_targets = list(/mob/living/basic/mining/ice_whelp)
|
||||
hunt_range = 10
|
||||
|
||||
/datum/ai_behavior/find_hunt_target/dragon_corpse
|
||||
|
||||
/datum/ai_behavior/find_hunt_target/dragon_corpse/valid_dinner(mob/living/source, mob/living/dinner, radius)
|
||||
if(dinner.stat != DEAD)
|
||||
return FALSE
|
||||
if(dinner.pulledby) //someone already got him before us
|
||||
return FALSE
|
||||
|
||||
return can_see(source, dinner, radius)
|
||||
|
||||
/datum/ai_behavior/cannibalize
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
|
||||
/datum/ai_behavior/cannibalize/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/cannibalize/perform(seconds_per_tick, datum/ai_controller/controller, target_key, attack_key)
|
||||
. = ..()
|
||||
var/mob/living/basic/living_pawn = controller.pawn
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
if(target.stat != DEAD || target.pulledby) //we were too slow
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
living_pawn.start_pulling(target)
|
||||
living_pawn.melee_attack(target)
|
||||
finish_action(controller, TRUE)
|
||||
|
||||
/datum/ai_behavior/cannibalize/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
///subtree to find icy rocks and create sculptures out of them
|
||||
/datum/ai_planning_subtree/sculpt_statues
|
||||
|
||||
/datum/ai_planning_subtree/sculpt_statues/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/obj/target = controller.blackboard[BB_TARGET_ROCK]
|
||||
|
||||
if(QDELETED(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_TARGET_ROCK, /obj/structure/flora/rock/icy)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/sculpt_statue, BB_TARGET_ROCK)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_behavior/sculpt_statue
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
action_cooldown = 5 MINUTES
|
||||
|
||||
/datum/ai_behavior/sculpt_statue/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/obj/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/sculpt_statue/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
var/mob/living/basic/living_pawn = controller.pawn
|
||||
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
|
||||
living_pawn.melee_attack(target)
|
||||
finish_action(controller, TRUE, target_key)
|
||||
|
||||
/datum/ai_behavior/sculpt_statue/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
|
||||
//subtree to use our attacks on the victim
|
||||
/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_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]
|
||||
|
||||
if(prob(enraged_value))
|
||||
controller.set_blackboard_key(enraged_key, 0)
|
||||
return controller.blackboard[secondary_ability_key]
|
||||
|
||||
controller.set_blackboard_key(enraged_key, enraged_value + ENRAGE_ADDITION)
|
||||
return controller.blackboard[ability_key]
|
||||
|
||||
///subtree to look for trees and burn them with our flamethrower
|
||||
/datum/ai_planning_subtree/burn_trees
|
||||
|
||||
/datum/ai_planning_subtree/burn_trees/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[BB_WHELP_STRAIGHTLINE_FIRE]
|
||||
if (!using_action.IsAvailable())
|
||||
return
|
||||
|
||||
var/obj/structure/target = controller.blackboard[BB_TARGET_TREE]
|
||||
if(QDELETED(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/set_target_tree, BB_TARGET_TREE)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_clear_target/burn_trees, BB_WHELP_STRAIGHTLINE_FIRE, BB_TARGET_TREE)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_behavior/set_target_tree
|
||||
|
||||
/datum/ai_behavior/set_target_tree/perform(seconds_per_tick, datum/ai_controller/controller, tree_key)
|
||||
. = ..()
|
||||
|
||||
var/mob/living_pawn = controller.pawn
|
||||
var/list/possible_trees = list()
|
||||
|
||||
for(var/obj/structure/flora/tree/possible_tree in oview(9, living_pawn))
|
||||
if(istype(possible_tree, /obj/structure/flora/tree/stump)) //no leaves to burn
|
||||
continue
|
||||
possible_trees += possible_tree
|
||||
|
||||
if(!length(possible_trees))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
controller.set_blackboard_key(tree_key, pick(possible_trees))
|
||||
finish_action(controller, TRUE)
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/and_clear_target/burn_trees
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
required_distance = 2
|
||||
action_cooldown = 2 MINUTES
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/and_clear_target/burn_trees/setup(datum/ai_controller/controller, ability_key, target_key)
|
||||
. = ..()
|
||||
var/obj/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
#undef ENRAGE_ADDITION
|
||||
Reference in New Issue
Block a user