mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
minebot buff (#82001)
## About The Pull Request this pr buffs non-sentient minebots a bit to make them more helpful with the new arcmining changes. Minebots now have a better overall AI, they will maintain distance from enemies and shoot while running. they will also plant landmines while theyre running away from enemies. these landmines are carefully programmed by the bot not to trigger when any of its miner friends step on it. u no longer need to feed minebots an ore to get them to listen to you, as they now automatically listen to any miners around. minebots can now repair damaged node drones  they also have a new autodefend feature, which makes them automatically attack any mob that attacks its miner friends or the drone. They also have some new upgrades! First is the regenerative shield, this shield allows minebots to tank a limited amount of hits before breaking. minebots will then need to wait sometime before the shield re-activates. Second is the rocket launcher remote control, this allows players to direct minebots to fire anti-fauna missiles at their target https://github.com/tgstation/tgstation/assets/138636438/3ec3605e-8e11-4a31-acaa-1382bed98294 Also minebots are now highly customizable, you can rename them, change their colors, or program their AI through their new user interface  ## Why It's Good For The Game Improves minebot AI a bit, and makes it a more viable option for mining solo players ## Changelog 🆑 balance: minebots have been buffed and have recieved new upgrades /🆑
This commit is contained in:
@@ -31,13 +31,18 @@
|
||||
light_on = FALSE
|
||||
combat_mode = FALSE
|
||||
ai_controller = /datum/ai_controller/basic_controller/minebot
|
||||
///the access card we use to access mining
|
||||
var/obj/item/card/id/access_card
|
||||
///the gun we use to kill
|
||||
var/obj/item/gun/energy/recharge/kinetic_accelerator/minebot/stored_gun
|
||||
///our normal overlay
|
||||
var/mutable_appearance/neutral_overlay
|
||||
///our combat mode overlay
|
||||
var/mutable_appearance/combat_overlay
|
||||
///our current color, if any
|
||||
var/selected_color
|
||||
///the commands our owner can give us
|
||||
var/list/pet_commands = list(
|
||||
var/static/list/pet_commands = list(
|
||||
/datum/pet_command/idle/minebot,
|
||||
/datum/pet_command/protect_owner/minebot,
|
||||
/datum/pet_command/minebot_ability/light,
|
||||
/datum/pet_command/minebot_ability/dump,
|
||||
/datum/pet_command/automate_mining,
|
||||
@@ -45,17 +50,27 @@
|
||||
/datum/pet_command/follow,
|
||||
/datum/pet_command/point_targeting/attack/minebot,
|
||||
)
|
||||
///possible colors the bot can have
|
||||
var/static/list/possible_colors= list(
|
||||
"Default" = null, //default color state
|
||||
"Blue" = "#70d5e7",
|
||||
"Red" = "#ee7fb9",
|
||||
"Green" = "#5fea94",
|
||||
)
|
||||
|
||||
/mob/living/basic/mining_drone/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
neutral_overlay = mutable_appearance(icon = 'icons/mob/silicon/aibots.dmi', icon_state = "mining_drone_grey")
|
||||
combat_overlay = mutable_appearance(icon = 'icons/mob/silicon/aibots.dmi', icon_state = "mining_drone_offense_grey")
|
||||
AddComponent(/datum/component/obeys_commands, pet_commands)
|
||||
var/static/list/death_drops = list(/obj/effect/decal/cleanable/robot_debris/old)
|
||||
AddElement(/datum/element/death_drops, death_drops)
|
||||
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE), INNATE_TRAIT)
|
||||
AddElement(/datum/element/footstep, FOOTSTEP_OBJ_ROBOT, 1, -6, sound_vary = TRUE)
|
||||
AddComponent(/datum/component/tameable, food_types = list(/obj/item/stack/ore), tame_chance = 100, bonus_tame_chance = 5)
|
||||
|
||||
var/static/list/innate_actions = list(
|
||||
/datum/action/cooldown/mob_cooldown/missile_launcher = BB_MINEBOT_MISSILE_ABILITY,
|
||||
/datum/action/cooldown/mob_cooldown/drop_landmine = BB_MINEBOT_LANDMINE_ABILITY,
|
||||
/datum/action/cooldown/mob_cooldown/minedrone/toggle_light = BB_MINEBOT_LIGHT_ABILITY,
|
||||
/datum/action/cooldown/mob_cooldown/minedrone/toggle_meson_vision = null,
|
||||
/datum/action/cooldown/mob_cooldown/minedrone/dump_ore = BB_MINEBOT_DUMP_ABILITY,
|
||||
@@ -66,10 +81,11 @@
|
||||
stored_gun = new(src)
|
||||
var/obj/item/implant/radio/mining/comms = new(src)
|
||||
comms.implant(src)
|
||||
access_card = new /obj/item/card/id/advanced/gold(src)
|
||||
SSid_access.apply_trim_to_card(access_card, /datum/id_trim/job/shaft_miner)
|
||||
|
||||
RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(attempt_access))
|
||||
var/static/list/accesses = list(
|
||||
/datum/id_trim/job/shaft_miner,
|
||||
)
|
||||
AddElement(/datum/element/mob_access, accesses)
|
||||
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
|
||||
|
||||
/mob/living/basic/mining_drone/set_combat_mode(new_mode, silent = TRUE)
|
||||
. = ..()
|
||||
@@ -115,8 +131,82 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mining_drone/attack_hand(mob/living/carbon/human/user, list/modifiers)
|
||||
if(!user.combat_mode)
|
||||
ui_interact(user)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mining_drone/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "MineBot", name)
|
||||
ui.open()
|
||||
|
||||
/mob/living/basic/mining_drone/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["auto_defend"] = ai_controller.blackboard[BB_MINEBOT_AUTO_DEFEND]
|
||||
data["repair_node_drone"] = ai_controller.blackboard[BB_MINEBOT_REPAIR_DRONE]
|
||||
data["plant_mines"] = ai_controller.blackboard[BB_MINEBOT_PLANT_MINES]
|
||||
data["bot_maintain_distance"] = ai_controller.blackboard[BB_MINIMUM_SHOOTING_DISTANCE]
|
||||
data["bot_name"] = name
|
||||
data["bot_mode"] = combat_mode
|
||||
data["bot_health"] = health
|
||||
data["bot_maxhealth"] = maxHealth
|
||||
data["bot_color"] = ""
|
||||
var/color_value = neutral_overlay.color
|
||||
for(var/index in possible_colors)
|
||||
if(possible_colors[index] == color_value)
|
||||
data["bot_color"] = index
|
||||
break
|
||||
return data
|
||||
|
||||
/mob/living/basic/mining_drone/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["bot_icon"] = icon2base64(getFlatIcon(src))
|
||||
data["possible_colors"] = list()
|
||||
for(var/color in possible_colors)
|
||||
data["possible_colors"] += list(list(
|
||||
"color_name" = color,
|
||||
"color_value" = possible_colors[color],
|
||||
))
|
||||
return data
|
||||
|
||||
/mob/living/basic/mining_drone/ui_act(action, params, datum/tgui/ui)
|
||||
. = ..()
|
||||
switch(action)
|
||||
if("change_min_distance")
|
||||
var/new_distance = clamp(params["distance"], 0, 5)
|
||||
ai_controller.set_blackboard_key(BB_MINIMUM_SHOOTING_DISTANCE, new_distance)
|
||||
if("toggle_defend")
|
||||
var/new_toggle = !ai_controller.blackboard[BB_MINEBOT_AUTO_DEFEND]
|
||||
ai_controller.set_blackboard_key(BB_MINEBOT_AUTO_DEFEND, new_toggle)
|
||||
if("toggle_repair")
|
||||
var/new_defend = !ai_controller.blackboard[BB_MINEBOT_REPAIR_DRONE]
|
||||
ai_controller.set_blackboard_key(BB_MINEBOT_REPAIR_DRONE, new_defend)
|
||||
if("toggle_mines")
|
||||
var/new_mines = !ai_controller.blackboard[BB_MINEBOT_PLANT_MINES]
|
||||
ai_controller.set_blackboard_key(BB_MINEBOT_PLANT_MINES, new_mines)
|
||||
if("set_name")
|
||||
var/input_name = sanitize_name(params["chosen_name"], allow_numbers = TRUE)
|
||||
name = (input_name ? input_name : initial(name))
|
||||
if("toggle_mode")
|
||||
set_combat_mode(!combat_mode)
|
||||
if("set_color")
|
||||
change_color(params["chosen_color"])
|
||||
update_static_data(ui.user, ui)
|
||||
return TRUE
|
||||
|
||||
/mob/living/basic/mining_drone/proc/change_color(new_color)
|
||||
selected_color = new_color
|
||||
if(!isnull(selected_color))
|
||||
neutral_overlay.color = selected_color
|
||||
combat_overlay.color = selected_color
|
||||
update_appearance()
|
||||
|
||||
/mob/living/basic/mining_drone/AltClick(mob/living/user)
|
||||
. = ..()
|
||||
if(user.combat_mode)
|
||||
return ..()
|
||||
return
|
||||
set_combat_mode(!combat_mode)
|
||||
balloon_alert(user, "now [combat_mode ? "attacking wildlife" : "collecting loose ore"]")
|
||||
|
||||
@@ -125,7 +215,6 @@
|
||||
return
|
||||
stored_gun.afterattack(target, src)
|
||||
|
||||
|
||||
/mob/living/basic/mining_drone/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
. = ..()
|
||||
|
||||
@@ -141,16 +230,6 @@
|
||||
for(var/obj/item/stack/ore/dropped_item in contents)
|
||||
dropped_item.forceMove(get_turf(src))
|
||||
|
||||
/mob/living/basic/mining_drone/proc/attempt_access(mob/drone, obj/door_attempt)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(door_attempt.check_access(access_card))
|
||||
return ACCESS_ALLOWED
|
||||
return ACCESS_DISALLOWED
|
||||
|
||||
/mob/living/basic/mining_drone/tamed(mob/living/tamer, atom/food)
|
||||
AddComponent(/datum/component/obeys_commands, pet_commands)
|
||||
|
||||
/mob/living/basic/mining_drone/death(gibbed)
|
||||
drop_ore()
|
||||
|
||||
@@ -164,6 +243,25 @@
|
||||
|
||||
/mob/living/basic/mining_drone/Destroy()
|
||||
QDEL_NULL(stored_gun)
|
||||
QDEL_NULL(access_card)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/mining_drone/proc/pre_attack(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!istype(target, /mob/living/basic/node_drone))
|
||||
return NONE
|
||||
INVOKE_ASYNC(src, PROC_REF(repair_node_drone), target)
|
||||
return COMPONENT_HOSTILE_NO_ATTACK
|
||||
|
||||
/mob/living/basic/mining_drone/proc/repair_node_drone(mob/living/my_target)
|
||||
do_sparks(5, FALSE, source = my_target)
|
||||
if(!do_after(src, 6 SECONDS, my_target))
|
||||
return
|
||||
my_target.heal_overall_damage(brute = 50)
|
||||
|
||||
/mob/living/basic/mining_drone/update_overlays()
|
||||
. = ..()
|
||||
if(stat == DEAD || isnull(selected_color))
|
||||
return
|
||||
|
||||
. += combat_mode ? combat_overlay : neutral_overlay
|
||||
|
||||
@@ -49,3 +49,131 @@
|
||||
|
||||
to_chat(owner, span_notice("You toggle your meson vision [(owner.sight & SEE_TURFS) ? "on" : "off"]."))
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/missile_launcher
|
||||
name = "Launch Missile"
|
||||
button_icon = 'icons/obj/weapons/guns/projectiles.dmi'
|
||||
button_icon_state = "84mm-heap"
|
||||
background_icon_state = "bg_default"
|
||||
overlay_icon_state = "bg_default_border"
|
||||
desc = "Launch a missile towards the target!"
|
||||
cooldown_time = 10 SECONDS
|
||||
shared_cooldown = NONE
|
||||
melee_cooldown_time = 0 SECONDS
|
||||
///how long before we launch said missile
|
||||
var/wind_up_timer = 1 SECONDS
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/missile_launcher/IsAvailable(feedback = TRUE)
|
||||
if(is_mining_level(owner.z))
|
||||
return TRUE
|
||||
if(feedback)
|
||||
owner.balloon_alert(owner, "cant be used here!")
|
||||
return FALSE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/missile_launcher/Activate(atom/target)
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if(isnull(target_turf) || !can_see(owner, target_turf, 7))
|
||||
return FALSE
|
||||
owner.Shake(duration = wind_up_timer)
|
||||
addtimer(CALLBACK(src, PROC_REF(launch_missile), target_turf), wind_up_timer)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/missile_launcher/proc/launch_missile(turf/target_turf)
|
||||
new /obj/effect/temp_visual/mook_dust(get_turf(owner))
|
||||
var/obj/effect/temp_visual/rising_rocket/new_rocket = new(get_turf(owner))
|
||||
addtimer(CALLBACK(src, PROC_REF(drop_missile), target_turf), new_rocket.duration)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/missile_launcher/proc/drop_missile(turf/target_turf)
|
||||
new /obj/effect/temp_visual/falling_rocket(target_turf)
|
||||
var/obj/effect/temp_visual/falling_shadow = new /obj/effect/temp_visual/shadow_telegraph(target_turf)
|
||||
animate(falling_shadow, transform = matrix().Scale(0.1, 0.1), time = falling_shadow.duration)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/drop_landmine
|
||||
name = "Landmine"
|
||||
desc = "Drop a landmine!"
|
||||
button_icon = 'icons/obj/weapons/grenade.dmi'
|
||||
button_icon_state = "landmine"
|
||||
background_icon_state = "bg_default"
|
||||
overlay_icon_state = "bg_default_border"
|
||||
cooldown_time = 10 SECONDS
|
||||
shared_cooldown = NONE
|
||||
melee_cooldown_time = 0 SECONDS
|
||||
click_to_activate = FALSE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/drop_landmine/IsAvailable(feedback = TRUE)
|
||||
if(is_mining_level(owner.z))
|
||||
return TRUE
|
||||
if(feedback)
|
||||
owner.balloon_alert(owner, "cant be used here!")
|
||||
return FALSE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/drop_landmine/Activate(atom/target)
|
||||
var/turf/my_turf = get_turf(owner)
|
||||
if(isgroundlessturf(my_turf))
|
||||
return FALSE
|
||||
var/obj/effect/mine/minebot/my_mine = new(my_turf)
|
||||
my_mine.ignore_list = owner.faction.Copy()
|
||||
playsound(my_turf, 'sound/weapons/armbomb.ogg', 20)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/temp_visual/rising_rocket
|
||||
name = "Missile"
|
||||
icon = 'icons/obj/weapons/guns/projectiles.dmi'
|
||||
icon_state = "84mm-heap"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
duration = 2 SECONDS
|
||||
|
||||
/obj/effect/temp_visual/rising_rocket/Initialize(mapload)
|
||||
. = ..()
|
||||
playsound(src, 'sound/weapons/minebot_rocket.ogg', 100, FALSE)
|
||||
animate(src, pixel_y = base_pixel_y + 500, time = duration, easing = EASE_IN)
|
||||
|
||||
/obj/effect/temp_visual/falling_rocket
|
||||
name = "Missile"
|
||||
icon = 'icons/obj/weapons/guns/projectiles.dmi'
|
||||
icon_state = "84mm-heap"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
duration = 0.7 SECONDS
|
||||
pixel_y = 60
|
||||
///the radius of our explosion
|
||||
var/explosion_radius = 2
|
||||
///damage of our explosion
|
||||
var/explosion_damage = 100
|
||||
|
||||
/obj/effect/temp_visual/falling_rocket/Initialize(mapload)
|
||||
. = ..()
|
||||
transform = transform.Turn(180)
|
||||
addtimer(CALLBACK(src, PROC_REF(create_explosion)), duration)
|
||||
animate(src, pixel_y = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/falling_rocket/proc/create_explosion()
|
||||
playsound(src, 'sound/weapons/minebot_rocket.ogg', 100, FALSE)
|
||||
var/datum/effect_system/fluid_spread/smoke/smoke = new
|
||||
smoke.set_up(1, holder = src)
|
||||
smoke.start()
|
||||
for(var/mob/living/living_target in oview(explosion_radius, src))
|
||||
if(living_target.incorporeal_move)
|
||||
continue
|
||||
living_target.apply_damage(explosion_damage)
|
||||
|
||||
/obj/effect/mine/minebot
|
||||
name = "Landmine"
|
||||
///we dont detonate if any of these people step on us
|
||||
var/list/ignore_list = list()
|
||||
///the damage we apply to whoever steps on us
|
||||
var/damage_to_apply = 50
|
||||
|
||||
/obj/effect/mine/minebot/mineEffect(mob/living/victim)
|
||||
if(!istype(victim))
|
||||
return
|
||||
var/datum/effect_system/fluid_spread/smoke/smoke = new
|
||||
smoke.set_up(0, holder = src)
|
||||
smoke.start()
|
||||
playsound(src, 'sound/effects/explosion3.ogg', 100)
|
||||
victim.apply_damage(damage_to_apply)
|
||||
|
||||
/obj/effect/mine/minebot/can_trigger(atom/movable/on_who)
|
||||
if(REF(on_who) in ignore_list)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
blackboard = list(
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
|
||||
BB_BASIC_MOB_FLEE_DISTANCE = 3,
|
||||
BB_MINIMUM_SHOOTING_DISTANCE = 3,
|
||||
BB_MINEBOT_PLANT_MINES = TRUE,
|
||||
BB_MINEBOT_REPAIR_DRONE = TRUE,
|
||||
BB_MINEBOT_AUTO_DEFEND = TRUE,
|
||||
BB_BLACKLIST_MINERAL_TURFS = list(/turf/closed/mineral/gibtonite),
|
||||
BB_AUTOMATED_MINING = FALSE,
|
||||
)
|
||||
@@ -11,11 +16,90 @@
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/simple_find_target,
|
||||
/datum/ai_planning_subtree/pet_planning,
|
||||
/datum/ai_planning_subtree/befriend_miners,
|
||||
/datum/ai_planning_subtree/defend_node,
|
||||
/datum/ai_planning_subtree/launch_missiles,
|
||||
/datum/ai_planning_subtree/minebot_maintain_distance,
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores/minebot,
|
||||
/datum/ai_planning_subtree/minebot_mining,
|
||||
/datum/ai_planning_subtree/locate_dead_humans,
|
||||
)
|
||||
ai_traits = PAUSE_DURING_DO_AFTER
|
||||
|
||||
/datum/ai_planning_subtree/launch_missiles
|
||||
|
||||
/datum/ai_planning_subtree/launch_missiles/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/datum/action/cooldown/missile_ability = controller.blackboard[BB_MINEBOT_MISSILE_ABILITY]
|
||||
if(!missile_ability?.IsAvailable())
|
||||
return
|
||||
if(!controller.blackboard_key_exists(BB_MINEBOT_MISSILE_TARGET))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/clear_bombing_zone, BB_MINEBOT_MISSILE_TARGET, /obj/effect/temp_visual/minebot_target, 7)
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_clear_target, BB_MINEBOT_MISSILE_ABILITY, BB_MINEBOT_MISSILE_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_behavior/find_and_set/clear_bombing_zone
|
||||
|
||||
/datum/ai_behavior/find_and_set/clear_bombing_zone/search_tactic(datum/ai_controller/controller, locate_path, search_range)
|
||||
for(var/obj/effect/temp_visual/minebot_target/target in oview(search_range, controller.pawn))
|
||||
if(isclosedturf(get_turf(target)))
|
||||
continue
|
||||
return target
|
||||
return null
|
||||
|
||||
/datum/ai_planning_subtree/befriend_miners/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(!controller.blackboard_key_exists(BB_MINER_FRIEND))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/miner_to_befriend, BB_MINER_FRIEND)
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/befriend_target, BB_MINER_FRIEND)
|
||||
|
||||
/datum/ai_behavior/find_and_set/miner_to_befriend
|
||||
|
||||
/datum/ai_behavior/find_and_set/miner_to_befriend/search_tactic(datum/ai_controller/controller, locate_path, search_range)
|
||||
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
|
||||
if(HAS_TRAIT(target, TRAIT_ROCK_STONER))
|
||||
return target
|
||||
return null
|
||||
|
||||
/datum/ai_planning_subtree/defend_node/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/mob/living/target = controller.blackboard[BB_DRONE_DEFEND]
|
||||
if(QDELETED(target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set, BB_DRONE_DEFEND, /mob/living/basic/node_drone)
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(!living_pawn.faction.Find(REF(target)))
|
||||
controller.queue_behavior(/datum/ai_behavior/befriend_target, BB_DRONE_DEFEND)
|
||||
return
|
||||
if(target.health < (target.maxHealth * 0.75) && controller.blackboard[BB_MINEBOT_REPAIR_DRONE])
|
||||
controller.queue_behavior(/datum/ai_behavior/repair_drone, BB_DRONE_DEFEND)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_behavior/repair_drone
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION | AI_BEHAVIOR_REQUIRE_REACH
|
||||
|
||||
/datum/ai_behavior/repair_drone/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/turf/target = controller.blackboard[target_key]
|
||||
if(isnull(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/repair_drone/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
living_pawn.say("REPAIRING [target]!")
|
||||
living_pawn.UnarmedAttack(target)
|
||||
finish_action(controller, TRUE, target_key)
|
||||
|
||||
/datum/ai_behavior/repair_drone/finish_action(datum/ai_controller/controller, success, target_key)
|
||||
. = ..()
|
||||
if(!success)
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
///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)
|
||||
@@ -28,6 +112,7 @@
|
||||
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
|
||||
if(target.stat >= UNCONSCIOUS && target.mind)
|
||||
return target
|
||||
return null
|
||||
|
||||
/datum/ai_behavior/send_sos_message
|
||||
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
@@ -58,16 +143,51 @@
|
||||
operational_datums = null
|
||||
ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/minebot
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/minebot
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
|
||||
avoid_friendly_fire = TRUE
|
||||
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(!living_pawn.combat_mode) //we are not on attack mode
|
||||
return
|
||||
controller.queue_behavior(ranged_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_planning_subtree/minebot_maintain_distance/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(get_dist(living_pawn, target) <= controller.blackboard[BB_MINIMUM_SHOOTING_DISTANCE])
|
||||
controller.queue_behavior(/datum/ai_behavior/run_away_from_target/run_and_shoot/minebot, BB_BASIC_MOB_CURRENT_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/run_and_shoot/minebot
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/run_and_shoot/minebot/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
|
||||
if(!controller.blackboard[BB_MINEBOT_PLANT_MINES])
|
||||
return ..()
|
||||
var/datum/action/cooldown/mine_ability = controller.blackboard[BB_MINEBOT_LANDMINE_ABILITY]
|
||||
mine_ability?.Trigger()
|
||||
return ..()
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/minebot
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
avoid_friendly_fire = TRUE
|
||||
///if our target is closer than this distance, finish action
|
||||
var/minimum_distance = 3
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/minebot/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key)
|
||||
. = ..()
|
||||
minimum_distance = controller.blackboard[BB_MINIMUM_SHOOTING_DISTANCE] ? controller.blackboard[BB_MINIMUM_SHOOTING_DISTANCE] : initial(minimum_distance)
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
finish_action(controller, target_key, FALSE)
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
if(get_dist(living_pawn, target) <= minimum_distance)
|
||||
finish_action(controller, target_key, TRUE)
|
||||
|
||||
///mine walls if we are on automated mining mode
|
||||
/datum/ai_planning_subtree/minebot_mining/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(!controller.blackboard[BB_AUTOMATED_MINING])
|
||||
@@ -216,3 +336,19 @@
|
||||
/datum/pet_command/idle/minebot/execute_action(datum/ai_controller/controller)
|
||||
controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE)
|
||||
return ..()
|
||||
|
||||
/datum/pet_command/protect_owner/minebot
|
||||
|
||||
/datum/pet_command/protect_owner/minebot/set_command_target(mob/living/parent, atom/target)
|
||||
if(!parent.ai_controller.blackboard[BB_MINEBOT_AUTO_DEFEND])
|
||||
return
|
||||
if(!parent.ai_controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET) && !QDELETED(target)) //we are already dealing with something,
|
||||
parent.ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, target)
|
||||
|
||||
/datum/pet_command/protect_owner/minebot/execute_action(datum/ai_controller/controller)
|
||||
if(controller.blackboard[BB_MINEBOT_AUTO_DEFEND])
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
living_pawn.set_combat_mode(TRUE)
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#define BOMB_COOLDOWN 20 SECONDS
|
||||
/obj/item/minebot_remote_control
|
||||
name = "Remote Control"
|
||||
desc = "Requesting stratagem!"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "minebot_bomb_control"
|
||||
item_flags = NOBLUDGEON
|
||||
///are we currently primed to drop a bomb?
|
||||
var/primed = FALSE
|
||||
///our last user
|
||||
var/datum/weakref/last_user
|
||||
///cooldown till we can drop the next bomb
|
||||
COOLDOWN_DECLARE(bomb_timer)
|
||||
|
||||
/obj/item/minebot_remote_control/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
|
||||
. = ..()
|
||||
clear_priming()
|
||||
|
||||
/obj/item/minebot_remote_control/proc/clear_priming()
|
||||
var/mob/living/living_user = last_user?.resolve()
|
||||
last_user = null
|
||||
primed = FALSE
|
||||
if(isnull(living_user))
|
||||
return
|
||||
living_user.client?.mouse_override_icon = initial(living_user.client?.mouse_override_icon)
|
||||
living_user.update_mouse_pointer()
|
||||
|
||||
/obj/item/minebot_remote_control/attack_self(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return .
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, bomb_timer))
|
||||
balloon_alert(user, "on cooldown!")
|
||||
return TRUE
|
||||
|
||||
prime_bomb(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/minebot_remote_control/proc/prime_bomb(mob/user)
|
||||
primed = TRUE
|
||||
last_user = WEAKREF(user)
|
||||
user.client?.mouse_override_icon = 'icons/effects/mouse_pointers/weapon_pointer.dmi'
|
||||
user.update_mouse_pointer()
|
||||
|
||||
/obj/item/minebot_remote_control/afterattack(atom/attacked_atom, mob/living/user, proximity)
|
||||
. = ..()
|
||||
|
||||
. |= AFTERATTACK_PROCESSED_ITEM
|
||||
|
||||
if(!primed)
|
||||
user.balloon_alert(user, "not primed!")
|
||||
return
|
||||
var/turf/target_turf = get_turf(attacked_atom)
|
||||
if(isnull(target_turf) || isclosedturf(target_turf) || isgroundlessturf(target_turf))
|
||||
user.balloon_alert(user, "invalid target!")
|
||||
return
|
||||
playsound(src, 'sound/machines/beep.ogg', 30)
|
||||
clear_priming()
|
||||
new /obj/effect/temp_visual/minebot_target(target_turf)
|
||||
COOLDOWN_START(src, bomb_timer, BOMB_COOLDOWN)
|
||||
|
||||
/obj/effect/temp_visual/minebot_target
|
||||
name = "Rocket Target"
|
||||
icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
layer = BELOW_MOB_LAYER
|
||||
plane = GAME_PLANE
|
||||
light_range = 2
|
||||
duration = 5 SECONDS
|
||||
|
||||
#undef BOMB_COOLDOWN
|
||||
@@ -3,6 +3,7 @@
|
||||
desc = "A minebot upgrade."
|
||||
icon_state = "door_electronics"
|
||||
icon = 'icons/obj/devices/circuitry_n_data.dmi'
|
||||
item_flags = NOBLUDGEON
|
||||
|
||||
/obj/item/mine_bot_upgrade/afterattack(mob/living/basic/mining_drone/minebot, mob/user, proximity)
|
||||
. = ..()
|
||||
@@ -58,3 +59,35 @@
|
||||
minebot.melee_damage_lower = initial(minebot.melee_damage_lower) + base_damage_add
|
||||
minebot.melee_damage_upper = initial(minebot.melee_damage_upper) + base_damage_add
|
||||
minebot.stored_gun?.recharge_time += base_cooldown_add
|
||||
|
||||
/obj/item/mine_bot_upgrade/regnerative_shield
|
||||
name = "regenerative shield"
|
||||
desc = "Allows your minebot to tank many hits before going down!"
|
||||
|
||||
/obj/item/mine_bot_upgrade/regnerative_shield/upgrade_bot(mob/living/basic/mining_drone/minebot, mob/user)
|
||||
if(HAS_TRAIT(minebot, TRAIT_REGEN_SHIELD))
|
||||
user.balloon_alert(minebot, "already has it!")
|
||||
return
|
||||
var/static/list/shield_layers = list(
|
||||
/obj/effect/overlay/minebot_top_shield,
|
||||
/obj/effect/overlay/minebot_bottom_shield
|
||||
)
|
||||
minebot.AddComponent(/datum/component/regenerative_shield, shield_overlays = shield_layers)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/overlay/minebot_top_shield
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
vis_flags = VIS_INHERIT_DIR
|
||||
icon = 'icons/mob/silicon/aibots.dmi'
|
||||
icon_state = "minebot_shield_top_layer"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
|
||||
/obj/effect/overlay/minebot_bottom_shield
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
vis_flags = VIS_INHERIT_DIR
|
||||
icon = 'icons/mob/silicon/aibots.dmi'
|
||||
icon_state = "minebot_shield_bottom_layer"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
|
||||
Reference in New Issue
Block a user