mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
[MIRROR] ice demon basic mobs [MDB IGNORE] (#24188)
* ice demon basic mobs * Modular updates * Modular updates --------- Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
This commit is contained in:
co-authored by
Ben10Omintrix
Giz
parent
afa41aae57
commit
ade3fb2813
@@ -147,6 +147,22 @@
|
||||
/// key holds the tray we will beam
|
||||
#define BB_BEAMABLE_HYDROPLANT_TARGET "beamable_hydroplant_target"
|
||||
|
||||
//ice demons
|
||||
///the list of items we are afraid of
|
||||
#define BB_LIST_SCARY_ITEMS "list_scary_items"
|
||||
///our teleportation ability
|
||||
#define BB_DEMON_TELEPORT_ABILITY "demon_teleport_ability"
|
||||
///the destination of our teleport ability
|
||||
#define BB_TELEPORT_DESTINATION "teleport_destination"
|
||||
///the ability to clone ourself
|
||||
#define BB_DEMON_CLONE_ABILITY "demon_clone_ability"
|
||||
///our slippery ice ability
|
||||
#define BB_DEMON_SLIP_ABILITY "demon_slip_ability"
|
||||
///the turf we are escaping too
|
||||
#define BB_ESCAPE_DESTINATION "escape_destination"
|
||||
///how far away we will be from our target before teleporting
|
||||
#define BB_MINIMUM_DISTANCE_RANGE "minimum_distance_range"
|
||||
|
||||
/// Corpse we have consumed
|
||||
#define BB_LEGION_CORPSE "legion_corpse"
|
||||
/// Things our target recently said
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
var/maximum_distance = 6
|
||||
/// How far do we look for our target?
|
||||
var/view_distance = 10
|
||||
/// the run away behavior we will use
|
||||
var/run_away_behavior = /datum/ai_behavior/step_away
|
||||
|
||||
/datum/ai_planning_subtree/maintain_distance/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
@@ -16,12 +18,15 @@
|
||||
return // Don't run away from cucumbers, they're not snakes
|
||||
var/range = get_dist(controller.pawn, target)
|
||||
if (range < minimum_distance)
|
||||
controller.queue_behavior(/datum/ai_behavior/step_away, target_key)
|
||||
controller.queue_behavior(run_away_behavior, target_key, minimum_distance)
|
||||
return
|
||||
if (range > maximum_distance)
|
||||
controller.queue_behavior(/datum/ai_behavior/pursue_to_range, target_key, maximum_distance)
|
||||
return
|
||||
|
||||
/datum/ai_planning_subtree/maintain_distance/cover_minimum_distance
|
||||
run_away_behavior = /datum/ai_behavior/cover_minimum_distance
|
||||
|
||||
/// Take one step away
|
||||
/datum/ai_behavior/step_away
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
@@ -80,3 +85,32 @@
|
||||
if (!QDELETED(current_target) && get_dist(controller.pawn, current_target) > range)
|
||||
return
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
///instead of taking a single step, we cover the entire distance
|
||||
/datum/ai_behavior/cover_minimum_distance
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
required_distance = 0
|
||||
action_cooldown = 0.2 SECONDS
|
||||
|
||||
/datum/ai_behavior/cover_minimum_distance/setup(datum/ai_controller/controller, target_key, minimum_distance)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
var/required_distance = minimum_distance - get_dist(controller.pawn, target) //the distance we need to move
|
||||
var/distance = 0
|
||||
var/turf/chosen_turf
|
||||
for(var/turf/open/potential_turf in oview(required_distance, controller.pawn))
|
||||
var/new_distance_from_target = get_dist(potential_turf, target)
|
||||
if(potential_turf.is_blocked_turf())
|
||||
continue
|
||||
if(new_distance_from_target > distance)
|
||||
chosen_turf = potential_turf
|
||||
distance = new_distance_from_target
|
||||
if(isnull(chosen_turf))
|
||||
return FALSE
|
||||
set_movement_target(controller, target = chosen_turf)
|
||||
|
||||
/datum/ai_behavior/cover_minimum_distance/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
@@ -4,28 +4,28 @@
|
||||
/// Blackboard key holding target atom
|
||||
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
|
||||
/// What AI behaviour do we actually run?
|
||||
var/datum/ai_behavior/ranged_skirmish/attack_behavior = /datum/ai_behavior/ranged_skirmish
|
||||
|
||||
/datum/ai_planning_subtree/ranged_skirmish/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
if(!controller.blackboard_key_exists(target_key))
|
||||
return
|
||||
controller.queue_behavior(attack_behavior, target_key, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
|
||||
/// How often will we try to perform our ranged attack?
|
||||
/datum/ai_behavior/ranged_skirmish
|
||||
action_cooldown = 1 SECONDS
|
||||
var/attack_behavior = /datum/ai_behavior/ranged_skirmish
|
||||
/// If target is further away than this we don't fire
|
||||
var/max_range = 9
|
||||
/// If target is closer than this we don't fire
|
||||
var/min_range = 2
|
||||
|
||||
/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
/datum/ai_planning_subtree/ranged_skirmish/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
if(!controller.blackboard_key_exists(target_key))
|
||||
return
|
||||
controller.queue_behavior(attack_behavior, target_key, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION, max_range, min_range)
|
||||
|
||||
/// How often will we try to perform our ranged attack?
|
||||
/datum/ai_behavior/ranged_skirmish
|
||||
action_cooldown = 1 SECONDS
|
||||
|
||||
/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, max_range, min_range)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
return !QDELETED(target)
|
||||
|
||||
/datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
/datum/ai_behavior/ranged_skirmish/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key, max_range, min_range)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target))
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
///behavior to activate ability to escape from target
|
||||
/datum/ai_planning_subtree/teleport_away_from_target
|
||||
///minimum distance away from the target before we execute behavior
|
||||
var/minimum_distance = 2
|
||||
///the ability we will execute
|
||||
var/ability_key
|
||||
|
||||
/datum/ai_planning_subtree/teleport_away_from_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
|
||||
return
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
var/distance_from_target = get_dist(target, controller.pawn)
|
||||
if(distance_from_target >= minimum_distance)
|
||||
controller.clear_blackboard_key(BB_ESCAPE_DESTINATION)
|
||||
return
|
||||
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
||||
if(!ability?.IsAvailable())
|
||||
return
|
||||
var/turf/location_turf = controller.blackboard[BB_ESCAPE_DESTINATION]
|
||||
|
||||
if(isnull(location_turf))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_furthest_turf_from_target, BB_BASIC_MOB_CURRENT_TARGET, BB_ESCAPE_DESTINATION, minimum_distance)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
if(get_dist(location_turf, target) < minimum_distance || !can_see(controller.pawn, location_turf)) //target moved close too close or we moved too far since finding the target turf
|
||||
controller.clear_blackboard_key(BB_ESCAPE_DESTINATION)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_clear_target, ability_key, BB_ESCAPE_DESTINATION)
|
||||
|
||||
///find furtherst turf target so we may teleport to it
|
||||
/datum/ai_behavior/find_furthest_turf_from_target
|
||||
|
||||
/datum/ai_behavior/find_furthest_turf_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, set_key, range)
|
||||
var/mob/living/living_target = controller.blackboard[target_key]
|
||||
if(QDELETED(living_target))
|
||||
return
|
||||
|
||||
var/distance = 0
|
||||
var/turf/chosen_turf
|
||||
for(var/turf/open/potential_destination in oview(range, living_target))
|
||||
if(potential_destination.is_blocked_turf())
|
||||
continue
|
||||
var/new_distance_to_target = get_dist(potential_destination, living_target)
|
||||
if(new_distance_to_target > distance)
|
||||
chosen_turf = potential_destination
|
||||
distance = new_distance_to_target
|
||||
if(distance == range)
|
||||
break //we have already found the max distance
|
||||
|
||||
if(isnull(chosen_turf))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
controller.set_blackboard_key(set_key, chosen_turf)
|
||||
finish_action(controller, TRUE)
|
||||
@@ -94,8 +94,6 @@
|
||||
var/atom/hunted = controller.blackboard[hunting_target_key]
|
||||
|
||||
if(QDELETED(hunted))
|
||||
//Target is gone for some reason. forget about this task!
|
||||
controller[hunting_target_key] = null
|
||||
finish_action(controller, FALSE, hunting_target_key)
|
||||
else
|
||||
target_caught(hunter, hunted)
|
||||
@@ -136,7 +134,7 @@
|
||||
|
||||
/datum/ai_behavior/hunt_target/use_ability_on_target/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key)
|
||||
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
||||
if(QDELETED(ability) || !ability.IsAvailable())
|
||||
if(!ability?.IsAvailable())
|
||||
finish_action(controller, FALSE, hunting_target_key)
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* A component given to mobs to damage a linked mob
|
||||
*/
|
||||
/datum/component/joint_damage
|
||||
///the mob we will damage
|
||||
var/datum/weakref/overlord_mob
|
||||
///our last health count
|
||||
var/previous_health_count
|
||||
|
||||
/datum/component/joint_damage/Initialize(mob/overlord_mob)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/mob/living/parent_mob = parent
|
||||
previous_health_count = parent_mob.health
|
||||
if(overlord_mob)
|
||||
src.overlord_mob = WEAKREF(overlord_mob)
|
||||
|
||||
/datum/component/joint_damage/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(damage_overlord))
|
||||
RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(damage_overlord))
|
||||
|
||||
/datum/component/joint_damage/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_LIVING_HEALTH_UPDATE, COMSIG_LIVING_DEATH))
|
||||
|
||||
/datum/component/joint_damage/Destroy()
|
||||
overlord_mob = null
|
||||
return ..()
|
||||
|
||||
/datum/component/joint_damage/proc/damage_overlord(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/overlord_to_damage = overlord_mob?.resolve()
|
||||
if(!isnull(overlord_to_damage))
|
||||
overlord_to_damage.adjustBruteLoss(previous_health_count - source.health) ///damage or heal overlord
|
||||
previous_health_count = source.health
|
||||
@@ -62,12 +62,12 @@
|
||||
weighted_closed_turf_types = list(/turf/closed/mineral/random/snow/underground = 1)
|
||||
weighted_mob_spawn_list = list(
|
||||
SPAWN_MEGAFAUNA = 1,
|
||||
/mob/living/basic/mining/ice_demon = 100,
|
||||
/mob/living/basic/mining/ice_whelp = 60,
|
||||
/mob/living/basic/mining/legion/snow = 100,
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon = 100,
|
||||
/obj/structure/spawner/ice_moon/demonic_portal = 6,
|
||||
/obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 6,
|
||||
/obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 6,
|
||||
/obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 6,
|
||||
)
|
||||
weighted_megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/colossus = 1)
|
||||
weighted_flora_spawn_list = list(
|
||||
|
||||
@@ -80,7 +80,7 @@ GLOBAL_LIST_INIT(ore_probability, list(
|
||||
name = "demonic portal"
|
||||
desc = "A portal that goes to another world, normal creatures couldn't survive there."
|
||||
icon_state = "nether"
|
||||
mob_types = list(/mob/living/simple_animal/hostile/asteroid/ice_demon)
|
||||
mob_types = list(/mob/living/basic/mining/ice_demon)
|
||||
light_range = 1
|
||||
light_color = COLOR_SOFT_RED
|
||||
mob_gps_id = "WT|B" // watcher | bluespace
|
||||
|
||||
@@ -437,3 +437,36 @@
|
||||
chaser.monster_damage_boost = FALSE // Weaker cuz no cooldown
|
||||
chaser.damage = 20
|
||||
log_combat(user, target, "fired a chaser at", src)
|
||||
|
||||
/obj/item/crusher_trophy/ice_demon_cube
|
||||
name = "demonic cube"
|
||||
desc = "A stone cold cube dropped from an ice demon."
|
||||
icon_state = "ice_demon_cube"
|
||||
denied_type = /obj/item/crusher_trophy/ice_demon_cube
|
||||
///how many will we summon?
|
||||
var/summon_amount = 2
|
||||
///cooldown to summon demons upon the target
|
||||
COOLDOWN_DECLARE(summon_cooldown)
|
||||
|
||||
/obj/item/crusher_trophy/ice_demon_cube/effect_desc()
|
||||
return "mark detonation to unleash demonic ice clones upon the target"
|
||||
|
||||
/obj/item/crusher_trophy/ice_demon_cube/on_mark_detonation(mob/living/target, mob/living/user)
|
||||
if(isnull(target) || !COOLDOWN_FINISHED(src, summon_cooldown))
|
||||
return
|
||||
for(var/i in 1 to summon_amount)
|
||||
var/turf/drop_off = find_dropoff_turf(target, user)
|
||||
var/mob/living/basic/mining/demon_afterimage/crusher/friend = new(drop_off)
|
||||
friend.faction = list(FACTION_NEUTRAL)
|
||||
friend.befriend(user)
|
||||
friend.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, target)
|
||||
COOLDOWN_START(src, summon_cooldown, 30 SECONDS)
|
||||
|
||||
///try to make them spawn all around the target to surround him
|
||||
/obj/item/crusher_trophy/ice_demon_cube/proc/find_dropoff_turf(mob/living/target, mob/living/user)
|
||||
var/list/turfs_list = get_adjacent_open_turfs(target)
|
||||
for(var/turf/possible_turf in turfs_list)
|
||||
if(possible_turf.is_blocked_turf())
|
||||
continue
|
||||
return possible_turf
|
||||
return get_turf(user)
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/mob/living/basic/mining/ice_demon
|
||||
name = "demonic watcher"
|
||||
desc = "A creature formed entirely out of ice, bluespace energy emanates from inside of it."
|
||||
icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
|
||||
icon_state = "ice_demon"
|
||||
icon_living = "ice_demon"
|
||||
icon_gib = "syndicate_gib"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
speed = 2
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
attack_verb_continuous = "slices"
|
||||
attack_verb_simple = "slice"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
crusher_loot = /obj/item/crusher_trophy/ice_demon_cube
|
||||
ai_controller = /datum/ai_controller/basic_controller/ice_demon
|
||||
death_message = "fades as the energies that tied it to this world dissipate."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
|
||||
/mob/living/basic/mining/ice_demon/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/action/cooldown/mob_cooldown/slippery_ice_floors/ice_floor = new(src)
|
||||
ice_floor.Grant(src)
|
||||
ai_controller.set_blackboard_key(BB_DEMON_SLIP_ABILITY, ice_floor)
|
||||
var/datum/action/cooldown/mob_cooldown/ice_demon_teleport/demon_teleport = new(src)
|
||||
demon_teleport.Grant(src)
|
||||
ai_controller.set_blackboard_key(BB_DEMON_TELEPORT_ABILITY, demon_teleport)
|
||||
var/datum/action/cooldown/spell/conjure/create_afterimages/afterimage = new(src)
|
||||
afterimage.Grant(src)
|
||||
ai_controller.set_blackboard_key(BB_DEMON_CLONE_ABILITY, afterimage)
|
||||
AddComponent(\
|
||||
/datum/component/ranged_attacks,\
|
||||
projectile_type = /obj/projectile/temp/ice_demon,\
|
||||
projectile_sound = 'sound/weapons/pierce.ogg',\
|
||||
)
|
||||
var/static/list/death_loot = list(/obj/item/stack/ore/bluespace_crystal = 3)
|
||||
AddElement(/datum/element/death_drops, death_loot)
|
||||
AddElement(/datum/element/simple_flying)
|
||||
|
||||
/mob/living/basic/mining/ice_demon/death(gibbed)
|
||||
if(prob(5))
|
||||
new /obj/item/raw_anomaly_core/bluespace(loc)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mining/demon_afterimage
|
||||
name = "afterimage demonic watcher"
|
||||
desc = "Is this some sort of illusion?"
|
||||
icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
|
||||
icon_state = "ice_demon"
|
||||
icon_living = "ice_demon"
|
||||
icon_gib = "syndicate_gib"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
basic_mob_flags = DEL_ON_DEATH
|
||||
speed = 5
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
attack_verb_continuous = "slices"
|
||||
attack_verb_simple = "slice"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
alpha = 80
|
||||
ai_controller = /datum/ai_controller/basic_controller/ice_demon/afterimage
|
||||
///how long do we exist for
|
||||
var/existence_period = 15 SECONDS
|
||||
|
||||
/mob/living/basic/mining/demon_afterimage/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/simple_flying)
|
||||
AddElement(/datum/element/temporary_atom, life_time = existence_period)
|
||||
|
||||
///afterimage subtypes summoned by the crusher
|
||||
/mob/living/basic/mining/demon_afterimage/crusher
|
||||
speed = 2
|
||||
health = 60
|
||||
maxHealth = 60
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
existence_period = 7 SECONDS
|
||||
@@ -0,0 +1,117 @@
|
||||
/obj/projectile/temp/ice_demon
|
||||
name = "ice blast"
|
||||
icon_state = "ice_2"
|
||||
damage = 5
|
||||
damage_type = BURN
|
||||
armor_flag = ENERGY
|
||||
speed = 1
|
||||
pixel_speed_multiplier = 0.25
|
||||
temperature = -75
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/ice_demon_teleport
|
||||
name = "Bluespace Teleport"
|
||||
desc = "Teleport towards a destination target!"
|
||||
button_icon = 'icons/obj/ore.dmi'
|
||||
button_icon_state = "bluespace_crystal"
|
||||
cooldown_time = 3 SECONDS
|
||||
melee_cooldown_time = 0 SECONDS
|
||||
///time delay before teleport
|
||||
var/time_delay = 0.5 SECONDS
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/ice_demon_teleport/Activate(atom/target_atom)
|
||||
if(isclosedturf(get_turf(target_atom)))
|
||||
owner.balloon_alert(owner, "blocked!")
|
||||
return FALSE
|
||||
animate(owner, transform = matrix().Scale(0.8), time = time_delay, easing = SINE_EASING)
|
||||
addtimer(CALLBACK(src, PROC_REF(teleport_to_turf), target_atom), time_delay)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/ice_demon_teleport/proc/teleport_to_turf(atom/target)
|
||||
animate(owner, transform = matrix(), time = 0.5 SECONDS, easing = SINE_EASING)
|
||||
do_teleport(teleatom = owner, destination = target, channel = TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/slippery_ice_floors
|
||||
name = "Iced Floors"
|
||||
desc = "Summon slippery ice floors all around!"
|
||||
button_icon = 'icons/turf/floors/ice_turf.dmi'
|
||||
button_icon_state = "ice_turf-6"
|
||||
cooldown_time = 2 SECONDS
|
||||
click_to_activate = FALSE
|
||||
melee_cooldown_time = 0 SECONDS
|
||||
///perimeter we will spawn the iced floors on
|
||||
var/radius = 1
|
||||
///intervals we will spawn the ice floors in
|
||||
var/spread_duration = 0.2 SECONDS
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/slippery_ice_floors/Activate(atom/target_atom)
|
||||
for(var/i in 0 to radius)
|
||||
var/list/list_of_turfs = border_diamond_range_turfs(owner, i)
|
||||
addtimer(CALLBACK(src, PROC_REF(spawn_icy_floors), list_of_turfs), i * spread_duration)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/slippery_ice_floors/proc/spawn_icy_floors(list/list_of_turfs)
|
||||
if(!length(list_of_turfs))
|
||||
return
|
||||
for(var/turf/location in list_of_turfs)
|
||||
if(isnull(location))
|
||||
continue
|
||||
if(isclosedturf(location) || isspaceturf(location))
|
||||
continue
|
||||
new /obj/effect/temp_visual/slippery_ice(location)
|
||||
|
||||
/obj/effect/temp_visual/slippery_ice
|
||||
name = "slippery acid"
|
||||
icon = 'icons/turf/floors/ice_turf.dmi'
|
||||
icon_state = "ice_turf-6"
|
||||
layer = BELOW_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
anchored = TRUE
|
||||
duration = 3 SECONDS
|
||||
alpha = 100
|
||||
/// how long does it take for the effect to phase in
|
||||
var/phase_in_period = 2 SECONDS
|
||||
|
||||
/obj/effect/temp_visual/slippery_ice/Initialize(mapload)
|
||||
. = ..()
|
||||
animate(src, alpha = 160, time = phase_in_period)
|
||||
animate(alpha = 0, time = duration - phase_in_period) /// slowly fade out of existence
|
||||
addtimer(CALLBACK(src, PROC_REF(add_slippery_component), phase_in_period)) //only become slippery after we phased in
|
||||
|
||||
/obj/effect/temp_visual/slippery_ice/proc/add_slippery_component()
|
||||
AddComponent(/datum/component/slippery, 2 SECONDS)
|
||||
|
||||
/datum/action/cooldown/spell/conjure/create_afterimages
|
||||
name = "Create After Images"
|
||||
button_icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
|
||||
button_icon_state = "ice_demon"
|
||||
spell_requirements = NONE
|
||||
cooldown_time = 1 MINUTES
|
||||
summon_type = list(/mob/living/basic/mining/demon_afterimage)
|
||||
summon_radius = 1
|
||||
summon_amount = 2
|
||||
///max number of after images
|
||||
var/max_afterimages = 2
|
||||
///How many clones do we have summoned
|
||||
var/number_of_afterimages = 0
|
||||
|
||||
/datum/action/cooldown/spell/conjure/create_afterimages/can_cast_spell(feedback = TRUE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(number_of_afterimages >= max_afterimages)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/conjure/create_afterimages/post_summon(atom/summoned_object, atom/cast_on)
|
||||
var/mob/living/basic/created_copy = summoned_object
|
||||
created_copy.AddComponent(/datum/component/joint_damage, overlord_mob = owner)
|
||||
RegisterSignals(created_copy, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH), PROC_REF(delete_copy))
|
||||
number_of_afterimages++
|
||||
|
||||
/datum/action/cooldown/spell/conjure/create_afterimages/proc/delete_copy(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(source, list(COMSIG_QDELETING, COMSIG_LIVING_DEATH))
|
||||
number_of_afterimages--
|
||||
@@ -0,0 +1,118 @@
|
||||
/datum/ai_controller/basic_controller/ice_demon
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
|
||||
BB_LIST_SCARY_ITEMS = list(
|
||||
/obj/item/weldingtool,
|
||||
/obj/item/flashlight/flare,
|
||||
),
|
||||
BB_BASIC_MOB_FLEEING = TRUE,
|
||||
BB_MINIMUM_DISTANCE_RANGE = 3,
|
||||
)
|
||||
|
||||
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/flee_target/ice_demon,
|
||||
/datum/ai_planning_subtree/ranged_skirmish/ice_demon,
|
||||
/datum/ai_planning_subtree/maintain_distance/cover_minimum_distance/ice_demon,
|
||||
/datum/ai_planning_subtree/teleport_away_from_target,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/teleport_destination,
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/summon_afterimages,
|
||||
)
|
||||
|
||||
|
||||
/datum/ai_planning_subtree/maintain_distance/cover_minimum_distance/ice_demon
|
||||
maximum_distance = 7
|
||||
|
||||
/datum/ai_planning_subtree/teleport_away_from_target
|
||||
ability_key = BB_DEMON_TELEPORT_ABILITY
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/teleport_destination
|
||||
target_key = BB_TELEPORT_DESTINATION
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/use_ability_on_target/demon_teleport
|
||||
finding_behavior = /datum/ai_behavior/find_valid_teleport_location
|
||||
hunt_targets = list(/turf/open)
|
||||
hunt_range = 3
|
||||
finish_planning = FALSE
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/teleport_destination/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
|
||||
return
|
||||
if(controller.blackboard_key_exists(BB_ESCAPE_DESTINATION))
|
||||
controller.clear_blackboard_key(BB_TELEPORT_DESTINATION)
|
||||
return
|
||||
var/datum/action/cooldown/ability = controller.blackboard[BB_DEMON_TELEPORT_ABILITY]
|
||||
if(!ability?.IsAvailable())
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/ai_behavior/find_valid_teleport_location
|
||||
|
||||
/datum/ai_behavior/find_valid_teleport_location/perform(seconds_per_tick, datum/ai_controller/controller, hunting_target_key, types_to_hunt, hunt_range)
|
||||
. = ..()
|
||||
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
var/list/possible_turfs = list()
|
||||
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
for(var/turf/open/potential_turf in oview(hunt_range, target)) //we check for turfs around the target
|
||||
if(potential_turf.is_blocked_turf())
|
||||
continue
|
||||
if(!can_see(target, potential_turf, hunt_range))
|
||||
continue
|
||||
possible_turfs += potential_turf
|
||||
|
||||
if(!length(possible_turfs))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
controller.set_blackboard_key(hunting_target_key, pick(possible_turfs))
|
||||
finish_action(controller, TRUE)
|
||||
|
||||
/datum/ai_behavior/hunt_target/use_ability_on_target/demon_teleport
|
||||
hunt_cooldown = 2 SECONDS
|
||||
ability_key = BB_DEMON_TELEPORT_ABILITY
|
||||
behavior_flags = NONE
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/summon_afterimages
|
||||
ability_key = BB_DEMON_CLONE_ABILITY
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/summon_afterimages/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(living_pawn.health / living_pawn.maxHealth > 0.5) //only use this ability when under half health
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/flee_target/ice_demon
|
||||
|
||||
/datum/ai_planning_subtree/flee_target/ice_demon/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(!iscarbon(target))
|
||||
return
|
||||
var/mob/living/carbon/human_target = target
|
||||
|
||||
for(var/obj/held_item in human_target.held_items)
|
||||
if(!is_type_in_list(held_item, controller.blackboard[BB_LIST_SCARY_ITEMS]))
|
||||
continue
|
||||
if(!held_item.light_on)
|
||||
continue
|
||||
var/datum/action/cooldown/slip_ability = controller.blackboard[BB_DEMON_SLIP_ABILITY]
|
||||
if(slip_ability?.IsAvailable())
|
||||
controller.queue_behavior(/datum/ai_behavior/use_mob_ability, BB_DEMON_SLIP_ABILITY)
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/ranged_skirmish/ice_demon
|
||||
min_range = 0
|
||||
|
||||
/datum/ai_controller/basic_controller/ice_demon/afterimage
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/flee_target/ice_demon, //even the afterimages are afraid of flames!
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
||||
)
|
||||
|
||||
@@ -27,13 +27,10 @@
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/ranged_skirmish/watcher
|
||||
attack_behavior = /datum/ai_behavior/ranged_skirmish/watcher
|
||||
min_range = 0
|
||||
|
||||
/datum/ai_planning_subtree/ranged_skirmish/watcher/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if (QDELETED(target) || HAS_TRAIT(target, TRAIT_OVERWATCHED))
|
||||
return // Don't bully people who are playing red light green light
|
||||
return ..()
|
||||
|
||||
/datum/ai_behavior/ranged_skirmish/watcher
|
||||
min_range = 0
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon
|
||||
name = "demonic watcher"
|
||||
desc = "A creature formed entirely out of ice, bluespace energy emanates from inside of it."
|
||||
icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
|
||||
icon_state = "ice_demon"
|
||||
icon_living = "ice_demon"
|
||||
icon_dead = "ice_demon_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
speak_emote = list("telepathically cries")
|
||||
speed = 2
|
||||
move_to_delay = 2
|
||||
projectiletype = /obj/projectile/temp/ice_demon
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
ranged = TRUE
|
||||
ranged_message = "manifests ice"
|
||||
ranged_cooldown_time = 1.5 SECONDS
|
||||
minimum_distance = 3
|
||||
retreat_distance = 3
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
attack_verb_continuous = "slices"
|
||||
attack_verb_simple = "slice"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
vision_range = 9
|
||||
aggro_vision_range = 9
|
||||
move_force = MOVE_FORCE_VERY_STRONG
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
pull_force = MOVE_FORCE_VERY_STRONG
|
||||
del_on_death = TRUE
|
||||
loot = list()
|
||||
crusher_loot = /obj/item/crusher_trophy/demon_core /// SKYRAT EDIT CHANGE - ORIGINAL : crusher_loot = /obj/item/crusher_trophy/watcher_wing/ice_wing
|
||||
death_message = "fades as the energies that tied it to this world dissipate."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
stat_attack = HARD_CRIT
|
||||
robust_searching = TRUE
|
||||
footstep_type = FOOTSTEP_MOB_CLAW
|
||||
/// Distance the demon will teleport from the target
|
||||
var/teleport_distance = 3
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/simple_flying)
|
||||
|
||||
/obj/projectile/temp/ice_demon
|
||||
name = "ice blast"
|
||||
icon_state = "ice_2"
|
||||
damage = 5
|
||||
damage_type = BURN
|
||||
armor_flag = ENERGY
|
||||
speed = 1
|
||||
pixel_speed_multiplier = 0.25
|
||||
range = 200
|
||||
temperature = -75
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon/OpenFire()
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
// Sentient ice demons teleporting has been linked to server crashes
|
||||
if(client)
|
||||
return ..()
|
||||
if(teleport_distance <= 0)
|
||||
return ..()
|
||||
var/list/possible_ends = view(teleport_distance, target.loc) - view(teleport_distance - 1, target.loc)
|
||||
for(var/turf/closed/turf_to_remove in possible_ends)
|
||||
possible_ends -= turf_to_remove
|
||||
if(!possible_ends.len)
|
||||
return ..()
|
||||
var/turf/end = pick(possible_ends)
|
||||
do_teleport(src, end, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
|
||||
SLEEP_CHECK_DEATH(8, src)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon/death(gibbed)
|
||||
move_force = MOVE_FORCE_DEFAULT
|
||||
move_resist = MOVE_RESIST_DEFAULT
|
||||
pull_force = PULL_FORCE_DEFAULT
|
||||
new /obj/item/stack/ore/bluespace_crystal(loc, 3)
|
||||
if(prob(5))
|
||||
new /obj/item/raw_anomaly_core/bluespace(loc)
|
||||
return ..()
|
||||
@@ -64,7 +64,6 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/grublunch,
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/gubbuck,
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch/guthen,
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon,
|
||||
/mob/living/simple_animal/hostile/asteroid/polarbear,
|
||||
/mob/living/simple_animal/hostile/asteroid/polarbear/lesser,
|
||||
/mob/living/simple_animal/hostile/asteroid/wolf,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,3 @@
|
||||
// crusher loot /obj/item/crusher_trophy/ice_demon_cube -> /obj/item/crusher_trophy/demon_core
|
||||
/mob/living/basic/mining/ice_demon
|
||||
crusher_loot = /obj/item/crusher_trophy/demon_core
|
||||
@@ -198,7 +198,7 @@
|
||||
/datum/ash_ritual/summon_icemoon_creature/ritual_success(obj/effect/ash_rune/success_rune)
|
||||
. = ..()
|
||||
var/mob_type = pick(
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon,
|
||||
/mob/living/basic/mining/ice_demon,
|
||||
/mob/living/basic/mining/ice_whelp,
|
||||
/mob/living/basic/mining/lobstrosity,
|
||||
/mob/living/simple_animal/hostile/asteroid/polarbear,
|
||||
|
||||
+6
-1
@@ -922,6 +922,7 @@
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\stare_at_thing.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\target_retaliate.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\targeted_mob_ability.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\teleport_away_from_target.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\tipped_subtree.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\travel_to_point.dm"
|
||||
#include "code\datums\ai\basic_mobs\basic_subtrees\use_mob_ability.dm"
|
||||
@@ -1100,6 +1101,7 @@
|
||||
#include "code\datums\components\itembound.dm"
|
||||
#include "code\datums\components\itempicky.dm"
|
||||
#include "code\datums\components\jetpack.dm"
|
||||
#include "code\datums\components\joint_damage.dm"
|
||||
#include "code\datums\components\jousting.dm"
|
||||
#include "code\datums\components\keep_me_secure.dm"
|
||||
#include "code\datums\components\knockoff.dm"
|
||||
@@ -4465,6 +4467,9 @@
|
||||
#include "code\modules\mob\living\basic\heretic\raw_prophet.dm"
|
||||
#include "code\modules\mob\living\basic\heretic\rust_walker.dm"
|
||||
#include "code\modules\mob\living\basic\heretic\star_gazer.dm"
|
||||
#include "code\modules\mob\living\basic\icemoon\ice_demon\ice_demon.dm"
|
||||
#include "code\modules\mob\living\basic\icemoon\ice_demon\ice_demon_abilities.dm"
|
||||
#include "code\modules\mob\living\basic\icemoon\ice_demon\ice_demon_ai.dm"
|
||||
#include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp.dm"
|
||||
#include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_abilities.dm"
|
||||
#include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_ai.dm"
|
||||
@@ -4828,7 +4833,6 @@
|
||||
#include "code\modules\mob\living\simple_animal\hostile\megafauna\wendigo.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\curse_blob.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\gutlunch.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\ice_demon.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\mining_mobs.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\polarbear.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\wolf.dm"
|
||||
@@ -6149,6 +6153,7 @@
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\living.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\living_defines.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\living_movement.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\basic\icemoon\ice_demon.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\carbon\death.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\carbon\human.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\carbon\human_helpers.dm"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/mob/living/simple_animal/hostile/asteroid/ice_demon : /mob/living/basic/mining/ice_demon{@OLD}
|
||||
Reference in New Issue
Block a user