mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
[MIRROR] Basic Mob Brimdemon [MDB IGNORE] (#23863)
* Basic Mob Brimdemon (#78424) ## About The Pull Request Fixes #71330 The brimdemon was basically already perfect (well, it has a novel means of attacking) so I didn't get too fancy with this one, it's _largely_ just a straightforward conversion. Following this change it's a little slower to back off, but better at lining up with people in order to blast them. Additionally, its beam is now a mob ability so you can give it to other mobs if you so desire. Because I can't help doing a _little_ tinkering, Brimdemons now explode 2.5 seconds after they die, after a brief warning animation. ## Why It's Good For The Game Simple mobs must die ## Changelog 🆑 add: Brimdemon corpses release an explosion shortly after death, just to keep you on your toes. refactor: Brimdemons now use the basic mob framework which (should) improve their pathfinding somewhat. Please bug report any unusual behaviour. admin: The brimdemon's beam ability can be given to any mob, for your Binding of Isaac event /🆑 * Basic Mob Brimdemon * Modular --------- Co-authored-by: Jacquerel <hnevard@gmail.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
This commit is contained in:
co-authored by
Jacquerel
Giz
parent
5c1490bf7e
commit
7509292edd
@@ -43,12 +43,12 @@
|
||||
|
||||
unset_click_ability(source, refund_cooldown = TRUE)
|
||||
|
||||
/datum/action/cooldown/spell/pointed/projectile/furious_steel/InterceptClickOn(mob/living/caller, params, atom/click_target)
|
||||
/datum/action/cooldown/spell/pointed/projectile/furious_steel/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
// Let the caster prioritize using items like guns over blade casts
|
||||
if(caller.get_active_held_item())
|
||||
return FALSE
|
||||
// Let the caster prioritize melee attacks like punches and shoves over blade casts
|
||||
if(get_dist(caller, click_target) <= 1)
|
||||
if(get_dist(caller, target) <= 1)
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -69,14 +69,10 @@
|
||||
/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
|
||||
if(controller.blackboard_key_exists(BB_TARGET_ROCK))
|
||||
controller.queue_behavior(/datum/ai_behavior/sculpt_statue, BB_TARGET_ROCK)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_TARGET_ROCK, /obj/structure/flora/rock/icy)
|
||||
|
||||
/datum/ai_behavior/sculpt_statue
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
@@ -135,16 +131,13 @@
|
||||
|
||||
/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())
|
||||
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
|
||||
if(controller.blackboard_key_exists(BB_TARGET_TREE))
|
||||
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
|
||||
controller.queue_behavior(/datum/ai_behavior/set_target_tree, BB_TARGET_TREE)
|
||||
|
||||
/datum/ai_behavior/set_target_tree
|
||||
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
/datum/ai_planning_subtree/bileworm_attack
|
||||
|
||||
/datum/ai_planning_subtree/bileworm_attack/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
|
||||
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(QDELETED(target))
|
||||
if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
|
||||
return
|
||||
|
||||
var/datum/action/cooldown/mob_cooldown/resurface = controller.blackboard[BB_BILEWORM_RESURFACE]
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/// Fires a bloody beam. Brimdemon Blast!
|
||||
/datum/action/cooldown/mob_cooldown/brimbeam
|
||||
name = "brimstone blast"
|
||||
desc = "Unleash a barrage of infernal energies in the targeted direction."
|
||||
button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
button_icon_state = "brimdemon_firing"
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
click_to_activate = TRUE
|
||||
cooldown_time = 5 SECONDS
|
||||
melee_cooldown_time = 0
|
||||
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED
|
||||
/// How far does our beam go?
|
||||
var/beam_range = 10
|
||||
/// How long does our beam last?
|
||||
var/beam_duration = 2 SECONDS
|
||||
/// How long do we wind up before firing?
|
||||
var/charge_duration = 1 SECONDS
|
||||
/// Overlay we show when we're about to fire
|
||||
var/static/image/direction_overlay = image('icons/mob/simple/lavaland/lavaland_monsters.dmi', "brimdemon_telegraph_dir")
|
||||
/// A list of all the beam parts.
|
||||
var/list/beam_parts = list()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/brimbeam/Destroy()
|
||||
extinguish_laser()
|
||||
return ..()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/brimbeam/Activate(atom/target)
|
||||
StartCooldown(360 SECONDS)
|
||||
|
||||
owner.face_atom(target)
|
||||
owner.move_resist = MOVE_FORCE_VERY_STRONG
|
||||
owner.add_overlay(direction_overlay)
|
||||
owner.balloon_alert_to_viewers("charging...")
|
||||
|
||||
var/fully_charged = do_after(owner, delay = charge_duration, target = owner)
|
||||
owner.cut_overlay(direction_overlay)
|
||||
if (!fully_charged)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
if (!fire_laser())
|
||||
var/static/list/fail_emotes = list("coughs.", "wheezes.", "belches out a puff of black smoke.")
|
||||
owner.manual_emote(pick(fail_emotes))
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
do_after(owner, delay = beam_duration, target = owner)
|
||||
extinguish_laser()
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
/// Create a laser in the direction we are facing
|
||||
/datum/action/cooldown/mob_cooldown/brimbeam/proc/fire_laser()
|
||||
owner.visible_message(span_danger("[owner] fires a brimbeam!"))
|
||||
playsound(owner, 'sound/creatures/brimdemon.ogg', 150, FALSE, 0, 3)
|
||||
var/turf/target_turf = get_ranged_target_turf(owner, owner.dir, beam_range)
|
||||
var/turf/origin_turf = get_turf(owner)
|
||||
var/list/affected_turfs = get_line(origin_turf, target_turf) - origin_turf
|
||||
for(var/turf/affected_turf in affected_turfs)
|
||||
if(affected_turf.opacity)
|
||||
break
|
||||
var/blocked = FALSE
|
||||
for(var/obj/potential_block in affected_turf.contents)
|
||||
if(potential_block.opacity)
|
||||
blocked = TRUE
|
||||
break
|
||||
if(blocked)
|
||||
break
|
||||
var/atom/new_brimbeam = new /obj/effect/brimbeam(affected_turf)
|
||||
new_brimbeam.dir = owner.dir
|
||||
beam_parts += new_brimbeam
|
||||
for(var/mob/living/hit_mob in affected_turf.contents)
|
||||
hit_mob.apply_damage(damage = 25, damagetype = BURN)
|
||||
to_chat(hit_mob, span_userdanger("You're blasted by [owner]'s brimbeam!"))
|
||||
RegisterSignal(new_brimbeam, COMSIG_QDELETING, PROC_REF(extinguish_laser)) // In case idk a singularity eats it or something
|
||||
if(!length(beam_parts))
|
||||
return FALSE
|
||||
var/atom/last_brimbeam = beam_parts[length(beam_parts)]
|
||||
last_brimbeam.icon_state = "brimbeam_end"
|
||||
var/atom/first_brimbeam = beam_parts[1]
|
||||
first_brimbeam.icon_state = "brimbeam_start"
|
||||
return TRUE
|
||||
|
||||
/// Get rid of our laser when we are done with it
|
||||
/datum/action/cooldown/mob_cooldown/brimbeam/proc/extinguish_laser()
|
||||
if(!length(beam_parts))
|
||||
return FALSE
|
||||
owner.move_resist = initial(owner.move_resist)
|
||||
for(var/obj/effect/brimbeam/beam in beam_parts)
|
||||
beam.disperse()
|
||||
beam_parts = list()
|
||||
|
||||
/// Segments of the actual beam, these hurt if you stand in them
|
||||
/obj/effect/brimbeam
|
||||
name = "brimbeam"
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "brimbeam_mid"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = ABOVE_GAME_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
light_color = LIGHT_COLOR_BLOOD_MAGIC
|
||||
light_power = 3
|
||||
light_range = 2
|
||||
|
||||
/obj/effect/brimbeam/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/effect/brimbeam/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/brimbeam/process()
|
||||
for(var/mob/living/hit_mob in get_turf(src))
|
||||
damage(hit_mob)
|
||||
|
||||
/// Hurt the passed mob
|
||||
/obj/effect/brimbeam/proc/damage(mob/living/hit_mob)
|
||||
hit_mob.apply_damage(damage = 5, damagetype = BURN)
|
||||
to_chat(hit_mob, span_danger("You're damaged by [src]!"))
|
||||
|
||||
/// Disappear
|
||||
/obj/effect/brimbeam/proc/disperse()
|
||||
animate(src, time = 0.5 SECONDS, alpha = 0)
|
||||
QDEL_IN(src, 0.5 SECONDS)
|
||||
@@ -0,0 +1,87 @@
|
||||
/// Lavaland mob which tries to line up with its target and fire a laser
|
||||
/mob/living/basic/mining/brimdemon
|
||||
name = "brimdemon"
|
||||
desc = "A volatile creature resembling an enormous horned skull. Its response to almost any stimulus is to unleash a beam of infernal energy."
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "brimdemon"
|
||||
icon_living = "brimdemon"
|
||||
icon_dead = "brimdemon_dead"
|
||||
speed = 3
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
friendly_verb_continuous = "scratches at"
|
||||
friendly_verb_simple = "scratch at"
|
||||
speak_emote = list("cackles")
|
||||
melee_damage_lower = 7.5
|
||||
melee_damage_upper = 7.5
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
melee_attack_cooldown = 0.6 SECONDS
|
||||
attack_vis_effect = ATTACK_EFFECT_BITE
|
||||
attack_verb_continuous = "bites"
|
||||
attack_verb_simple = "bite"
|
||||
death_message = "wails as infernal energy escapes from its wounds, leaving it an empty husk."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
light_color = LIGHT_COLOR_BLOOD_MAGIC
|
||||
light_power = 5
|
||||
light_range = 1.4
|
||||
|
||||
ai_controller = /datum/ai_controller/basic_controller/brimdemon
|
||||
|
||||
crusher_loot = /obj/item/crusher_trophy/brimdemon_fang
|
||||
butcher_results = list(
|
||||
/obj/item/food/meat/slab = 2,
|
||||
/obj/effect/decal/cleanable/brimdust = 1,
|
||||
/obj/item/organ/internal/monster_core/brimdust_sac = 1,
|
||||
)
|
||||
/// How we get blasting
|
||||
var/datum/action/cooldown/mob_cooldown/brimbeam/beam
|
||||
|
||||
/mob/living/basic/mining/brimdemon/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
|
||||
beam = new(src)
|
||||
beam.Grant(src)
|
||||
ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, beam)
|
||||
|
||||
/mob/living/basic/mining/brimdemon/Destroy()
|
||||
QDEL_NULL(beam)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mining/brimdemon/RangedAttack(atom/target, modifiers)
|
||||
beam.Trigger(target = target)
|
||||
|
||||
/mob/living/basic/mining/brimdemon/death(gibbed)
|
||||
. = ..()
|
||||
if (gibbed)
|
||||
return
|
||||
var/obj/effect/temp_visual/brim_burst/bang = new(loc)
|
||||
forceMove(bang)
|
||||
|
||||
/// Show a funny animation before doing an explosion
|
||||
/obj/effect/temp_visual/brim_burst
|
||||
name = "bursting brimdemon"
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "brimdemon_dead"
|
||||
duration = 1.9 SECONDS
|
||||
|
||||
/obj/effect/temp_visual/brim_burst/Initialize(mapload)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, PROC_REF(bang)), duration - (1 DECISECONDS), TIMER_DELETE_ME)
|
||||
animate(src, color = "#ff8888", transform = matrix().Scale(1.1), time = 0.7 SECONDS)
|
||||
animate(color = "#ffffff", transform = matrix(), time = 0.2 SECONDS)
|
||||
animate(color = "#ff4444", transform = matrix().Scale(1.3), time = 0.5 SECONDS)
|
||||
animate(color = "#ffffff", transform = matrix(), time = 0.2 SECONDS)
|
||||
animate(color = "#ff0000", transform = matrix().Scale(1.5), time = 0.3 SECONDS)
|
||||
|
||||
/// Make an explosion
|
||||
/obj/effect/temp_visual/brim_burst/proc/bang()
|
||||
var/turf/origin_turf = get_turf(src)
|
||||
playsound(origin_turf, 'sound/effects/pop_expl.ogg', 50)
|
||||
new /obj/effect/temp_visual/explosion/fast(origin_turf)
|
||||
var/list/possible_targets = range(1, origin_turf)
|
||||
for(var/mob/living/target in possible_targets)
|
||||
var/armor = target.run_armor_check(attack_flag = BOMB)
|
||||
target.apply_damage(20, damagetype = BURN, blocked = armor, spread_damage = TRUE)
|
||||
|
||||
for (var/atom/movable/thing as anything in contents)
|
||||
thing.forceMove(loc)
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Slap someone who is nearby, line up with target, blast with a beam
|
||||
*/
|
||||
/datum/ai_controller/basic_controller/brimdemon
|
||||
blackboard = list(
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/brimdemon,
|
||||
)
|
||||
|
||||
ai_traits = PAUSE_DURING_DO_AFTER
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk/no_target
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
|
||||
/datum/ai_planning_subtree/move_to_cardinal/brimdemon,
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/brimbeam,
|
||||
)
|
||||
|
||||
/datum/targetting_datum/basic/brimdemon
|
||||
stat_attack = HARD_CRIT
|
||||
|
||||
/datum/ai_planning_subtree/move_to_cardinal/brimdemon
|
||||
move_behaviour = /datum/ai_behavior/move_to_cardinal/brimdemon
|
||||
|
||||
/datum/ai_behavior/move_to_cardinal/brimdemon
|
||||
minimum_distance = 2
|
||||
|
||||
/datum/ai_behavior/move_to_cardinal/brimdemon/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
if (!succeeded)
|
||||
return
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
var/datum/action/cooldown/ability = controller.blackboard[BB_TARGETTED_ACTION]
|
||||
if(!ability?.IsAvailable())
|
||||
return
|
||||
ability.InterceptClickOn(caller = controller.pawn, target = target)
|
||||
|
||||
/datum/ai_planning_subtree/targeted_mob_ability/brimbeam
|
||||
use_ability_behaviour = /datum/ai_behavior/targeted_mob_ability/brimbeam
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/brimbeam
|
||||
/// Don't shoot if too far away
|
||||
var/max_target_distance = 9
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/brimbeam/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key)
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target) || !(get_dir(controller.pawn, target) in GLOB.cardinals) || get_dist(controller.pawn, target) > max_target_distance)
|
||||
finish_action(controller, succeeded = FALSE, ability_key = ability_key, target_key = target_key)
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,56 @@
|
||||
/// Brimdemon crusher trophy, it... makes a funny sound?
|
||||
/obj/item/crusher_trophy/brimdemon_fang
|
||||
name = "brimdemon's fang"
|
||||
icon_state = "brimdemon_fang"
|
||||
desc = "A fang from a brimdemon's corpse."
|
||||
denied_type = /obj/item/crusher_trophy/brimdemon_fang
|
||||
/// Cartoon punching vfx
|
||||
var/static/list/comic_phrases = list("BOOM", "BANG", "KABLOW", "KAPOW", "OUCH", "BAM", "KAPOW", "WHAM", "POW", "KABOOM")
|
||||
|
||||
/obj/item/crusher_trophy/brimdemon_fang/effect_desc()
|
||||
return "mark detonation creates visual and audiosensory effects on the target"
|
||||
|
||||
/obj/item/crusher_trophy/brimdemon_fang/on_mark_detonation(mob/living/target, mob/living/user)
|
||||
target.balloon_alert_to_viewers("[pick(comic_phrases)]!")
|
||||
playsound(target, 'sound/lavaland/brimdemon_crush.ogg', 100)
|
||||
|
||||
/// Reagent pool left by dying brimdemon
|
||||
/obj/effect/decal/cleanable/brimdust
|
||||
name = "brimdust"
|
||||
desc = "Dust from a brimdemon. It is considered valuable for its' botanical abilities."
|
||||
icon_state = "brimdust"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
layer = FLOOR_CLEAN_LAYER
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/brimdust/Initialize(mapload)
|
||||
. = ..()
|
||||
reagents.add_reagent(/datum/reagent/brimdust, 15)
|
||||
|
||||
/// Ashwalker ore sensor crafted from brimdemon ash
|
||||
/obj/item/ore_sensor
|
||||
name = "ore sensor"
|
||||
desc = "Using demonic frequencies, this ear-mounted tool detects ores in the nearby terrain."
|
||||
icon_state = "oresensor"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
slot_flags = ITEM_SLOT_EARS
|
||||
var/range = 5
|
||||
var/cooldown = 4 SECONDS //between the standard and the advanced ore scanner in strength
|
||||
COOLDOWN_DECLARE(ore_sensing_cooldown)
|
||||
|
||||
/obj/item/ore_sensor/equipped(mob/user, slot, initial)
|
||||
. = ..()
|
||||
if(slot & ITEM_SLOT_EARS)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/ore_sensor/dropped(mob/user, silent)
|
||||
. = ..()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/ore_sensor/process(seconds_per_tick)
|
||||
if(!COOLDOWN_FINISHED(src, ore_sensing_cooldown))
|
||||
return
|
||||
COOLDOWN_START(src, ore_sensing_cooldown, cooldown)
|
||||
mineral_scan_pulse(get_turf(src), range)
|
||||
@@ -108,10 +108,15 @@
|
||||
if(!dig_ability.IsAvailable())
|
||||
return
|
||||
|
||||
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
var/has_target = controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)
|
||||
|
||||
//a storm is coming or someone is nearby, its time to escape
|
||||
if(currently_underground || !currently_underground && storm_approaching || !QDELETED(target))
|
||||
if(currently_underground)
|
||||
if(has_target)
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/use_mob_ability/burrow, BB_BURROW_ABILITY)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if(storm_approaching || has_target)
|
||||
controller.queue_behavior(/datum/ai_behavior/use_mob_ability/burrow, BB_BURROW_ABILITY)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
@@ -122,14 +127,10 @@
|
||||
/datum/ai_planning_subtree/grub_mine
|
||||
|
||||
/datum/ai_planning_subtree/grub_mine/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/turf/target_wall = controller.blackboard[BB_TARGET_MINERAL_WALL]
|
||||
|
||||
if(QDELETED(target_wall))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_TARGET_MINERAL_WALL)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if(controller.blackboard_key_exists(BB_TARGET_MINERAL_WALL))
|
||||
controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_TARGET_MINERAL_WALL)
|
||||
|
||||
/datum/ai_behavior/mine_wall
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
@@ -168,7 +169,7 @@
|
||||
|
||||
/datum/pet_command/grub_spit/execute_action(datum/ai_controller/controller)
|
||||
var/datum/action/cooldown/spit_ability = controller.blackboard[BB_SPIT_ABILITY]
|
||||
if(QDELETED(spit_ability) || !spit_ability.IsAvailable())
|
||||
if(!spit_ability?.IsAvailable())
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/use_mob_ability, BB_SPIT_ABILITY)
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
@@ -96,8 +96,7 @@
|
||||
var/target_key = BB_GOLIATH_HOLE_TARGET
|
||||
|
||||
/datum/ai_planning_subtree/goliath_dig/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/turf/target_turf = controller.blackboard[target_key]
|
||||
if (QDELETED(target_turf))
|
||||
if (!controller.blackboard_key_exists(target_key))
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/goliath_dig, target_key)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
|
||||
)
|
||||
|
||||
ai_traits = PAUSE_DURING_DO_AFTER
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk
|
||||
planning_subtrees = list(
|
||||
|
||||
@@ -19,14 +19,10 @@
|
||||
|
||||
///find dead humans and report their location on the radio
|
||||
/datum/ai_planning_subtree/locate_dead_humans/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/dead_target = controller.blackboard[BB_NEARBY_DEAD_MINER]
|
||||
|
||||
if(QDELETED(dead_target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/unconscious_human, BB_NEARBY_DEAD_MINER, /mob/living/carbon/human)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/send_sos_message, BB_NEARBY_DEAD_MINER)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if(controller.blackboard_key_exists(BB_NEARBY_DEAD_MINER))
|
||||
controller.queue_behavior(/datum/ai_behavior/send_sos_message, BB_NEARBY_DEAD_MINER)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/unconscious_human, BB_NEARBY_DEAD_MINER, /mob/living/carbon/human)
|
||||
|
||||
/datum/ai_behavior/find_and_set/unconscious_human/search_tactic(datum/ai_controller/controller, locate_path, search_range)
|
||||
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
|
||||
@@ -73,18 +69,12 @@
|
||||
|
||||
///mine walls if we are on automated mining mode
|
||||
/datum/ai_planning_subtree/minebot_mining/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/turf/mineral_target = controller.blackboard[BB_TARGET_MINERAL_TURF]
|
||||
var/automated_mining = controller.blackboard[BB_AUTOMATED_MINING]
|
||||
|
||||
if(!automated_mining)
|
||||
if(!controller.blackboard[BB_AUTOMATED_MINING])
|
||||
return
|
||||
|
||||
if(QDELETED(mineral_target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mineral_wall/minebot, BB_TARGET_MINERAL_TURF)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/minebot_mine_turf, BB_TARGET_MINERAL_TURF)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if(controller.blackboard_key_exists(BB_TARGET_MINERAL_TURF))
|
||||
controller.queue_behavior(/datum/ai_behavior/minebot_mine_turf, BB_TARGET_MINERAL_TURF)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
controller.queue_behavior(/datum/ai_behavior/find_mineral_wall/minebot, BB_TARGET_MINERAL_TURF)
|
||||
|
||||
/datum/ai_behavior/find_mineral_wall/minebot
|
||||
|
||||
@@ -190,7 +180,7 @@
|
||||
|
||||
/datum/pet_command/minebot_ability/execute_action(datum/ai_controller/controller)
|
||||
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
||||
if(QDELETED(ability) || !ability.IsAvailable())
|
||||
if(!ability?.IsAvailable())
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/use_mob_ability, ability_key)
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
@@ -34,9 +34,7 @@
|
||||
|
||||
/datum/ai_planning_subtree/find_nearest_magicarp_spell_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL]
|
||||
if (QDELETED(using_action))
|
||||
return
|
||||
if (!using_action.IsAvailable())
|
||||
if (!using_action?.IsAvailable())
|
||||
return
|
||||
|
||||
var/spell_targetting = controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING]
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
if (!rift_behaviour)
|
||||
CRASH("Forgot to specify rift behaviour for [src]")
|
||||
|
||||
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
|
||||
return
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[BB_CARP_RIFT]
|
||||
if (QDELETED(target) || QDELETED(using_action) || !using_action.IsAvailable())
|
||||
if (!using_action?.IsAvailable())
|
||||
return
|
||||
|
||||
controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, BB_BASIC_MOB_CURRENT_TARGET)
|
||||
|
||||
@@ -17,14 +17,10 @@
|
||||
/datum/ai_planning_subtree/heal_the_blind
|
||||
|
||||
/datum/ai_planning_subtree/heal_the_blind/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/carbon/target = controller.blackboard[BB_BLIND_TARGET]
|
||||
|
||||
if(QDELETED(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_the_blind, BB_BLIND_TARGET, BB_EYE_DAMAGE_THRESHOLD)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/heal_eye_damage, BB_BLIND_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if(controller.blackboard_key_exists(BB_BLIND_TARGET))
|
||||
controller.queue_behavior(/datum/ai_behavior/heal_eye_damage, BB_BLIND_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
controller.queue_behavior(/datum/ai_behavior/find_the_blind, BB_BLIND_TARGET, BB_EYE_DAMAGE_THRESHOLD)
|
||||
|
||||
/datum/targetting_datum/basic/eyeball/can_attack(mob/living/owner, atom/target)
|
||||
. = ..()
|
||||
|
||||
@@ -54,14 +54,10 @@
|
||||
if(!SPT_PROB(relay_chance, seconds_per_tick))
|
||||
return
|
||||
|
||||
var/mob/hive_target = controller.blackboard[BB_HIVE_PARTNER]
|
||||
|
||||
if(QDELETED(hive_target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/hive_partner, BB_HIVE_PARTNER, /mob/living/basic/hivebot)
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/relay_message, BB_HIVE_PARTNER)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if (controller.blackboard_key_exists(BB_HIVE_PARTNER))
|
||||
controller.queue_behavior(/datum/ai_behavior/relay_message, BB_HIVE_PARTNER)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/hive_partner, BB_HIVE_PARTNER, /mob/living/basic/hivebot)
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/repair_machines
|
||||
target_key = BB_MACHINE_TARGET
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(),
|
||||
)
|
||||
|
||||
ai_traits = STOP_MOVING_WHEN_PULLED
|
||||
ai_traits = STOP_MOVING_WHEN_PULLED | PAUSE_DURING_DO_AFTER
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking
|
||||
|
||||
|
||||
+3
-6
@@ -62,12 +62,9 @@
|
||||
var/target_key = BB_SPIDER_WEB_TARGET
|
||||
|
||||
/datum/ai_planning_subtree/spin_web/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[action_key]
|
||||
var/turf/target_turf = controller.blackboard[target_key]
|
||||
if (QDELETED(using_action) || QDELETED(target_turf))
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/spin_web, action_key, target_key)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if (controller.blackboard_key_exists(action_key) && controller.blackboard_key_exists(target_key))
|
||||
controller.queue_behavior(/datum/ai_behavior/spin_web, action_key, target_key)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/// Move to an unwebbed nearby turf and web it up
|
||||
/datum/ai_behavior/spin_web
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
#define BRIMBEAM_RANGE 10
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon
|
||||
name = "brimdemon"
|
||||
desc = "A misshapen demon with big, red eyes and a hinged mouth. Not much is known about the creatures \
|
||||
due to their response to any unexpected stimulus being \"brimbeam\", a deadly blood-laser barrage."
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "brimdemon"
|
||||
icon_living = "brimdemon"
|
||||
icon_dead = "brimdemon_dead"
|
||||
mob_biotypes = MOB_ORGANIC|MOB_BEAST
|
||||
speak_emote = list("cackles")
|
||||
emote_taunt = list("screeches")
|
||||
emote_hear = list("cackles","screeches")
|
||||
combat_mode = TRUE
|
||||
stat_attack = HARD_CRIT
|
||||
ranged_cooldown_time = 5 SECONDS
|
||||
vision_range = 9
|
||||
retreat_distance = 2
|
||||
speed = 3
|
||||
move_to_delay = 5
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
obj_damage = 15
|
||||
melee_damage_lower = 7.5
|
||||
melee_damage_upper = 7.5
|
||||
rapid_melee = 2 // every second attack
|
||||
attack_verb_continuous = "bites"
|
||||
attack_verb_simple = "bite"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_BITE
|
||||
butcher_results = list(
|
||||
/obj/item/food/meat/slab = 2,
|
||||
/obj/effect/decal/cleanable/brimdust = 1,
|
||||
/obj/item/organ/internal/monster_core/brimdust_sac = 1,
|
||||
)
|
||||
loot = list()
|
||||
robust_searching = TRUE
|
||||
footstep_type = FOOTSTEP_MOB_CLAW
|
||||
death_message = "wails as infernal energy escapes from its wounds, leaving it an empty husk."
|
||||
death_sound = 'sound/magic/demon_dies.ogg'
|
||||
light_color = LIGHT_COLOR_BLOOD_MAGIC
|
||||
light_power = 5
|
||||
light_range = 1.4
|
||||
crusher_loot = /obj/item/crusher_trophy/brimdemon_fang
|
||||
/// Are we charging/firing? If yes stops our movement.
|
||||
var/firing = FALSE
|
||||
/// A list of all the beam parts.
|
||||
var/list/beamparts = list()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/Destroy()
|
||||
QDEL_LIST(beamparts)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/Login()
|
||||
ranged = TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/Logout()
|
||||
ranged = FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/death()
|
||||
firing = FALSE
|
||||
cut_overlay("brimdemon_telegraph_dir")
|
||||
move_resist = initial(move_resist)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/Goto(target, delay, minimum_distance)
|
||||
if(firing)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/MoveToTarget(list/possible_targets)
|
||||
if(firing)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/AttackingTarget(atom/attacked_target)
|
||||
if(firing)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/Move(atom/newloc, dir, step_x , step_y)
|
||||
if(firing)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/OpenFire()
|
||||
if(firing)
|
||||
balloon_alert(src, "already firing!")
|
||||
return
|
||||
if(!COOLDOWN_FINISHED(src, ranged_cooldown))
|
||||
balloon_alert(src, "on cooldown!")
|
||||
return
|
||||
firing = TRUE
|
||||
set_dir_on_move = FALSE
|
||||
icon_state = "brimdemon_firing"
|
||||
move_resist = MOVE_FORCE_VERY_STRONG
|
||||
add_overlay("brimdemon_telegraph_dir")
|
||||
visible_message(span_danger("[src] starts charging!"))
|
||||
balloon_alert(src, "charging...")
|
||||
addtimer(CALLBACK(src, PROC_REF(fire_laser)), 1 SECONDS)
|
||||
COOLDOWN_START(src, ranged_cooldown, ranged_cooldown_time)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
|
||||
. = ..()
|
||||
check_fire()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/proc/check_fire()
|
||||
if(key || QDELETED(target) || get_dist(src, target) > BRIMBEAM_RANGE || !(get_dir(src, target) in GLOB.cardinals))
|
||||
return
|
||||
face_atom(target)
|
||||
OpenFire()
|
||||
|
||||
/// Fires a brimbeam, getting a line of turfs between it and the direction to the target and creating a brimbeam effect on every one of them.
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/proc/fire_laser()
|
||||
if(stat == DEAD)
|
||||
return
|
||||
visible_message(span_danger("[src] fires a brimbeam!"))
|
||||
balloon_alert(src, "brimbeam fired")
|
||||
playsound(src, 'sound/creatures/brimdemon.ogg', 150, FALSE, 0, 3)
|
||||
cut_overlay("brimdemon_telegraph_dir")
|
||||
var/turf/target_turf = get_ranged_target_turf(src, dir, BRIMBEAM_RANGE)
|
||||
var/turf/origin_turf = get_turf(src)
|
||||
var/list/affected_turfs = get_line(origin_turf, target_turf) - origin_turf
|
||||
for(var/turf/affected_turf in affected_turfs)
|
||||
var/blocked = FALSE
|
||||
if(affected_turf.opacity)
|
||||
blocked = TRUE
|
||||
for(var/obj/potential_block in affected_turf.contents)
|
||||
if(potential_block.opacity)
|
||||
blocked = TRUE
|
||||
break
|
||||
if(blocked)
|
||||
break
|
||||
var/atom/new_brimbeam = new /obj/effect/brimbeam(affected_turf)
|
||||
new_brimbeam.dir = dir
|
||||
beamparts += new_brimbeam
|
||||
for(var/mob/living/hit_mob in affected_turf.contents)
|
||||
hit_mob.adjustFireLoss(25)
|
||||
to_chat(hit_mob, span_userdanger("You're hit by [src]'s brimbeam!"))
|
||||
if(length(beamparts))
|
||||
var/atom/last_brimbeam = beamparts[length(beamparts)]
|
||||
last_brimbeam.icon_state = "brimbeam_end"
|
||||
var/atom/first_brimbeam = beamparts[1]
|
||||
first_brimbeam.icon_state = "brimbeam_start"
|
||||
addtimer(CALLBACK(src, PROC_REF(end_laser)), 2 SECONDS)
|
||||
|
||||
/// Deletes all the brimbeam parts and sets variables back to their initial ones.
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon/proc/end_laser()
|
||||
if(stat != DEAD)
|
||||
icon_state = initial(icon_state)
|
||||
move_resist = initial(move_resist)
|
||||
set_dir_on_move = initial(set_dir_on_move)
|
||||
firing = FALSE
|
||||
for(var/obj/effect/brimbeam/beam in beamparts)
|
||||
animate(beam, time = 0.5 SECONDS, alpha = 0)
|
||||
QDEL_IN(beam, 0.5 SECONDS)
|
||||
beamparts -= beam
|
||||
|
||||
/obj/effect/brimbeam
|
||||
name = "brimbeam"
|
||||
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "brimbeam_mid"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
plane = ABOVE_GAME_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
light_color = LIGHT_COLOR_BLOOD_MAGIC
|
||||
light_power = 3
|
||||
light_range = 2
|
||||
|
||||
/obj/effect/brimbeam/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/effect/brimbeam/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/brimbeam/process()
|
||||
for(var/mob/living/hit_mob in get_turf(src))
|
||||
damage(hit_mob)
|
||||
|
||||
/obj/effect/brimbeam/proc/damage(mob/living/hit_mob)
|
||||
hit_mob.adjustFireLoss(5)
|
||||
to_chat(hit_mob, span_danger("You're damaged by [src]!"))
|
||||
|
||||
/obj/item/crusher_trophy/brimdemon_fang
|
||||
name = "brimdemon's fang"
|
||||
icon_state = "brimdemon_fang"
|
||||
desc = "A fang from a brimdemon's corpse."
|
||||
denied_type = /obj/item/crusher_trophy/brimdemon_fang
|
||||
var/static/list/comic_phrases = list("BOOM", "BANG", "KABLOW", "KAPOW", "OUCH", "BAM", "KAPOW", "WHAM", "POW", "KABOOM")
|
||||
|
||||
/obj/item/crusher_trophy/brimdemon_fang/effect_desc()
|
||||
return "mark detonation creates visual and audiosensory effects on the target"
|
||||
|
||||
/obj/item/crusher_trophy/brimdemon_fang/on_mark_detonation(mob/living/target, mob/living/user)
|
||||
target.balloon_alert_to_viewers("[pick(comic_phrases)]!")
|
||||
playsound(target, 'sound/lavaland/brimdemon_crush.ogg', 100)
|
||||
|
||||
/obj/effect/decal/cleanable/brimdust
|
||||
name = "brimdust"
|
||||
desc = "Dust from a brimdemon. It is considered valuable for its' botanical abilities."
|
||||
icon_state = "brimdust"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
layer = FLOOR_CLEAN_LAYER
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/brimdust/Initialize(mapload)
|
||||
. = ..()
|
||||
reagents.add_reagent(/datum/reagent/brimdust, 15)
|
||||
|
||||
/obj/item/ore_sensor
|
||||
name = "ore sensor"
|
||||
desc = "Using demonic frequencies, this ear-mounted tool detects ores in the nearby terrain."
|
||||
icon_state = "oresensor"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
slot_flags = ITEM_SLOT_EARS
|
||||
var/range = 5
|
||||
var/cooldown = 4 SECONDS //between the standard and the advanced ore scanner in strength
|
||||
COOLDOWN_DECLARE(ore_sensing_cooldown)
|
||||
|
||||
/obj/item/ore_sensor/equipped(mob/user, slot, initial)
|
||||
. = ..()
|
||||
if(slot & ITEM_SLOT_EARS)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/ore_sensor/dropped(mob/user, silent)
|
||||
. = ..()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/ore_sensor/process(seconds_per_tick)
|
||||
if(!COOLDOWN_FINISHED(src, ore_sensing_cooldown))
|
||||
return
|
||||
COOLDOWN_START(src, ore_sensing_cooldown, cooldown)
|
||||
mineral_scan_pulse(get_turf(src), range)
|
||||
|
||||
#undef BRIMBEAM_RANGE
|
||||
@@ -64,17 +64,17 @@
|
||||
build_all_button_icons()
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/click_target)
|
||||
/datum/action/cooldown/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
|
||||
var/atom/aim_assist_target
|
||||
if(aim_assist && isturf(click_target))
|
||||
if(aim_assist && isturf(target))
|
||||
// Find any human in the list. We aren't picky, it's aim assist after all
|
||||
aim_assist_target = locate(/mob/living/carbon/human) in click_target
|
||||
aim_assist_target = locate(/mob/living/carbon/human) in target
|
||||
if(!aim_assist_target)
|
||||
// If we didn't find a human, we settle for any living at all
|
||||
aim_assist_target = locate(/mob/living) in click_target
|
||||
aim_assist_target = locate(/mob/living) in target
|
||||
|
||||
return ..(caller, params, aim_assist_target || click_target)
|
||||
return ..(caller, params, aim_assist_target || target)
|
||||
|
||||
/datum/action/cooldown/spell/pointed/is_valid_target(atom/cast_on)
|
||||
if(cast_on == owner)
|
||||
|
||||
@@ -35,27 +35,27 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/spell/pointed/swap/InterceptClickOn(mob/living/caller, params, atom/click_target)
|
||||
/datum/action/cooldown/spell/pointed/swap/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
|
||||
if(!IsAvailable(feedback = TRUE))
|
||||
return FALSE
|
||||
if(!target)
|
||||
return FALSE
|
||||
if(!isliving(click_target) || isturf(click_target))
|
||||
if(!isliving(target) || isturf(target))
|
||||
// Find any living being in the list. We aren't picky, it's aim assist after all
|
||||
click_target = locate(/mob/living) in click_target
|
||||
if(!click_target)
|
||||
target = locate(/mob/living) in target
|
||||
if(!target)
|
||||
to_chat(owner, span_warning("You can only select living beings as secondary target!"))
|
||||
return FALSE
|
||||
if(click_target == owner)
|
||||
if(target == owner)
|
||||
if(!isnull(second_target))
|
||||
to_chat(owner, span_notice("You cancel your secondary swap target!"))
|
||||
second_target = null
|
||||
else
|
||||
to_chat(owner, span_warning("You have no secondary swap target!"))
|
||||
return FALSE
|
||||
second_target = click_target
|
||||
to_chat(owner, span_notice("You select [click_target.name] as a secondary swap target!"))
|
||||
second_target = target
|
||||
to_chat(owner, span_notice("You select [target.name] as a secondary swap target!"))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
/mob/living/simple_animal/hostile/alien/queen/large,
|
||||
/mob/living/simple_animal/hostile/alien/sentinel,
|
||||
/mob/living/simple_animal/hostile/asteroid,
|
||||
/mob/living/simple_animal/hostile/asteroid/brimdemon,
|
||||
/mob/living/simple_animal/hostile/asteroid/curseblob,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite/broodmother,
|
||||
|
||||
Reference in New Issue
Block a user