mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 02:32:10 +00:00
## 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 /🆑
260 lines
9.8 KiB
Plaintext
260 lines
9.8 KiB
Plaintext
// None of these are really complex enough to merit their own file
|
|
|
|
/**
|
|
* # Pet Command: Idle
|
|
* Tells a pet to resume its idle behaviour, usually staying put where you leave it
|
|
*/
|
|
/datum/pet_command/idle
|
|
command_name = "Stay"
|
|
command_desc = "Command your pet to stay idle in this location."
|
|
radial_icon = 'icons/obj/bed.dmi'
|
|
radial_icon_state = "dogbed"
|
|
speech_commands = list("sit", "stay", "stop")
|
|
command_feedback = "sits"
|
|
|
|
/datum/pet_command/idle/execute_action(datum/ai_controller/controller)
|
|
return SUBTREE_RETURN_FINISH_PLANNING // This cancels further AI planning
|
|
|
|
/**
|
|
* # Pet Command: Stop
|
|
* Tells a pet to exit command mode and resume its normal behaviour, which includes regular target-seeking and what have you
|
|
*/
|
|
/datum/pet_command/free
|
|
command_name = "Loose"
|
|
command_desc = "Allow your pet to resume its natural behaviours."
|
|
radial_icon = 'icons/mob/actions/actions_spells.dmi'
|
|
radial_icon_state = "repulse"
|
|
speech_commands = list("free", "loose")
|
|
command_feedback = "relaxes"
|
|
|
|
/datum/pet_command/free/execute_action(datum/ai_controller/controller)
|
|
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
|
return // Just move on to the next planning subtree.
|
|
|
|
/**
|
|
* # Pet Command: Follow
|
|
* Tells a pet to follow you until you tell it to do something else
|
|
*/
|
|
/datum/pet_command/follow
|
|
command_name = "Follow"
|
|
command_desc = "Command your pet to accompany you."
|
|
radial_icon = 'icons/testing/turf_analysis.dmi'
|
|
radial_icon_state = "red_arrow"
|
|
speech_commands = list("heel", "follow")
|
|
///the behavior we use to follow
|
|
var/follow_behavior = /datum/ai_behavior/pet_follow_friend
|
|
|
|
/datum/pet_command/follow/set_command_active(mob/living/parent, mob/living/commander)
|
|
. = ..()
|
|
set_command_target(parent, commander)
|
|
|
|
/datum/pet_command/follow/execute_action(datum/ai_controller/controller)
|
|
controller.queue_behavior(follow_behavior, BB_CURRENT_PET_TARGET)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/**
|
|
* # Pet Command: Play Dead
|
|
* Pretend to be dead for a random period of time
|
|
*/
|
|
/datum/pet_command/play_dead
|
|
command_name = "Play Dead"
|
|
command_desc = "Play a macabre trick."
|
|
radial_icon = 'icons/mob/simple/pets.dmi'
|
|
radial_icon_state = "puppy_dead"
|
|
speech_commands = list("play dead") // Don't get too creative here, people talk about dying pretty often
|
|
|
|
/datum/pet_command/play_dead/execute_action(datum/ai_controller/controller)
|
|
controller.queue_behavior(/datum/ai_behavior/play_dead)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/**
|
|
* # Pet Command: Good Boy
|
|
* React if complimented
|
|
*/
|
|
/datum/pet_command/good_boy
|
|
command_name = "Good Boy"
|
|
command_desc = "Give your pet a compliment."
|
|
hidden = TRUE
|
|
|
|
/datum/pet_command/good_boy/New(mob/living/parent)
|
|
. = ..()
|
|
speech_commands += "good [parent.name]"
|
|
switch (parent.gender)
|
|
if (MALE)
|
|
speech_commands += "good boy"
|
|
return
|
|
if (FEMALE)
|
|
speech_commands += "good girl"
|
|
return
|
|
// If we get past this point someone has finally added a non-binary dog
|
|
|
|
/datum/pet_command/good_boy/execute_action(datum/ai_controller/controller)
|
|
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
|
var/mob/living/parent = weak_parent.resolve()
|
|
if (!parent)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
new /obj/effect/temp_visual/heart(parent.loc)
|
|
parent.emote("spin")
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/**
|
|
* # Pet Command: Use ability
|
|
* Use an an ability that does not require any targets
|
|
*/
|
|
/datum/pet_command/untargeted_ability
|
|
///untargeted ability we will use
|
|
var/ability_key
|
|
|
|
/datum/pet_command/untargeted_ability/execute_action(datum/ai_controller/controller)
|
|
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
|
if(!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
|
|
|
|
/**
|
|
* # Pet Command: Attack
|
|
* Tells a pet to chase and bite the next thing you point at
|
|
*/
|
|
/datum/pet_command/point_targeting/attack
|
|
command_name = "Attack"
|
|
command_desc = "Command your pet to attack things that you point out to it."
|
|
radial_icon = 'icons/effects/effects.dmi'
|
|
radial_icon_state = "bite"
|
|
|
|
speech_commands = list("attack", "sic", "kill")
|
|
command_feedback = "growl"
|
|
pointed_reaction = "and growls"
|
|
/// Balloon alert to display if providing an invalid target
|
|
var/refuse_reaction = "shakes head"
|
|
/// Attack behaviour to use
|
|
var/attack_behaviour = /datum/ai_behavior/basic_melee_attack
|
|
|
|
// Refuse to target things we can't target, chiefly other friends
|
|
/datum/pet_command/point_targeting/attack/set_command_target(mob/living/parent, atom/target)
|
|
if (!target)
|
|
return
|
|
var/mob/living/living_parent = parent
|
|
if (!living_parent.ai_controller)
|
|
return
|
|
var/datum/targeting_strategy/targeter = GET_TARGETING_STRATEGY(living_parent.ai_controller.blackboard[targeting_strategy_key])
|
|
if (!targeter)
|
|
return
|
|
if (!targeter.can_attack(living_parent, target))
|
|
refuse_target(parent, target)
|
|
return
|
|
return ..()
|
|
|
|
/// Display feedback about not targeting something
|
|
/datum/pet_command/point_targeting/attack/proc/refuse_target(mob/living/parent, atom/target)
|
|
var/mob/living/living_parent = parent
|
|
living_parent.balloon_alert_to_viewers("[refuse_reaction]")
|
|
living_parent.visible_message(span_notice("[living_parent] refuses to attack [target]."))
|
|
|
|
/datum/pet_command/point_targeting/attack/execute_action(datum/ai_controller/controller)
|
|
controller.queue_behavior(attack_behaviour, BB_CURRENT_PET_TARGET, targeting_strategy_key)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/**
|
|
* # Breed command. breed with a partner!
|
|
*/
|
|
/datum/pet_command/point_targeting/breed
|
|
command_name = "Breed"
|
|
command_desc = "Command your pet to attempt to breed with a partner."
|
|
radial_icon = 'icons/mob/simple/animal.dmi'
|
|
radial_icon_state = "heart"
|
|
speech_commands = list("breed", "consummate")
|
|
var/datum/ai_behavior/reproduce_behavior = /datum/ai_behavior/make_babies
|
|
|
|
/datum/pet_command/point_targeting/breed/set_command_target(mob/living/parent, atom/target)
|
|
if(isnull(target) || !isliving(target))
|
|
return
|
|
if(!HAS_TRAIT(parent, TRAIT_MOB_BREEDER) || !HAS_TRAIT(target, TRAIT_MOB_BREEDER))
|
|
return
|
|
if(isnull(parent.ai_controller))
|
|
return
|
|
if(!parent.ai_controller.blackboard[BB_BREED_READY] || isnull(parent.ai_controller.blackboard[BB_BABIES_PARTNER_TYPES]))
|
|
return
|
|
var/mob/living/living_target = target
|
|
if(!living_target.ai_controller?.blackboard[BB_BREED_READY])
|
|
return
|
|
return ..()
|
|
|
|
/datum/pet_command/point_targeting/breed/execute_action(datum/ai_controller/controller)
|
|
if(is_type_in_list(controller.blackboard[BB_CURRENT_PET_TARGET], controller.blackboard[BB_BABIES_PARTNER_TYPES]))
|
|
controller.queue_behavior(reproduce_behavior, BB_CURRENT_PET_TARGET)
|
|
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/**
|
|
* # Pet Command: Targetted Ability
|
|
* Tells a pet to use some kind of ability on the next thing you point at
|
|
*/
|
|
/datum/pet_command/point_targeting/use_ability
|
|
command_name = "Use ability"
|
|
command_desc = "Command your pet to use one of its special skills on something that you point out to it."
|
|
radial_icon = 'icons/mob/actions/actions_spells.dmi'
|
|
radial_icon_state = "projectile"
|
|
speech_commands = list("shoot", "blast", "cast")
|
|
command_feedback = "growl"
|
|
pointed_reaction = "and growls"
|
|
/// Blackboard key where a reference to some kind of mob ability is stored
|
|
var/pet_ability_key
|
|
|
|
/datum/pet_command/point_targeting/use_ability/execute_action(datum/ai_controller/controller)
|
|
if (!pet_ability_key)
|
|
return
|
|
var/datum/action/cooldown/using_action = controller.blackboard[pet_ability_key]
|
|
if (QDELETED(using_action))
|
|
return
|
|
// We don't check if the target exists because we want to 'sit attentively' if we've been instructed to attack but not given one yet
|
|
// We also don't check if the cooldown is over because there's no way a pet owner can know that, the behaviour will handle it
|
|
controller.queue_behavior(/datum/ai_behavior/pet_use_ability, pet_ability_key, BB_CURRENT_PET_TARGET)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/datum/pet_command/protect_owner
|
|
command_name = "Protect owner"
|
|
command_desc = "Your pet will run to your aid."
|
|
hidden = TRUE
|
|
///the range our owner needs to be in for us to protect him
|
|
var/protect_range = 9
|
|
///the behavior we will use when he is attacked
|
|
var/protect_behavior = /datum/ai_behavior/basic_melee_attack
|
|
|
|
/datum/pet_command/protect_owner/add_new_friend(mob/living/tamer)
|
|
RegisterSignal(tamer, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(set_attacking_target))
|
|
if(!HAS_TRAIT(tamer, TRAIT_RELAYING_ATTACKER))
|
|
tamer.AddElement(/datum/element/relay_attackers)
|
|
|
|
/datum/pet_command/protect_owner/remove_friend(mob/living/unfriended)
|
|
UnregisterSignal(unfriended, COMSIG_ATOM_WAS_ATTACKED)
|
|
|
|
/datum/pet_command/protect_owner/execute_action(datum/ai_controller/controller)
|
|
var/mob/living/victim = controller.blackboard[BB_CURRENT_PET_TARGET]
|
|
if(QDELETED(victim))
|
|
return
|
|
// cancel the action if they're below our given crit stat, OR if we're trying to attack ourselves (this can happen on tamed mobs w/ protect subtree rarely)
|
|
if(victim.stat > controller.blackboard[BB_TARGET_MINIMUM_STAT] || victim == controller.pawn)
|
|
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
|
return
|
|
controller.queue_behavior(protect_behavior, BB_CURRENT_PET_TARGET, BB_PET_TARGETING_STRATEGY)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
/datum/pet_command/protect_owner/set_command_active(mob/living/parent, mob/living/victim)
|
|
. = ..()
|
|
set_command_target(parent, victim)
|
|
|
|
/datum/pet_command/protect_owner/proc/set_attacking_target(atom/source, mob/living/attacker)
|
|
SIGNAL_HANDLER
|
|
|
|
var/mob/living/basic/owner = weak_parent.resolve()
|
|
if(isnull(owner))
|
|
return
|
|
var/mob/living/current_target = owner.ai_controller?.blackboard[BB_CURRENT_PET_TARGET]
|
|
if(attacker == current_target) //we are already dealing with this target
|
|
return
|
|
if(isliving(attacker) && can_see(owner, attacker, protect_range))
|
|
set_command_active(owner, attacker)
|