[MIRROR] minebots basic bots [MDB IGNORE] (#23529)

* minebots basic bots (#78032)

## About The Pull Request
Transforms the minebots into basic robots. You can now command these
minebots to extract minerals for you. To activate automated mining mode,
simply instruct them with the command "mine." They will then proceed to
autonomously mine walls and gather ores. If you wish to make the bot
deposit all the collected ores, use the command "drop." Alternatively,
you can leave it in collection mode, and it will gather all the ores you
mine. Additionally, the bot now responds to several more commands; you
can instruct it to follow you, toggle its lights on or off by saying
"lights." In attack mode, it refrains from mining or collecting ores but
will engage in combat alongside you. If it detects you as deceased or
unconscious, it will alert all miners, request assistance, and relay
your coordinates via the mining communication channel. to power it on u
will need to feed it any type of ore first so it may listen to ur
commands

## Why It's Good For The Game
makes the non sapiant minebots more useful

## Changelog
🆑
refactor: the minebots have been refactored please report any bugs
add: minebots can now mine walls and collect ores automatically and they
will alert everyone if they find u dead
/🆑

* minebots basic bots

* Modular

---------

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:
SkyratBot
2023-09-05 12:46:11 +02:00
committed by GitHub
parent 7ae8d9ad22
commit 18b0abe4b3
21 changed files with 612 additions and 387 deletions
@@ -131,40 +131,6 @@
controller.queue_behavior(/datum/ai_behavior/mine_wall, BB_TARGET_MINERAL_WALL)
return SUBTREE_RETURN_FINISH_PLANNING
/datum/ai_behavior/find_mineral_wall
/datum/ai_behavior/find_mineral_wall/perform(seconds_per_tick, datum/ai_controller/controller, found_wall_key)
. = ..()
var/mob/living_pawn = controller.pawn
for(var/turf/closed/mineral/potential_wall in oview(9, living_pawn))
if(!check_if_mineable(living_pawn, potential_wall)) //check if its surrounded by walls
continue
controller.set_blackboard_key(found_wall_key, potential_wall) //closest wall first!
finish_action(controller, TRUE)
return
finish_action(controller, FALSE)
/datum/ai_behavior/find_mineral_wall/proc/check_if_mineable(mob/living/source, turf/target_wall)
var/direction_to_turf = get_dir(target_wall, source)
if(!ISDIAGONALDIR(direction_to_turf))
return TRUE
var/list/directions_to_check = list()
for(var/direction_check in GLOB.cardinals)
if(direction_check & direction_to_turf)
directions_to_check += direction_check
for(var/direction in directions_to_check)
var/turf/test_turf = get_step(target_wall, direction)
if(isnull(test_turf))
continue
if(!test_turf.is_blocked_turf(ignore_atoms = list(source)))
return TRUE
return FALSE
/datum/ai_behavior/mine_wall
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
action_cooldown = 15 SECONDS
@@ -0,0 +1,175 @@
/mob/living/basic/mining_drone
name = "\improper Nanotrasen minebot"
desc = "The instructions printed on the side read: This is a small robot used to support miners, can be set to search and collect loose ore, or to help fend off wildlife. Insert any type of ore into it to make it start listening to your commands!"
gender = NEUTER
icon = 'icons/mob/silicon/aibots.dmi'
icon_state = "mining_drone"
icon_living = "mining_drone"
basic_mob_flags = DEL_ON_DEATH
status_flags = CANSTUN|CANKNOCKDOWN|CANPUSH
mouse_opacity = MOUSE_OPACITY_ICON
combat_mode = TRUE
habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minimum_survivable_temperature = 0
health = 125
maxHealth = 125
melee_damage_lower = 15
melee_damage_upper = 15
obj_damage = 10
attack_verb_continuous = "drills"
attack_verb_simple = "drill"
attack_sound = 'sound/weapons/circsawhit.ogg'
sentience_type = SENTIENCE_MINEBOT
speak_emote = list("states")
mob_biotypes = MOB_ROBOTIC
death_message = "blows apart!"
light_system = MOVABLE_LIGHT
light_range = 6
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
///the commands our owner can give us
var/list/pet_commands = list(
/datum/pet_command/idle/minebot,
/datum/pet_command/minebot_ability/light,
/datum/pet_command/minebot_ability/dump,
/datum/pet_command/automate_mining,
/datum/pet_command/free/minebot,
/datum/pet_command/follow,
/datum/pet_command/point_targetting/attack/minebot,
)
/mob/living/basic/mining_drone/Initialize(mapload)
. = ..()
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,\
after_tame = CALLBACK(src, PROC_REF(activate_bot)),\
)
var/datum/action/cooldown/mob_cooldown/minedrone/toggle_light/toggle_light_action = new(src)
var/datum/action/cooldown/mob_cooldown/minedrone/toggle_meson_vision/toggle_meson_vision_action = new(src)
var/datum/action/cooldown/mob_cooldown/minedrone/dump_ore/dump_ore_action = new(src)
toggle_light_action.Grant(src)
toggle_meson_vision_action.Grant(src)
dump_ore_action.Grant(src)
ai_controller.set_blackboard_key(BB_MINEBOT_LIGHT_ABILITY, toggle_light_action)
ai_controller.set_blackboard_key(BB_MINEBOT_DUMP_ABILITY, dump_ore_action)
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))
/mob/living/basic/mining_drone/set_combat_mode(new_mode, silent = TRUE)
. = ..()
icon_state = combat_mode ? "mining_drone_offense" : "mining_drone"
balloon_alert(src, "now [combat_mode ? "attacking" : "collecting"]")
/mob/living/basic/mining_drone/examine(mob/user)
. = ..()
if(health < maxHealth)
if(health >= maxHealth * 0.5)
. += span_warning("[p_They()] look slightly dented.")
else
. += span_boldwarning("[p_They()] look severely dented!")
if(isnull(stored_gun) || !stored_gun.max_mod_capacity)
return
. += "<b>[stored_gun.get_remaining_mod_capacity()]%</b> mod capacity remaining."
for(var/obj/item/borg/upgrade/modkit/modkit as anything in stored_gun.modkits)
. += span_notice("There is \a [modkit] installed, using <b>[modkit.cost]%</b> capacity.")
/mob/living/basic/mining_drone/welder_act(mob/living/user, obj/item/welder)
if(user.combat_mode)
return FALSE
if(combat_mode)
user.balloon_alert(user, "can't repair in attack mode!")
return TRUE
if(maxHealth == health)
user.balloon_alert(user, "at full integrity!")
return TRUE
if(welder.use_tool(src, user, 0, volume=40))
adjustBruteLoss(-15)
user.balloon_alert(user, "successfully repaired!")
return TRUE
/mob/living/basic/mining_drone/attackby(obj/item/item_used, mob/user, params)
if(item_used.tool_behaviour == TOOL_CROWBAR || istype(item_used, /obj/item/borg/upgrade/modkit))
item_used.melee_attack_chain(user, stored_gun, params)
return
return ..()
/mob/living/basic/mining_drone/attack_hand(mob/living/carbon/human/user, list/modifiers)
. = ..()
if(. || user.combat_mode)
return
set_combat_mode(!combat_mode)
balloon_alert(user, "now [combat_mode ? "attacking wildlife" : "collecting loose ore"]")
/mob/living/basic/mining_drone/RangedAttack(atom/target)
if(!combat_mode)
return
stored_gun.afterattack(target, src)
/mob/living/basic/mining_drone/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
. = ..()
if(!. || !proximity_flag || combat_mode)
return
if(istype(attack_target, /obj/item/stack/ore))
var/obj/item/target_ore = attack_target
target_ore.forceMove(src)
/mob/living/basic/mining_drone/proc/drop_ore()
to_chat(src, span_notice("You dump your stored ore."))
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/proc/activate_bot()
AddComponent(/datum/component/obeys_commands, pet_commands)
/mob/living/basic/mining_drone/death(gibbed)
drop_ore()
if(isnull(stored_gun))
return ..()
for(var/obj/item/borg/upgrade/modkit/modkit as anything in stored_gun.modkits)
modkit.uninstall(stored_gun)
return ..()
/mob/living/basic/mining_drone/Destroy()
QDEL_NULL(stored_gun)
QDEL_NULL(access_card)
return ..()
@@ -0,0 +1,51 @@
/datum/action/cooldown/mob_cooldown/minedrone
button_icon = 'icons/mob/actions/actions_mecha.dmi'
background_icon_state = "bg_default"
overlay_icon_state = "bg_default_border"
click_to_activate = FALSE
/datum/action/cooldown/mob_cooldown/minedrone/toggle_light
name = "Toggle Light"
button_icon_state = "mech_lights_off"
/datum/action/cooldown/mob_cooldown/minedrone/Activate()
owner.set_light_on(!owner.light_on)
owner.balloon_alert(owner, "lights [owner.light_on ? "on" : "off"]!")
/datum/action/cooldown/mob_cooldown/minedrone/dump_ore
name = "Dump Ore"
button_icon_state = "mech_eject"
/datum/action/cooldown/mob_cooldown/minedrone/dump_ore/IsAvailable(feedback = TRUE)
if(locate(/obj/item/stack/ore) in owner.contents)
return TRUE
if(feedback)
owner.balloon_alert(owner, "no ore!")
return FALSE
/datum/action/cooldown/mob_cooldown/minedrone/dump_ore/Activate()
var/mob/living/basic/mining_drone/user = owner
user.drop_ore()
/datum/action/cooldown/mob_cooldown/minedrone/toggle_meson_vision
name = "Toggle Meson Vision"
button_icon_state = "meson"
/datum/action/cooldown/mob_cooldown/minedrone/toggle_meson_vision/Activate()
if(owner.sight & SEE_TURFS)
owner.clear_sight(SEE_TURFS)
owner.lighting_cutoff_red += 5
owner.lighting_cutoff_green += 15
owner.lighting_cutoff_blue += 5
else
owner.add_sight(SEE_TURFS)
owner.lighting_cutoff_red -= 5
owner.lighting_cutoff_green -= 15
owner.lighting_cutoff_blue -= 5
owner.sync_lighting_plane_cutoff()
to_chat(owner, span_notice("You toggle your meson vision [(owner.sight & SEE_TURFS) ? "on" : "off"]."))
@@ -0,0 +1,227 @@
/datum/ai_controller/basic_controller/minebot
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/not_friends,
BB_BLACKLIST_MINERAL_TURFS = list(/turf/closed/mineral/gibtonite),
BB_AUTOMATED_MINING = FALSE,
)
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/pet_planning,
/datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot,
/datum/ai_planning_subtree/find_and_hunt_target/consume_ores/minebot,
/datum/ai_planning_subtree/minebot_mining,
/datum/ai_planning_subtree/locate_dead_humans,
)
///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
/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))
if(target.stat >= UNCONSCIOUS && target.mind)
return target
/datum/ai_behavior/send_sos_message
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
action_cooldown = 2 MINUTES
/datum/ai_behavior/send_sos_message/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
. = ..()
var/mob/living/carbon/target = controller.blackboard[target_key]
var/mob/living/living_pawn = controller.pawn
if(QDELETED(target) || is_station_level(target.z))
finish_action(controller, FALSE, target_key)
return
var/turf/target_turf = get_turf(target)
var/obj/item/implant/radio/radio_implant = locate(/obj/item/implant/radio) in living_pawn.contents
if(!radio_implant)
finish_action(controller, FALSE, target_key)
return
var/message = "ALERT, [target] in need of help at coordinates: [target_turf.x], [target_turf.y], [target_turf.z]!"
radio_implant.radio.talk_into(living_pawn, message, RADIO_CHANNEL_SUPPLY)
finish_action(controller, TRUE, target_key)
/datum/ai_behavior/send_sos_message/finish_action(datum/ai_controller/controller, success, target_key)
. = ..()
controller.clear_blackboard_key(target_key)
///operational datums is null because we dont use a ranged component, we use a gun in our contents
/datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot
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
/datum/ai_planning_subtree/basic_ranged_attack_subtree/minebot/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(!living_pawn.combat_mode) //we are not on attack mode
return
return ..()
///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)
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
/datum/ai_behavior/find_mineral_wall/minebot
/datum/ai_behavior/find_mineral_wall/minebot/check_if_mineable(datum/ai_controller/controller, turf/target_wall)
var/list/forbidden_turfs = controller.blackboard[BB_BLACKLIST_MINERAL_TURFS]
var/turf/previous_unreachable_wall = controller.blackboard[BB_PREVIOUS_UNREACHABLE_WALL]
if(is_type_in_list(target_wall, forbidden_turfs) || target_wall == previous_unreachable_wall)
return FALSE
controller.clear_blackboard_key(BB_PREVIOUS_UNREACHABLE_WALL)
return ..()
/datum/ai_behavior/minebot_mine_turf
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
required_distance = 2
action_cooldown = 3 SECONDS
/datum/ai_behavior/minebot_mine_turf/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/minebot_mine_turf/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
. = ..()
var/mob/living/basic/living_pawn = controller.pawn
var/turf/target = controller.blackboard[target_key]
if(QDELETED(target))
finish_action(controller, FALSE, target_key)
return
if(check_obstacles_in_path(controller, target))
finish_action(controller, FALSE, target_key)
return
if(!living_pawn.combat_mode)
living_pawn.set_combat_mode(TRUE)
living_pawn.RangedAttack(target)
finish_action(controller, TRUE, target_key)
return
/datum/ai_behavior/minebot_mine_turf/proc/check_obstacles_in_path(datum/ai_controller/controller, turf/target)
var/mob/living/source = controller.pawn
var/list/turfs_in_path = get_line(source, target) - target
for(var/turf/turf in turfs_in_path)
if(turf.is_blocked_turf(ignore_atoms = list(source)))
controller.set_blackboard_key(BB_PREVIOUS_UNREACHABLE_WALL, target)
return TRUE
return FALSE
/datum/ai_behavior/minebot_mine_turf/finish_action(datum/ai_controller/controller, success, target_key)
. = ..()
controller.clear_blackboard_key(target_key)
///store ores in our body
/datum/ai_planning_subtree/find_and_hunt_target/consume_ores/minebot
hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/consume_ores/minebot
hunt_chance = 100
/datum/ai_planning_subtree/find_and_hunt_target/consume_ores/minebot/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/automated_mining = controller.blackboard[BB_AUTOMATED_MINING]
var/mob/living/living_pawn = controller.pawn
if(!automated_mining && living_pawn.combat_mode) //are we not on automated mining or collect mode?
return
return ..()
/datum/ai_behavior/hunt_target/unarmed_attack_target/consume_ores/minebot
hunt_cooldown = 2 SECONDS
/datum/ai_behavior/hunt_target/unarmed_attack_target/consume_ores/minebot/target_caught(mob/living/hunter, obj/item/stack/ore/hunted)
if(hunter.combat_mode)
hunter.set_combat_mode(FALSE)
return ..()
///pet commands
/datum/pet_command/free/minebot
/datum/pet_command/free/minebot/execute_action(datum/ai_controller/controller)
controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE)
return ..()
/datum/pet_command/automate_mining
command_name = "Automate mining"
command_desc = "Make your minebot automatically mine!"
radial_icon = 'icons/obj/mining.dmi'
radial_icon_state = "pickaxe"
speech_commands = list("mine")
/datum/pet_command/automate_mining/execute_action(datum/ai_controller/controller)
controller.set_blackboard_key(BB_AUTOMATED_MINING, TRUE)
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
/datum/pet_command/minebot_ability
command_name = "Minebot ability"
command_desc = "Make your minebot use one of its abilities."
radial_icon = 'icons/mob/actions/actions_mecha.dmi'
///the ability we will use
var/ability_key
/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())
return
controller.queue_behavior(/datum/ai_behavior/use_mob_ability, ability_key)
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
return SUBTREE_RETURN_FINISH_PLANNING
/datum/pet_command/minebot_ability/light
command_name = "Toggle lights"
command_desc = "Make your minebot toggle its lights."
speech_commands = list("light")
radial_icon_state = "mech_lights_off"
ability_key = BB_MINEBOT_LIGHT_ABILITY
/datum/pet_command/minebot_ability/dump
command_name = "Dump ore"
command_desc = "Make your minebot dump all its ore!"
speech_commands = list("dump", "ore")
radial_icon_state = "mech_eject"
ability_key = BB_MINEBOT_DUMP_ABILITY
/datum/pet_command/point_targetting/attack/minebot
attack_behaviour = /datum/ai_behavior/basic_ranged_attack/minebot
/datum/pet_command/point_targetting/attack/minebot/execute_action(datum/ai_controller/controller)
controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE)
var/mob/living/living_pawn = controller.pawn
if(!living_pawn.combat_mode)
living_pawn.set_combat_mode(TRUE)
return ..()
/datum/pet_command/idle/minebot
/datum/pet_command/idle/minebot/execute_action(datum/ai_controller/controller)
controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE)
return ..()
@@ -0,0 +1,60 @@
/obj/item/mine_bot_upgrade
name = "minebot melee upgrade"
desc = "A minebot upgrade."
icon_state = "door_electronics"
icon = 'icons/obj/assemblies/module.dmi'
/obj/item/mine_bot_upgrade/afterattack(mob/living/basic/mining_drone/minebot, mob/user, proximity)
. = ..()
if(!istype(minebot) || !proximity)
return
upgrade_bot(minebot, user)
/obj/item/mine_bot_upgrade/proc/upgrade_bot(mob/living/basic/mining_drone/minebot, mob/user)
if(minebot.melee_damage_upper != initial(minebot.melee_damage_upper))
user.balloon_alert(user, "already has armor!")
return
minebot.melee_damage_lower += 7
minebot.melee_damage_upper += 7
to_chat(user, span_notice("You increase the close-quarter combat abilities of [minebot]."))
qdel(src)
//Health
/obj/item/mine_bot_upgrade/health
name = "minebot armor upgrade"
/obj/item/mine_bot_upgrade/health/upgrade_bot(mob/living/basic/mining_drone/minebot, mob/user)
if(minebot.maxHealth != initial(minebot.maxHealth))
to_chat(user, span_warning("[minebot] already has reinforced armor!"))
return
minebot.maxHealth += 45
minebot.updatehealth()
to_chat(user, span_notice("You reinforce the armor of [minebot]."))
qdel(src)
//AI
/obj/item/slimepotion/slime/sentience/mining
name = "minebot AI upgrade"
desc = "Can be used to grant sentience to minebots. It's incompatible with minebot armor and melee upgrades, and will override them."
icon_state = "door_electronics"
icon = 'icons/obj/assemblies/module.dmi'
sentience_type = SENTIENCE_MINEBOT
///health boost to add
var/base_health_add = 5
///damage boost to add
var/base_damage_add = 1
///speed boost to add
var/base_speed_add = 1
///cooldown boost to add
var/base_cooldown_add = 10
/obj/item/slimepotion/slime/sentience/mining/after_success(mob/living/user, mob/living/basic_mob)
if(!istype(basic_mob, /mob/living/basic/mining_drone))
return
var/mob/living/basic/mining_drone/minebot = basic_mob
minebot.maxHealth = initial(minebot.maxHealth) + base_health_add
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
@@ -247,4 +247,4 @@
return ..()
/datum/pet_command/protect_owner/glockroach
protect_behavior = /datum/ai_planning_subtree/basic_ranged_attack_subtree/glockroach
protect_behavior = /datum/ai_behavior/basic_ranged_attack/glockroach