Files
Ben10Omintrix 7763db34a1 Basic beepskies and some ED209 additions (#95783)
## About The Pull Request
this PR refactors beepskies and ED209s into basic mobs. ive also added a
few features for the ed209 because i cant keep my hands to myself:

ED bots can now wear hats! a few hats give them some new unique
dialogue. Putting a cowboy's hat on an ED will have it acting like a
town Sherrif

EDs are now rideable when emagged. theyll still be shooting people while
ridden. youll also have the ability to charge at people full throttle
running them over

ive also added a new Nukie variant, purchasable from the uplink. These
versions come fitted with an LMG and will patrol the station and shoot
all walks of life. If emagged, theyll blow up people with (weaker)
rockets (im still working on balancing this). they are rideable but i
highly suggest against it; youll be caught in the crossfire. (i
understand if ud prefer i atomize this feature)

## Why It's Good For The Game
gives some personality to EDs, as well as updating all these bots to the
cool new ai system

## Changelog
🆑
refactor: beepskies, and ed209s have been refactored. please report any
bugs
add: ed209s can now wear hats! some hats give them new dialogue
add: emagged ed209s are now rideable! 
add: added evil versions of the ed209s to the syndie uplink
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
2026-04-25 00:25:28 +00:00

171 lines
6.8 KiB
Plaintext

/datum/ai_controller/basic_controller/bot/honkbot
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/secbot,
BB_UNREACHABLE_LIST_COOLDOWN = 1 MINUTES,
BB_ALWAYS_IGNORE_FACTION = TRUE,
)
planning_subtrees = list(
/datum/ai_planning_subtree/escape_captivity/pacifist,
/datum/ai_planning_subtree/respond_to_summon,
/datum/ai_planning_subtree/use_mob_ability/random_honk,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/arrest_target,
/datum/ai_planning_subtree/slip_victims,
/datum/ai_planning_subtree/play_with_clowns,
/datum/ai_planning_subtree/find_patrol_beacon,
)
reset_keys = list(
BB_BEACON_TARGET,
BB_PREVIOUS_BEACON_TARGET,
BB_BOT_SUMMON_TARGET,
)
/datum/ai_controller/basic_controller/bot/honkbot/TryPossessPawn(atom/new_pawn)
. = ..()
if(. & AI_CONTROLLER_INCOMPATIBLE)
return
RegisterSignal(new_pawn, COMSIG_AI_BLACKBOARD_KEY_CLEARED(BB_SLIP_TARGET), PROC_REF(on_clear_target))
RegisterSignal(new_pawn, COMSIG_ATOM_NO_LONGER_PULLING, PROC_REF(on_stop_pulling))
/datum/ai_controller/basic_controller/bot/honkbot/proc/on_clear_target(datum/source)
SIGNAL_HANDLER
var/mob/living/living_pawn = pawn
living_pawn.stop_pulling()
/datum/ai_controller/basic_controller/bot/honkbot/proc/on_stop_pulling(datum/source)
SIGNAL_HANDLER
if(!blackboard_key_exists(BB_SLIP_TARGET))
return
var/atom/slip_target = blackboard[BB_SLIP_TARGET]
add_to_blacklist(slip_target)
clear_blackboard_key(BB_SLIP_TARGET)
/datum/ai_planning_subtree/play_with_clowns/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/clown_target = controller.blackboard[BB_CLOWN_FRIEND]
if(QDELETED(clown_target))
var/list/my_list = controller.blackboard[BB_CLOWNS_LIST]
controller.queue_behavior(/datum/ai_behavior/bot_search/clown_friends, BB_CLOWN_FRIEND, my_list)
return
controller.queue_behavior(/datum/ai_behavior/play_with_clown, BB_CLOWN_FRIEND)
return SUBTREE_RETURN_FINISH_PLANNING
/datum/ai_behavior/bot_search/clown_friends
/datum/ai_behavior/bot_search/clown_friends/valid_target(datum/ai_controller/basic_controller/bot/controller, mob/living/my_target)
if(HAS_TRAIT(my_target, TRAIT_PERCEIVED_AS_CLOWN))
return TRUE
if(!istype(my_target, /mob/living/silicon/robot))
return FALSE
var/mob/living/silicon/robot/robot_target = my_target
return istype(robot_target.model, /obj/item/robot_model/clown)
/datum/ai_behavior/play_with_clown
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/play_with_clown/setup(datum/ai_controller/controller, target_key)
. = ..()
var/atom/target = controller.blackboard[target_key]
if(QDELETED(target))
return FALSE
set_movement_target(controller, target)
/datum/ai_behavior/play_with_clown/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
var/mob/living/living_target = controller.blackboard[target_key]
if(QDELETED(living_target))
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/mob/living/living_pawn = controller.pawn
var/datum/action/honk_ability = controller.blackboard[BB_HONK_ABILITY]
honk_ability?.Trigger()
living_pawn.manual_emote("celebrates with [living_target]!")
living_pawn.emote("flip")
living_pawn.emote("beep")
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
/datum/ai_behavior/play_with_clown/finish_action(datum/ai_controller/basic_controller/bot/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
var/mob/living/living_target = controller.blackboard[target_key]
if(QDELETED(living_target))
return
controller.add_to_blacklist(living_target)
controller.clear_blackboard_key(target_key)
/datum/ai_planning_subtree/slip_victims/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(!living_pawn.has_gravity())
return
var/atom/slippery_item = controller.blackboard[BB_SLIPPERY_TARGET]
if(QDELETED(slippery_item) || !can_see(controller.pawn, slippery_item, 5))
controller.clear_blackboard_key(BB_SLIP_TARGET)
controller.clear_blackboard_key(BB_SLIPPERY_TARGET)
controller.queue_behavior(/datum/ai_behavior/bot_search, BB_SLIPPERY_TARGET, controller.blackboard[BB_SLIPPERY_ITEMS])
return
var/mob/living/living_target = controller.blackboard[BB_SLIP_TARGET]
if(QDELETED(living_target))
var/static/list/to_slip = typecacheof(list(/mob/living/carbon/human))
controller.queue_behavior(/datum/ai_behavior/bot_search/slip_target, BB_SLIP_TARGET, to_slip)
return
if(living_pawn.pulling == living_target)
controller.queue_behavior(/datum/ai_behavior/drag_to_slip, BB_SLIP_TARGET, BB_SLIPPERY_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING
controller.queue_behavior(/datum/ai_behavior/drag_target, BB_SLIP_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING
/datum/ai_behavior/bot_search/slip_target
/datum/ai_behavior/bot_search/slip_target/valid_target(datum/ai_controller/basic_controller/bot/controller, mob/living/my_target)
return (!my_target.buckled && my_target.has_gravity())
/datum/ai_behavior/drag_to_slip
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
required_distance = 0
/datum/ai_behavior/drag_to_slip/setup(datum/ai_controller/controller, slip_target, slippery_target)
. = ..()
var/atom/target = controller.blackboard[slippery_target]
if(QDELETED(target))
return FALSE
set_movement_target(controller, target)
/datum/ai_behavior/drag_to_slip/perform(seconds_per_tick, datum/ai_controller/controller, slip_target, slippery_target)
var/mob/living/our_pawn = controller.pawn
var/atom/living_target = controller.blackboard[slip_target]
if(QDELETED(living_target))
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/list/possible_dirs = GLOB.alldirs.Copy()
possible_dirs -= get_dir(our_pawn, living_target)
for(var/direction in possible_dirs)
var/turf/possible_turf = get_step(our_pawn, direction)
if(possible_turf.is_blocked_turf(source_atom = our_pawn))
possible_dirs -= direction
step(our_pawn, pick(possible_dirs))
our_pawn.stop_pulling()
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
/datum/ai_behavior/drag_to_slip/finish_action(datum/ai_controller/basic_controller/bot/controller, success, slip_target, slippery_target)
. = ..()
if(success)
var/mob/living/living_pawn = controller.pawn
living_pawn.emote("flip")
var/atom/slipped_victim = controller.blackboard[slip_target]
if(!isnull(slipped_victim))
controller.add_to_blacklist(slipped_victim)
controller.clear_blackboard_key(slip_target)
controller.clear_blackboard_key(slippery_target)
/datum/ai_planning_subtree/use_mob_ability/random_honk
ability_key = BB_HONK_ABILITY
/datum/ai_planning_subtree/use_mob_ability/random_honk/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
if(!SPT_PROB(5, seconds_per_tick))
return
return ..()