[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
-331
View File
@@ -1,331 +0,0 @@
/**********************Mining drone**********************/
#define MINEDRONE_COLLECT 1
#define MINEDRONE_ATTACK 2
/mob/living/simple_animal/hostile/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."
gender = NEUTER
icon = 'icons/mob/silicon/aibots.dmi'
icon_state = "mining_drone"
icon_living = "mining_drone"
status_flags = CANSTUN|CANKNOCKDOWN|CANPUSH
mouse_opacity = MOUSE_OPACITY_ICON
faction = list(FACTION_NEUTRAL)
combat_mode = TRUE
atmos_requirements = 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)
minbodytemp = 0
move_to_delay = 10
health = 125
maxHealth = 125
melee_damage_lower = 15
melee_damage_upper = 15
obj_damage = 10
environment_smash = ENVIRONMENT_SMASH_NONE
check_friendly_fire = TRUE
stop_automated_movement_when_pulled = TRUE
attack_verb_continuous = "drills"
attack_verb_simple = "drill"
attack_sound = 'sound/weapons/circsawhit.ogg'
sentience_type = SENTIENCE_MINEBOT
speak_emote = list("states")
wanted_objects = list(/obj/item/stack/ore/diamond, /obj/item/stack/ore/gold, /obj/item/stack/ore/silver,
/obj/item/stack/ore/plasma, /obj/item/stack/ore/uranium, /obj/item/stack/ore/iron,
/obj/item/stack/ore/bananium, /obj/item/stack/ore/titanium)
mob_biotypes = MOB_ROBOTIC
loot = list(/obj/effect/decal/cleanable/robot_debris)
del_on_death = TRUE
light_system = MOVABLE_LIGHT
light_range = 6
light_on = FALSE
var/mode = MINEDRONE_COLLECT
var/obj/item/gun/energy/recharge/kinetic_accelerator/minebot/stored_gun
/mob/living/simple_animal/hostile/mining_drone/Initialize(mapload)
. = ..()
AddElement(/datum/element/footstep, FOOTSTEP_OBJ_ROBOT, 1, -6, sound_vary = TRUE)
stored_gun = new(src)
var/datum/action/innate/minedrone/toggle_light/toggle_light_action = new()
toggle_light_action.Grant(src)
var/datum/action/innate/minedrone/toggle_meson_vision/toggle_meson_vision_action = new()
toggle_meson_vision_action.Grant(src)
var/datum/action/innate/minedrone/toggle_mode/toggle_mode_action = new()
toggle_mode_action.Grant(src)
var/datum/action/innate/minedrone/dump_ore/dump_ore_action = new()
dump_ore_action.Grant(src)
var/obj/item/implant/radio/mining/imp = new(src)
imp.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)
SetCollectBehavior()
/mob/living/simple_animal/hostile/mining_drone/Destroy()
QDEL_NULL(stored_gun)
for (var/datum/action/innate/minedrone/action in actions)
qdel(action)
return ..()
/mob/living/simple_animal/hostile/mining_drone/sentience_act()
..()
check_friendly_fire = 0
/mob/living/simple_animal/hostile/mining_drone/examine(mob/user)
. = ..()
var/t_He = p_They()
var/t_him = p_them()
var/t_s = p_s()
if(health < maxHealth)
if(health >= maxHealth * 0.5)
. += span_warning("[t_He] look[t_s] slightly dented.")
else
. += span_boldwarning("[t_He] look[t_s] severely dented!")
. += {"<span class='notice'>Using a mining scanner on [t_him] will instruct [t_him] to drop stored ore. <b>[max(0, LAZYLEN(contents) - 1)] Stored Ore</b>\n
Field repairs can be done with a welder."}
if(stored_gun?.max_mod_capacity)
. += "<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/simple_animal/hostile/mining_drone/welder_act(mob/living/user, obj/item/welder)
..()
. = TRUE
if(mode == MINEDRONE_ATTACK)
to_chat(user, span_warning("[src] can't be repaired while in attack mode!"))
return
if(maxHealth == health)
to_chat(user, span_info("[src] is at full integrity."))
return
if(welder.use_tool(src, user, 0, volume=40))
adjustBruteLoss(-15)
to_chat(user, span_info("You repair some of the armor on [src]."))
/mob/living/simple_animal/hostile/mining_drone/attackby(obj/item/item_used, mob/user, params)
if(istype(item_used, /obj/item/mining_scanner) || istype(item_used, /obj/item/t_scanner/adv_mining_scanner))
to_chat(user, span_info("You instruct [src] to drop any collected ore."))
DropOre()
return
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
..()
/mob/living/simple_animal/hostile/mining_drone/death()
DropOre()
if(stored_gun)
for(var/obj/item/borg/upgrade/modkit/modkit as anything in stored_gun.modkits)
modkit.uninstall(stored_gun)
death_message = "blows apart!"
..()
/mob/living/simple_animal/hostile/mining_drone/attack_hand(mob/living/carbon/human/user, list/modifiers)
. = ..()
if(.)
return
if(!user.combat_mode)
toggle_mode()
switch(mode)
if(MINEDRONE_COLLECT)
to_chat(user, span_info("[src] has been set to search and store loose ore."))
if(MINEDRONE_ATTACK)
to_chat(user, span_info("[src] has been set to attack hostile wildlife."))
return
/mob/living/simple_animal/hostile/mining_drone/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
if(istype(mover, /obj/projectile/kinetic))
var/obj/projectile/kinetic/projectile = mover
if(projectile.kinetic_gun)
if (locate(/obj/item/borg/upgrade/modkit/minebot_passthrough) in projectile.kinetic_gun.modkits)
return TRUE
else if(istype(mover, /obj/projectile/destabilizer))
return TRUE
/mob/living/simple_animal/hostile/mining_drone/proc/SetCollectBehavior()
mode = MINEDRONE_COLLECT
vision_range = 9
search_objects = 2
wander = TRUE
ranged = FALSE
minimum_distance = 1
retreat_distance = null
icon_state = "mining_drone"
to_chat(src, span_info("You are set to collect mode. You can now collect loose ore."))
/mob/living/simple_animal/hostile/mining_drone/proc/SetOffenseBehavior()
mode = MINEDRONE_ATTACK
vision_range = 7
search_objects = 0
wander = FALSE
ranged = TRUE
retreat_distance = 2
minimum_distance = 1
icon_state = "mining_drone_offense"
to_chat(src, span_info("You are set to attack mode. You can now attack from range."))
/mob/living/simple_animal/hostile/mining_drone/AttackingTarget()
if(istype(target, /obj/item/stack/ore) && mode == MINEDRONE_COLLECT)
CollectOre()
return
if(isliving(target))
SetOffenseBehavior()
return ..()
/mob/living/simple_animal/hostile/mining_drone/OpenFire(atom/target)
if(CheckFriendlyFire(target))
return
stored_gun.afterattack(target, src) //of the possible options to allow minebots to have KA mods, would you believe this is the best?
/mob/living/simple_animal/hostile/mining_drone/proc/CollectOre()
for(var/obj/item/stack/ore/O in range(1, src))
O.forceMove(src)
/mob/living/simple_animal/hostile/mining_drone/proc/DropOre(message = 1)
if(!contents.len)
if(message)
to_chat(src, span_warning("You attempt to dump your stored ore, but you have none!"))
return
if(message)
to_chat(src, span_notice("You dump your stored ore."))
for(var/obj/item/stack/ore/O in contents)
O.forceMove(drop_location())
/mob/living/simple_animal/hostile/mining_drone/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(mode != MINEDRONE_ATTACK && amount > 0)
SetOffenseBehavior()
. = ..()
/datum/action/innate/minedrone/toggle_meson_vision
name = "Toggle Meson Vision"
button_icon_state = "meson"
/datum/action/innate/minedrone/toggle_meson_vision/Activate()
var/mob/living/simple_animal/hostile/mining_drone/user = owner
if(user.sight & SEE_TURFS)
user.clear_sight(SEE_TURFS)
user.lighting_cutoff_red += 5
user.lighting_cutoff_green += 15
user.lighting_cutoff_blue += 5
else
user.add_sight(SEE_TURFS)
user.lighting_cutoff_red -= 5
user.lighting_cutoff_green -= 15
user.lighting_cutoff_blue -= 5
user.sync_lighting_plane_cutoff()
to_chat(user, span_notice("You toggle your meson vision [(user.sight & SEE_TURFS) ? "on" : "off"]."))
/mob/living/simple_animal/hostile/mining_drone/proc/toggle_mode()
switch(mode)
if(MINEDRONE_ATTACK)
SetCollectBehavior()
else
SetOffenseBehavior()
//Actions for sentient minebots
/datum/action/innate/minedrone
check_flags = AB_CHECK_CONSCIOUS
button_icon = 'icons/mob/actions/actions_mecha.dmi'
background_icon_state = "bg_default"
overlay_icon_state = "bg_default_border"
/datum/action/innate/minedrone/toggle_light
name = "Toggle Light"
button_icon_state = "mech_lights_off"
/datum/action/innate/minedrone/toggle_light/Activate()
var/mob/living/simple_animal/hostile/mining_drone/user = owner
user.set_light_on(!user.light_on)
to_chat(user, span_notice("You toggle your light [user.light_on ? "on" : "off"]."))
/datum/action/innate/minedrone/toggle_mode
name = "Toggle Mode"
button_icon_state = "mech_cycle_equip_off"
/datum/action/innate/minedrone/toggle_mode/Activate()
var/mob/living/simple_animal/hostile/mining_drone/user = owner
user.toggle_mode()
/datum/action/innate/minedrone/dump_ore
name = "Dump Ore"
button_icon_state = "mech_eject"
/datum/action/innate/minedrone/dump_ore/Activate()
var/mob/living/simple_animal/hostile/mining_drone/user = owner
user.DropOre()
/**********************Minebot Upgrades**********************/
//Melee
/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/simple_animal/hostile/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/simple_animal/hostile/mining_drone/minebot, mob/user)
if(minebot.melee_damage_upper != initial(minebot.melee_damage_upper))
to_chat(user, span_warning("[minebot] already has a combat upgrade installed!"))
return
minebot.melee_damage_lower += 7
minebot.melee_damage_upper += 7
to_chat(user, "<span class='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/simple_animal/hostile/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 class='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
var/base_health_add = 5 //sentient minebots are penalized for beign sentient; they have their stats reset to normal plus these values
var/base_damage_add = 1 //this thus disables other minebot upgrades
var/base_speed_add = 1
var/base_cooldown_add = 10 //base cooldown isn't reset to normal, it's just added on, since it's not practical to disable the cooldown module
/obj/item/slimepotion/slime/sentience/mining/after_success(mob/living/user, mob/living/simple_animal/simple_mob)
if(!istype(simple_mob, /mob/living/simple_animal/hostile/mining_drone))
return
var/mob/living/simple_animal/hostile/mining_drone/minebot = simple_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.move_to_delay = initial(minebot.move_to_delay) + base_speed_add
minebot.stored_gun?.recharge_time += base_cooldown_add
#undef MINEDRONE_COLLECT
#undef MINEDRONE_ATTACK
+1 -1
View File
@@ -62,7 +62,7 @@
icon = 'icons/mob/silicon/aibots.dmi'
icon_state = "mining_drone"
set_items = list(
/mob/living/simple_animal/hostile/mining_drone,
/mob/living/basic/mining_drone,
/obj/item/weldingtool/hugetank,
/obj/item/clothing/head/utility/welding,
/obj/item/borg/upgrade/modkit/minebot_passthrough,
@@ -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
@@ -263,10 +263,10 @@
/obj/item/borg/upgrade/modkit/proc/install(obj/item/gun/energy/recharge/kinetic_accelerator/KA, mob/user, transfer_to_loc = TRUE)
. = TRUE
if(minebot_upgrade)
if(minebot_exclusive && !istype(KA.loc, /mob/living/simple_animal/hostile/mining_drone))
if(minebot_exclusive && !istype(KA.loc, /mob/living/basic/mining_drone))
to_chat(user, span_notice("The modkit you're trying to install is only rated for minebot use."))
return FALSE
else if(istype(KA.loc, /mob/living/simple_animal/hostile/mining_drone))
else if(istype(KA.loc, /mob/living/basic/mining_drone))
to_chat(user, span_notice("The modkit you're trying to install is not rated for minebot use."))
return FALSE
if(denied_type)
@@ -163,7 +163,6 @@
/mob/living/simple_animal/hostile/mimic/copy/ranged,
/mob/living/simple_animal/hostile/mimic/crate,
/mob/living/simple_animal/hostile/mimic/xenobio,
/mob/living/simple_animal/hostile/mining_drone,
/mob/living/simple_animal/hostile/nanotrasen,
/mob/living/simple_animal/hostile/nanotrasen/elite,
/mob/living/simple_animal/hostile/nanotrasen/ranged,
@@ -299,7 +298,6 @@
/mob/living/simple_animal/hostile/megafauna/bubblegum/no_gps,
/mob/living/simple_animal/hostile/megafauna/gladiator,
/mob/living/simple_animal/hostile/megafauna/hierophant/astrum,
/mob/living/simple_animal/hostile/mining_drone/interdyne,
/mob/living/simple_animal/hostile/mutantliz,
/mob/living/simple_animal/hostile/plantmutant,
/mob/living/simple_animal/hostile/scorpion,