mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-17 13:12:37 +00:00
[MIRROR] hygeienbots basic bots [MDB IGNORE] (#25923)
* hygeienbots basic bots (#80435) ## About The Pull Request turns hygenic bots into basic bots. also now PAIs and people can play as hygeinebots. and they can wear hats ## Why It's Good For The Game transforms hyginebots into basic bots. their old AI used to handle all the logic. i moved some of the logic to the mob itself so players can also clean (or burn) things. also this pr will add pathing limits to bots, in the case the jps movement thinks it can reach something, but actually cant, in which case the bot will give up the chase ## Changelog 🆑 refactor: hygeinebots are now basic bots. please report all the bugs fix: fixes hygenebots not being able to patrol add: hygeinebots can now be controlled by Players /🆑 * hygeienbots basic bots --------- Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
This commit is contained in:
@@ -716,7 +716,7 @@
|
||||
/turf/open/floor/grass,
|
||||
/area/shuttle/escape)
|
||||
"nQ" = (
|
||||
/mob/living/simple_animal/bot/hygienebot,
|
||||
/mob/living/basic/bot/hygienebot,
|
||||
/turf/open/floor/wood,
|
||||
/area/shuttle/escape)
|
||||
"nV" = (
|
||||
|
||||
@@ -215,17 +215,6 @@
|
||||
/obj/structure/lattice/catwalk,
|
||||
/turf/open/space/basic,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"mG" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/surgery_tray/full,
|
||||
/obj/effect/turf_decal/bot,
|
||||
/obj/structure/sink/directional/east,
|
||||
/obj/item/toy/figure/borg{
|
||||
pixel_x = 7;
|
||||
pixel_y = 12
|
||||
},
|
||||
/turf/open/floor/iron/dark,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"mN" = (
|
||||
/obj/machinery/conveyor{
|
||||
dir = 4;
|
||||
@@ -584,11 +573,6 @@
|
||||
/obj/structure/cable,
|
||||
/turf/open/floor/iron/showroomfloor,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"Fe" = (
|
||||
/mob/living/simple_animal/bot/hygienebot,
|
||||
/obj/machinery/camera/directional/south,
|
||||
/turf/open/floor/iron/showroomfloor,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"FQ" = (
|
||||
/obj/structure/lattice,
|
||||
/mob/living/basic/hivebot/range,
|
||||
@@ -654,6 +638,11 @@
|
||||
/mob/living/basic/hivebot/mechanic,
|
||||
/turf/template_noop,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"JS" = (
|
||||
/mob/living/basic/bot/hygienebot,
|
||||
/obj/machinery/camera/directional/south,
|
||||
/turf/open/floor/iron/showroomfloor,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"Ks" = (
|
||||
/obj/structure/cable,
|
||||
/obj/machinery/conveyor/inverted{
|
||||
@@ -722,6 +711,17 @@
|
||||
/obj/structure/cable,
|
||||
/turf/open/floor/circuit/airless,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"Oq" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/surgery_tray/full,
|
||||
/obj/effect/turf_decal/bot,
|
||||
/obj/structure/sink/directional/east,
|
||||
/obj/item/toy/figure/borg{
|
||||
pixel_x = 7;
|
||||
pixel_y = 12
|
||||
},
|
||||
/turf/open/floor/iron/dark,
|
||||
/area/shuttle/ruin/cyborg_mothership)
|
||||
"Ou" = (
|
||||
/obj/machinery/camera/directional/west,
|
||||
/obj/structure/cable,
|
||||
@@ -1161,7 +1161,7 @@ zZ
|
||||
zZ
|
||||
mN
|
||||
iN
|
||||
mG
|
||||
Oq
|
||||
zZ
|
||||
kz
|
||||
kz
|
||||
@@ -1186,7 +1186,7 @@ fB
|
||||
zZ
|
||||
Ey
|
||||
Sd
|
||||
Fe
|
||||
JS
|
||||
yF
|
||||
HM
|
||||
yF
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#define BB_RADIO_CHANNEL "radio_channel"
|
||||
///list of unreachable things we will temporarily ignore
|
||||
#define BB_TEMPORARY_IGNORE_LIST "temporary_ignore_list"
|
||||
///Last thing we attempted to reach
|
||||
#define BB_LAST_ATTEMPTED_PATHING "last_attempted_pathing"
|
||||
|
||||
// medbot keys
|
||||
///the patient we must heal
|
||||
@@ -55,3 +57,17 @@
|
||||
#define BB_ACID_SPRAY_TARGET "acid_spray_target"
|
||||
///key that holds trash we will burn
|
||||
#define BB_HUNTABLE_TRASH "huntable_trash"
|
||||
|
||||
//hygienebots
|
||||
///key that holds our threats
|
||||
#define BB_WASH_THREATS "wash_threats"
|
||||
///key that holds speech when we find our target
|
||||
#define BB_WASH_FOUND "wash_found"
|
||||
///key that holds speech when we cleaned our target
|
||||
#define BB_WASH_DONE "wash_done"
|
||||
///key that holds target we will wash
|
||||
#define BB_WASH_TARGET "wash_target"
|
||||
///key that holds how frustrated we are when target is running away
|
||||
#define BB_WASH_FRUSTRATION "wash_frustration"
|
||||
///key that holds cooldown after we finish cleaning something, so we dont immediately run off to patrol
|
||||
#define BB_POST_CLEAN_COOLDOWN "post_clean_cooldown"
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
/datum/crafting_recipe/hygienebot
|
||||
name = "Hygienebot"
|
||||
result = /mob/living/simple_animal/bot/hygienebot
|
||||
result = /mob/living/basic/bot/hygienebot
|
||||
reqs = list(
|
||||
/obj/item/bot_assembly/hygienebot = 1,
|
||||
/obj/item/stack/ducts = 1,
|
||||
|
||||
@@ -819,8 +819,13 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
diag_hud_set_botmode()
|
||||
|
||||
/mob/living/basic/bot/proc/after_attacked(datum/source, atom/attacker, attack_flags)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(attack_flags & ATTACKER_DAMAGING_ATTACK)
|
||||
do_sparks(number = 5, cardinal_only = TRUE, source = src)
|
||||
|
||||
/mob/living/basic/bot/spawn_gibs(drop_bitflags = NONE)
|
||||
new /obj/effect/gibspawner/robot(drop_location(), src)
|
||||
|
||||
/mob/living/basic/bot/proc/on_bot_movement(atom/movable/source, atom/oldloc, dir, forced)
|
||||
return
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
BB_PREVIOUS_BEACON_TARGET,
|
||||
BB_BOT_SUMMON_TARGET,
|
||||
)
|
||||
///how many times we tried to reach the target
|
||||
var/current_pathing_attempts = 0
|
||||
///if we cant reach it after this many attempts, add it to our ignore list
|
||||
var/max_pathing_attempts = 25
|
||||
|
||||
/datum/ai_controller/basic_controller/bot/TryPossessPawn(atom/new_pawn)
|
||||
. = ..()
|
||||
@@ -70,8 +74,15 @@
|
||||
var/datum/target = blackboard[key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
if(!can_reach_target(target, distance))
|
||||
var/datum/last_attempt = blackboard[BB_LAST_ATTEMPTED_PATHING]
|
||||
if(last_attempt != target)
|
||||
current_pathing_attempts = 0
|
||||
set_blackboard_key(BB_LAST_ATTEMPTED_PATHING, target)
|
||||
else
|
||||
current_pathing_attempts++
|
||||
if(current_pathing_attempts >= max_pathing_attempts || !can_reach_target(target, distance))
|
||||
clear_blackboard_key(key)
|
||||
clear_blackboard_key(BB_LAST_ATTEMPTED_PATHING)
|
||||
set_blackboard_key_assoc_lazylist(BB_TEMPORARY_IGNORE_LIST, target, TRUE)
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -84,7 +95,7 @@
|
||||
|
||||
/datum/ai_behavior/manage_unreachable_list
|
||||
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
action_cooldown = 15 SECONDS
|
||||
action_cooldown = 45 SECONDS
|
||||
|
||||
/datum/ai_behavior/manage_unreachable_list/perform(seconds_per_tick, datum/ai_controller/controller, list_key)
|
||||
. = ..()
|
||||
|
||||
@@ -90,9 +90,13 @@
|
||||
hud.add_atom_to_hud(src)
|
||||
|
||||
///proc that handles moving along the bot's drawn path
|
||||
/mob/living/basic/bot/proc/handle_loop_movement(atom/movable/source)
|
||||
/mob/living/basic/bot/proc/handle_loop_movement(atom/movable/source, atom/oldloc, dir, forced)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
handle_hud_path()
|
||||
on_bot_movement(source, oldloc, dir, forced)
|
||||
|
||||
/mob/living/basic/bot/proc/handle_hud_path()
|
||||
if(client || !length(current_pathed_turfs) || isnull(ai_controller))
|
||||
return
|
||||
|
||||
@@ -106,7 +110,6 @@
|
||||
if(target_image)
|
||||
animate(target_image, alpha = 0, time = 0.3 SECONDS)
|
||||
current_pathed_turfs -= our_turf
|
||||
return
|
||||
|
||||
///proc that handles deleting the bot's drawn path when needed
|
||||
/mob/living/basic/bot/proc/clear_path_hud()
|
||||
|
||||
@@ -94,7 +94,6 @@
|
||||
/obj/effect/decal/cleanable/glass,
|
||||
/obj/effect/decal/cleanable/vomit,
|
||||
/obj/effect/decal/cleanable/wrapping,
|
||||
/obj/effect/decal/remains,
|
||||
))
|
||||
///blood we can clean
|
||||
var/static/list/cleanable_blood = typecacheof(list(
|
||||
@@ -111,6 +110,7 @@
|
||||
var/static/list/huntable_trash = typecacheof(list(
|
||||
/obj/item/trash,
|
||||
/obj/item/food/deadmouse,
|
||||
/obj/effect/decal/remains,
|
||||
))
|
||||
///drawings we hunt
|
||||
var/static/list/cleanable_drawings = typecacheof(list(/obj/effect/decal/cleanable/crayon))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define BOT_CLEAN_PATH_LIMIT 15
|
||||
#define POST_CLEAN_COOLDOWN 5 SECONDS
|
||||
|
||||
/datum/ai_controller/basic_controller/bot/cleanbot
|
||||
blackboard = list(
|
||||
@@ -51,7 +52,6 @@
|
||||
|
||||
/datum/ai_planning_subtree/cleaning_subtree/SelectBehaviors(datum/ai_controller/basic_controller/bot/cleanbot/controller, seconds_per_tick)
|
||||
if(controller.reachable_key(BB_CLEAN_TARGET, BOT_CLEAN_PATH_LIMIT))
|
||||
controller.clear_blackboard_key(BB_BEACON_TARGET)
|
||||
controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_CLEAN_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
|
||||
/datum/ai_behavior/execute_clean/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
|
||||
. = ..()
|
||||
controller.set_blackboard_key(BB_POST_CLEAN_COOLDOWN, POST_CLEAN_COOLDOWN + world.time)
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target) || is_type_in_typecache(target, controller.blackboard[BB_HUNTABLE_TRASH]))
|
||||
return
|
||||
@@ -186,7 +187,7 @@
|
||||
/datum/ai_planning_subtree/find_patrol_beacon/cleanbot
|
||||
|
||||
/datum/ai_planning_subtree/find_patrol_beacon/cleanbot/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
||||
if(controller.blackboard_key_exists(BB_CLEAN_TARGET))
|
||||
if(controller.blackboard[BB_POST_CLEAN_COOLDOWN] >= world.time)
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -214,3 +215,4 @@
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
#undef BOT_CLEAN_PATH_LIMIT
|
||||
#undef POST_CLEAN_COOLDOWN
|
||||
|
||||
132
code/modules/mob/living/basic/bots/hygienebot/hygienebot.dm
Normal file
132
code/modules/mob/living/basic/bots/hygienebot/hygienebot.dm
Normal file
@@ -0,0 +1,132 @@
|
||||
#define WASH_PERIOD 3 SECONDS
|
||||
|
||||
/mob/living/basic/bot/hygienebot
|
||||
name = "\improper Hygienebot"
|
||||
desc = "A flying cleaning robot, he'll chase down people who can't shower properly!"
|
||||
icon = 'icons/mob/silicon/aibots.dmi'
|
||||
icon_state = "hygienebot"
|
||||
base_icon_state = "hygienebot"
|
||||
pass_flags = PASSMOB | PASSFLAPS | PASSTABLE
|
||||
layer = MOB_UPPER_LAYER
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
health = 100
|
||||
maxHealth = 100
|
||||
path_image_color = "#80dae7"
|
||||
maints_access_required = list(ACCESS_ROBOTICS, ACCESS_JANITOR)
|
||||
radio_key = /obj/item/encryptionkey/headset_service
|
||||
radio_channel = RADIO_CHANNEL_SERVICE
|
||||
bot_type = HYGIENE_BOT
|
||||
additional_access = /datum/id_trim/job/janitor
|
||||
hackables = "cleaning service protocols"
|
||||
ai_controller = /datum/ai_controller/basic_controller/bot/hygienebot
|
||||
|
||||
///are we currently washing someone?
|
||||
var/washing = FALSE
|
||||
///Visual overlay of the bot spraying water.
|
||||
var/static/mutable_appearance/water_overlay = mutable_appearance('icons/mob/silicon/aibots.dmi', "hygienebot-water")
|
||||
///Visual overlay of the bot commiting warcrimes.
|
||||
var/static/mutable_appearance/fire_overlay = mutable_appearance('icons/mob/silicon/aibots.dmi', "hygienebot-fire")
|
||||
///announcements we say when we find a target
|
||||
var/static/list/found_announcements = list(
|
||||
HYGIENEBOT_VOICED_UNHYGIENIC = 'sound/voice/hygienebot/unhygienicclient.ogg',
|
||||
)
|
||||
///announcements we say when the target keeps moving away
|
||||
var/static/list/threat_announcements = list(
|
||||
HYGIENEBOT_VOICED_THREAT_AIRLOCK = 'sound/voice/hygienebot/dragyouout.ogg',
|
||||
HYGIENEBOT_VOICED_FOUL_SMELL = 'sound/voice/hygienebot/foulsmelling.ogg',
|
||||
HYGIENEBOT_VOICED_TROGLODYTE = 'sound/voice/hygienebot/troglodyte.ogg',
|
||||
HYGIENEBOT_VOICED_GREEN_CLOUD = 'sound/voice/hygienebot/greencloud.ogg',
|
||||
HYGIENEBOT_VOICED_ARSEHOLE = 'sound/voice/hygienebot/letmeclean.ogg',
|
||||
HYGIENEBOT_VOICED_THREAT_ARTERIES = 'sound/voice/hygienebot/cutarteries.ogg',
|
||||
HYGIENEBOT_VOICED_STOP_RUNNING = 'sound/voice/hygienebot/stoprunning.ogg',
|
||||
)
|
||||
///announcements we say after we have cleaned our target
|
||||
var/static/list/cleaned_announcements = list(
|
||||
HYGIENEBOT_VOICED_FUCKING_FINALLY = 'sound/voice/hygienebot/finally.ogg',
|
||||
HYGIENEBOT_VOICED_THANK_GOD = 'sound/voice/hygienebot/thankgod.ogg',
|
||||
HYGIENEBOT_VOICED_DEGENERATE = 'sound/voice/hygienebot/degenerate.ogg',
|
||||
)
|
||||
|
||||
/mob/living/basic/bot/hygienebot/Initialize(mapload)
|
||||
. = ..()
|
||||
update_appearance(UPDATE_ICON)
|
||||
|
||||
generate_ai_speech()
|
||||
|
||||
var/static/list/loc_connections = list(
|
||||
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
||||
)
|
||||
AddElement(/datum/element/connect_loc, loc_connections)
|
||||
var/static/list/hat_offsets = list(1, 1)
|
||||
AddElement(/datum/element/hat_wearer, offsets = hat_offsets)
|
||||
|
||||
ADD_TRAIT(src, TRAIT_SPRAY_PAINTABLE, INNATE_TRAIT)
|
||||
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_attack))
|
||||
|
||||
/mob/living/basic/bot/hygienebot/explode()
|
||||
var/datum/effect_system/fluid_spread/foam/foam = new
|
||||
foam.set_up(2, holder = src, location = loc)
|
||||
foam.start()
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/bot/hygienebot/generate_speak_list()
|
||||
var/static/list/finalized_speak_list = (found_announcements + threat_announcements + cleaned_announcements)
|
||||
return finalized_speak_list
|
||||
|
||||
/mob/living/basic/bot/hygienebot/update_icon_state()
|
||||
. = ..()
|
||||
icon_state = "[base_icon_state][bot_mode_flags & BOT_MODE_ON ? "-on" : ""]"
|
||||
|
||||
|
||||
/mob/living/basic/bot/hygienebot/update_overlays()
|
||||
. = ..()
|
||||
if(bot_mode_flags & BOT_MODE_ON)
|
||||
. += mutable_appearance(icon, "hygienebot-flame")
|
||||
|
||||
if(!washing)
|
||||
return
|
||||
|
||||
. += (bot_access_flags & BOT_COVER_EMAGGED) ? fire_overlay : water_overlay
|
||||
|
||||
/mob/living/basic/bot/hygienebot/proc/on_entered(datum/source, atom/movable/movable)
|
||||
SIGNAL_HANDLER
|
||||
if(!washing)
|
||||
return
|
||||
commence_wash(movable)
|
||||
|
||||
/mob/living/basic/bot/hygienebot/proc/on_attack(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
. = COMPONENT_HOSTILE_NO_ATTACK
|
||||
if(washing)
|
||||
return
|
||||
set_washing_mode(new_mode = TRUE)
|
||||
for(var/atom/to_wash in loc)
|
||||
commence_wash(to_wash)
|
||||
addtimer(CALLBACK(src, PROC_REF(set_washing_mode), FALSE), WASH_PERIOD)
|
||||
|
||||
/mob/living/basic/bot/hygienebot/proc/set_washing_mode(new_mode)
|
||||
washing = new_mode
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
/mob/living/basic/bot/hygienebot/proc/commence_wash(atom/target)
|
||||
if(bot_access_flags & BOT_COVER_EMAGGED)
|
||||
target.fire_act()
|
||||
return
|
||||
target.wash(CLEAN_WASH)
|
||||
|
||||
/mob/living/basic/bot/hygienebot/on_bot_movement(atom/movable/source, atom/oldloc, dir, forced)
|
||||
|
||||
if(!washing || !isturf(loc))
|
||||
return
|
||||
|
||||
for(var/mob/living/carbon/human in loc)
|
||||
commence_wash(human)
|
||||
|
||||
|
||||
/mob/living/basic/bot/hygienebot/proc/generate_ai_speech()
|
||||
ai_controller.set_blackboard_key(BB_WASH_FOUND, found_announcements)
|
||||
ai_controller.set_blackboard_key(BB_WASH_THREATS, threat_announcements)
|
||||
ai_controller.set_blackboard_key(BB_WASH_DONE, cleaned_announcements)
|
||||
|
||||
#undef WASH_PERIOD
|
||||
142
code/modules/mob/living/basic/bots/hygienebot/hygienebot_ai.dm
Normal file
142
code/modules/mob/living/basic/bots/hygienebot/hygienebot_ai.dm
Normal file
@@ -0,0 +1,142 @@
|
||||
#define BOT_FRUSTRATION_LIMIT 8
|
||||
|
||||
/datum/ai_controller/basic_controller/bot/hygienebot
|
||||
blackboard = list(
|
||||
BB_SALUTE_MESSAGES = list(
|
||||
"salutes",
|
||||
"nods in appreciation towards",
|
||||
),
|
||||
BB_WASH_FRUSTRATION = 0,
|
||||
)
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/manage_unreachable_list,
|
||||
/datum/ai_planning_subtree/respond_to_summon,
|
||||
/datum/ai_planning_subtree/wash_people,
|
||||
/datum/ai_planning_subtree/salute_authority,
|
||||
/datum/ai_planning_subtree/find_patrol_beacon,
|
||||
)
|
||||
reset_keys = list(
|
||||
BB_WASH_TARGET,
|
||||
BB_BEACON_TARGET,
|
||||
BB_PREVIOUS_BEACON_TARGET,
|
||||
BB_BOT_SUMMON_TARGET,
|
||||
)
|
||||
|
||||
/datum/ai_controller/basic_controller/bot/hygienebot/TryPossessPawn(atom/new_pawn)
|
||||
. = ..()
|
||||
if(. & AI_CONTROLLER_INCOMPATIBLE)
|
||||
return
|
||||
RegisterSignal(new_pawn, COMSIG_AI_BLACKBOARD_KEY_CLEARED(BB_WASH_TARGET), PROC_REF(reset_anger))
|
||||
|
||||
/datum/ai_controller/basic_controller/bot/hygienebot/proc/reset_anger()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
set_blackboard_key(BB_WASH_FRUSTRATION, 0)
|
||||
|
||||
|
||||
/datum/ai_planning_subtree/wash_people
|
||||
|
||||
/datum/ai_planning_subtree/wash_people/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
||||
var/mob/living/basic/bot/bot_pawn = controller.pawn
|
||||
|
||||
var/atom/wash_target = controller.blackboard[BB_WASH_TARGET]
|
||||
if(QDELETED(wash_target))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_valid_wash_targets, BB_WASH_TARGET, bot_pawn.bot_access_flags)
|
||||
return
|
||||
|
||||
if(get_dist(bot_pawn, wash_target) < 9)
|
||||
controller.queue_behavior(/datum/ai_behavior/wash_target, BB_WASH_TARGET)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
controller.clear_blackboard_key(BB_WASH_TARGET) //delete if too far
|
||||
|
||||
/datum/ai_behavior/find_valid_wash_targets
|
||||
action_cooldown = 5 SECONDS
|
||||
|
||||
/datum/ai_behavior/find_valid_wash_targets/perform(seconds_per_tick, datum/ai_controller/controller, target_key, our_access_flags)
|
||||
. = ..()
|
||||
var/list/ignore_list = controller.blackboard[BB_TEMPORARY_IGNORE_LIST]
|
||||
var/atom/found_target
|
||||
for(var/mob/living/carbon/human/wash_potential in oview(5, controller.pawn))
|
||||
|
||||
if(found_target)
|
||||
break
|
||||
|
||||
if(isnull(wash_potential.mind) || wash_potential.stat != CONSCIOUS)
|
||||
continue
|
||||
|
||||
if(LAZYACCESS(ignore_list, wash_potential))
|
||||
continue
|
||||
|
||||
if(our_access_flags & BOT_COVER_EMAGGED)
|
||||
controller.set_blackboard_key_assoc_lazylist(BB_TEMPORARY_IGNORE_LIST, wash_potential, TRUE)
|
||||
found_target = wash_potential
|
||||
break
|
||||
|
||||
for(var/atom/clothing in wash_potential.get_equipped_items())
|
||||
if(GET_ATOM_BLOOD_DNA_LENGTH(clothing))
|
||||
found_target = wash_potential
|
||||
break
|
||||
|
||||
if(isnull(found_target))
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
|
||||
controller.set_blackboard_key(target_key, found_target)
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
|
||||
|
||||
/datum/ai_behavior/find_valid_wash_targets/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
if(!succeeded)
|
||||
return
|
||||
var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY]
|
||||
announcement.announce(pick(controller.blackboard[BB_WASH_FOUND]))
|
||||
|
||||
/datum/ai_behavior/wash_target
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION | AI_BEHAVIOR_MOVE_AND_PERFORM
|
||||
required_distance = 0
|
||||
action_cooldown = 1 SECONDS
|
||||
|
||||
/datum/ai_behavior/wash_target/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/wash_target/perform(seconds_per_tick, datum/ai_controller/basic_controller/bot/controller, target_key)
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/unclean_target = controller.blackboard[target_key]
|
||||
var/mob/living/basic/living_pawn = controller.pawn
|
||||
if(QDELETED(unclean_target))
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
|
||||
if(living_pawn.loc == get_turf(unclean_target))
|
||||
living_pawn.melee_attack(unclean_target)
|
||||
finish_action(controller, TRUE, target_key)
|
||||
return
|
||||
|
||||
var/frustration_count = controller.blackboard[BB_WASH_FRUSTRATION]
|
||||
controller.set_blackboard_key(BB_WASH_FRUSTRATION, frustration_count + 1)
|
||||
finish_action(controller, FALSE, target_key)
|
||||
|
||||
/datum/ai_behavior/wash_target/finish_action(datum/ai_controller/controller, succeeded, target_key)
|
||||
. = ..()
|
||||
var/datum/action/cooldown/bot_announcement/announcement = controller.blackboard[BB_ANNOUNCE_ABILITY]
|
||||
|
||||
if(succeeded)
|
||||
if(controller.blackboard[BB_WASH_FRUSTRATION] > 0)
|
||||
announcement.announce(pick(controller.blackboard[BB_WASH_DONE]))
|
||||
controller.clear_blackboard_key(target_key)
|
||||
return
|
||||
|
||||
if(controller.blackboard[BB_WASH_FRUSTRATION] < BOT_FRUSTRATION_LIMIT)
|
||||
return
|
||||
|
||||
announcement.announce(pick(controller.blackboard[BB_WASH_THREATS]))
|
||||
controller.set_blackboard_key(BB_WASH_FRUSTRATION, 0)
|
||||
|
||||
#undef BOT_FRUSTRATION_LIMIT
|
||||
@@ -16,6 +16,7 @@
|
||||
BB_PREVIOUS_BEACON_TARGET,
|
||||
BB_BOT_SUMMON_TARGET,
|
||||
)
|
||||
ai_traits = PAUSE_DURING_DO_AFTER
|
||||
|
||||
/datum/ai_movement/jps/bot/medbot
|
||||
|
||||
@@ -185,7 +186,7 @@
|
||||
return can_see(source, patient, radius)
|
||||
|
||||
/datum/ai_behavior/announce_patient
|
||||
action_cooldown = 30 SECONDS
|
||||
action_cooldown = 3 MINUTES
|
||||
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
|
||||
/datum/ai_behavior/announce_patient/perform(seconds_per_tick, datum/ai_controller/basic_controller/bot/controller, target_key)
|
||||
|
||||
@@ -552,8 +552,8 @@
|
||||
to_chat(user, span_notice("You start to pipe up [src]..."))
|
||||
if(do_after(user, 40, target = src) && D.use(1))
|
||||
to_chat(user, span_notice("You pipe up [src]."))
|
||||
var/mob/living/simple_animal/bot/hygienebot/H = new(drop_location())
|
||||
H.name = created_name
|
||||
var/mob/living/basic/bot/hygienebot/new_bot = new(drop_location())
|
||||
new_bot.name = created_name
|
||||
qdel(src)
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct
|
||||
new /obj/item/assembly/prox_sensor(Tsec)
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
//Cleanbot
|
||||
/mob/living/simple_animal/bot/hygienebot
|
||||
name = "\improper Hygienebot"
|
||||
desc = "A flying cleaning robot, he'll chase down people who can't shower properly!"
|
||||
icon = 'icons/mob/silicon/aibots.dmi'
|
||||
icon_state = "hygienebot"
|
||||
base_icon_state = "hygienebot"
|
||||
pass_flags = PASSMOB | PASSFLAPS | PASSTABLE
|
||||
layer = MOB_UPPER_LAYER
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
health = 100
|
||||
maxHealth = 100
|
||||
|
||||
maints_access_required = list(ACCESS_ROBOTICS, ACCESS_JANITOR)
|
||||
radio_key = /obj/item/encryptionkey/headset_service
|
||||
radio_channel = RADIO_CHANNEL_SERVICE //Service
|
||||
bot_mode_flags = ~BOT_MODE_CAN_BE_SAPIENT
|
||||
bot_type = HYGIENE_BOT
|
||||
hackables = "cleaning service protocols"
|
||||
path_image_color = "#993299"
|
||||
|
||||
automated_announcements = list(
|
||||
HYGIENEBOT_VOICED_UNHYGIENIC = 'sound/voice/hygienebot/unhygienicclient.ogg',
|
||||
HYGIENEBOT_VOICED_ENJOY_DAY = 'sound/voice/hygienebot/cleanandtidy.ogg',
|
||||
HYGIENEBOT_VOICED_THREAT_AIRLOCK = 'sound/voice/hygienebot/dragyouout.ogg',
|
||||
HYGIENEBOT_VOICED_FOUL_SMELL = 'sound/voice/hygienebot/foulsmelling.ogg',
|
||||
HYGIENEBOT_VOICED_TROGLODYTE = 'sound/voice/hygienebot/troglodyte.ogg',
|
||||
HYGIENEBOT_VOICED_GREEN_CLOUD = 'sound/voice/hygienebot/greencloud.ogg',
|
||||
HYGIENEBOT_VOICED_ARSEHOLE = 'sound/voice/hygienebot/letmeclean.ogg',
|
||||
HYGIENEBOT_VOICED_THREAT_ARTERIES = 'sound/voice/hygienebot/cutarteries.ogg',
|
||||
HYGIENEBOT_VOICED_STOP_RUNNING = 'sound/voice/hygienebot/stoprunning.ogg',
|
||||
HYGIENEBOT_VOICED_FUCKING_FINALLY = 'sound/voice/hygienebot/finally.ogg',
|
||||
HYGIENEBOT_VOICED_THANK_GOD = 'sound/voice/hygienebot/thankgod.ogg',
|
||||
HYGIENEBOT_VOICED_DEGENERATE = 'sound/voice/hygienebot/degenerate.ogg',
|
||||
)
|
||||
|
||||
///The human target the bot is trying to wash.
|
||||
var/mob/living/carbon/human/target
|
||||
///The mob's current speed, which varies based on how long the bot chases it's target.
|
||||
var/currentspeed = 5
|
||||
///Is the bot currently washing it's target/everything else that crosses it?
|
||||
var/washing = FALSE
|
||||
///Have the target evaded the bot for long enough that it will swear at it like kirk did to kahn?
|
||||
var/mad = FALSE
|
||||
///The last time that the previous/current target was found.
|
||||
var/last_found
|
||||
///Name of the previous target the bot was pursuing.
|
||||
var/oldtarget_name
|
||||
///Visual overlay of the bot spraying water.
|
||||
var/mutable_appearance/water_overlay
|
||||
///Visual overlay of the bot commiting warcrimes.
|
||||
var/mutable_appearance/fire_overlay
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/Initialize(mapload)
|
||||
. = ..()
|
||||
update_appearance(UPDATE_ICON)
|
||||
|
||||
// Doing this hurts my soul, but simplebot access reworks are for another day.
|
||||
var/datum/id_trim/job/jani_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/janitor]
|
||||
access_card.add_access(jani_trim.access + jani_trim.wildcard_access)
|
||||
prev_access = access_card.access.Copy()
|
||||
var/static/list/loc_connections = list(
|
||||
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
||||
)
|
||||
AddElement(/datum/element/connect_loc, loc_connections)
|
||||
|
||||
ADD_TRAIT(src, TRAIT_SPRAY_PAINTABLE, INNATE_TRAIT)
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/explode()
|
||||
var/datum/effect_system/fluid_spread/foam/foam = new
|
||||
foam.set_up(2, holder = src, location = loc)
|
||||
foam.start()
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/on_entered(datum/source, atom/movable/AM)
|
||||
SIGNAL_HANDLER
|
||||
if(washing)
|
||||
do_wash(AM)
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/update_icon_state()
|
||||
. = ..()
|
||||
icon_state = "[base_icon_state][bot_mode_flags & BOT_MODE_ON ? "-on" : null]"
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/update_overlays()
|
||||
. = ..()
|
||||
if(bot_mode_flags & BOT_MODE_ON)
|
||||
. += mutable_appearance(icon, "hygienebot-flame")
|
||||
|
||||
if(washing)
|
||||
. += mutable_appearance(icon, bot_cover_flags & BOT_COVER_EMAGGED ? "hygienebot-fire" : "hygienebot-water")
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/turn_off()
|
||||
..()
|
||||
mode = BOT_IDLE
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/bot_reset()
|
||||
..()
|
||||
target = null
|
||||
oldtarget_name = null
|
||||
SSmove_manager.stop_looping(src)
|
||||
last_found = world.time
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/handle_automated_action()
|
||||
if(!..())
|
||||
return
|
||||
|
||||
if(washing)
|
||||
do_wash(loc)
|
||||
for(var/AM in loc)
|
||||
if (AM == src)
|
||||
continue
|
||||
do_wash(AM)
|
||||
if(isopenturf(loc) && !(bot_cover_flags & BOT_COVER_EMAGGED))
|
||||
var/turf/open/tile = loc
|
||||
tile.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
|
||||
|
||||
switch(mode)
|
||||
if(BOT_IDLE) // idle
|
||||
SSmove_manager.stop_looping(src)
|
||||
look_for_lowhygiene() // see if any disgusting fucks are in range
|
||||
if(!mode && bot_mode_flags & BOT_MODE_AUTOPATROL) // still idle, and set to patrol
|
||||
mode = BOT_START_PATROL // switch to patrol mode
|
||||
|
||||
if(BOT_HUNT) // hunting for stinkman
|
||||
if(bot_cover_flags & BOT_COVER_EMAGGED) //lol fuck em up
|
||||
currentspeed = 3.5
|
||||
start_washing()
|
||||
mad = TRUE
|
||||
else
|
||||
switch(frustration)
|
||||
if(0 to 4)
|
||||
currentspeed = 5
|
||||
mad = FALSE
|
||||
if(5 to INFINITY)
|
||||
currentspeed = 2.5
|
||||
mad = TRUE
|
||||
if(target && !check_purity(target))
|
||||
if(target.loc == loc && isturf(target.loc)) //LADIES AND GENTLEMAN WE GOTEM PREPARE TO DUMP
|
||||
start_washing()
|
||||
if(mad)
|
||||
var/static/list/relief = list(
|
||||
HYGIENEBOT_VOICED_FUCKING_FINALLY,
|
||||
HYGIENEBOT_VOICED_THANK_GOD,
|
||||
HYGIENEBOT_VOICED_DEGENERATE,
|
||||
)
|
||||
speak(pick(relief))
|
||||
playsound(loc, 'sound/effects/hygienebot_angry.ogg', 60, 1) //i think it should still make robot noises too
|
||||
mad = FALSE
|
||||
mode = BOT_SHOWERSTANCE
|
||||
else
|
||||
stop_washing()
|
||||
var/olddist = get_dist(src, target)
|
||||
if(olddist > 20 || frustration > 100) // Focus on something else
|
||||
back_to_idle()
|
||||
return
|
||||
SSmove_manager.move_to(src, target, 0, currentspeed)
|
||||
if(mad && prob(min(frustration * 2, 60)))
|
||||
var/static/list/threats = list(
|
||||
HYGIENEBOT_VOICED_THREAT_AIRLOCK,
|
||||
HYGIENEBOT_VOICED_FOUL_SMELL,
|
||||
HYGIENEBOT_VOICED_TROGLODYTE,
|
||||
HYGIENEBOT_VOICED_GREEN_CLOUD,
|
||||
HYGIENEBOT_VOICED_ARSEHOLE,
|
||||
HYGIENEBOT_VOICED_THREAT_ARTERIES,
|
||||
HYGIENEBOT_VOICED_STOP_RUNNING,
|
||||
)
|
||||
speak(pick(threats))
|
||||
playsound(loc, 'sound/effects/hygienebot_angry.ogg', 60, 1)
|
||||
if((get_dist(src, target)) >= olddist)
|
||||
frustration++
|
||||
else
|
||||
frustration = 0
|
||||
else
|
||||
back_to_idle()
|
||||
|
||||
if(BOT_SHOWERSTANCE)
|
||||
if(check_purity(target))
|
||||
speak(HYGIENEBOT_VOICED_ENJOY_DAY)
|
||||
playsound(loc, 'sound/effects/hygienebot_happy.ogg', 60, 1)
|
||||
back_to_idle()
|
||||
return
|
||||
if(!target)
|
||||
last_found = world.time
|
||||
if(target.loc != loc || !isturf(target.loc))
|
||||
back_to_hunt()
|
||||
|
||||
if(BOT_START_PATROL)
|
||||
look_for_lowhygiene()
|
||||
start_patrol()
|
||||
|
||||
if(BOT_PATROL)
|
||||
look_for_lowhygiene()
|
||||
bot_patrol()
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/back_to_idle()
|
||||
mode = BOT_IDLE
|
||||
SSmove_manager.stop_looping(src)
|
||||
target = null
|
||||
frustration = 0
|
||||
last_found = world.time
|
||||
stop_washing()
|
||||
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/back_to_hunt()
|
||||
frustration = 0
|
||||
mode = BOT_HUNT
|
||||
stop_washing()
|
||||
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/look_for_lowhygiene()
|
||||
for (var/mob/living/carbon/human/H in view(7,src)) //Find the NEET
|
||||
if((H.name == oldtarget_name) && (world.time < last_found + 100))
|
||||
continue
|
||||
if(!check_purity(H)) //Theyre impure
|
||||
target = H
|
||||
oldtarget_name = H.name
|
||||
speak(HYGIENEBOT_VOICED_UNHYGIENIC)
|
||||
playsound(loc, 'sound/effects/hygienebot_happy.ogg', 60, 1)
|
||||
visible_message("<b>[src]</b> points at [H.name]!")
|
||||
mode = BOT_HUNT
|
||||
INVOKE_ASYNC(src, PROC_REF(handle_automated_action))
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/start_washing()
|
||||
washing = TRUE
|
||||
update_appearance()
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/stop_washing()
|
||||
washing = FALSE
|
||||
update_appearance()
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/check_purity(mob/living/L)
|
||||
if((bot_cover_flags & BOT_COVER_EMAGGED) && L.stat != DEAD)
|
||||
return FALSE
|
||||
|
||||
for(var/X in list(ITEM_SLOT_HEAD, ITEM_SLOT_MASK, ITEM_SLOT_ICLOTHING, ITEM_SLOT_OCLOTHING, ITEM_SLOT_FEET))
|
||||
|
||||
var/obj/item/I = L.get_item_by_slot(X)
|
||||
if(I && GET_ATOM_BLOOD_DNA_LENGTH(I))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/bot/hygienebot/proc/do_wash(atom/A)
|
||||
if(bot_cover_flags & BOT_COVER_EMAGGED)
|
||||
A.fire_act() //lol pranked no cleaning besides that
|
||||
else
|
||||
A.wash(CLEAN_WASH)
|
||||
@@ -8,7 +8,6 @@
|
||||
/mob/living/simple_animal/bot,
|
||||
/mob/living/simple_animal/bot/firebot,
|
||||
/mob/living/simple_animal/bot/floorbot,
|
||||
/mob/living/simple_animal/bot/hygienebot,
|
||||
/mob/living/simple_animal/bot/mulebot,
|
||||
/mob/living/simple_animal/bot/mulebot/paranormal,
|
||||
/mob/living/simple_animal/bot/secbot,
|
||||
|
||||
@@ -4577,6 +4577,8 @@
|
||||
#include "code\modules\mob\living\basic\bots\cleanbot\cleanbot.dm"
|
||||
#include "code\modules\mob\living\basic\bots\cleanbot\cleanbot_abilities.dm"
|
||||
#include "code\modules\mob\living\basic\bots\cleanbot\cleanbot_ai.dm"
|
||||
#include "code\modules\mob\living\basic\bots\hygienebot\hygienebot.dm"
|
||||
#include "code\modules\mob\living\basic\bots\hygienebot\hygienebot_ai.dm"
|
||||
#include "code\modules\mob\living\basic\bots\medbot\medbot.dm"
|
||||
#include "code\modules\mob\living\basic\bots\medbot\medbot_ai.dm"
|
||||
#include "code\modules\mob\living\basic\clown\clown.dm"
|
||||
@@ -4994,7 +4996,6 @@
|
||||
#include "code\modules\mob\living\simple_animal\bot\firebot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\floorbot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\honkbot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\hygienebot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\mulebot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\secbot.dm"
|
||||
#include "code\modules\mob\living\simple_animal\bot\SuperBeepsky.dm"
|
||||
|
||||
Reference in New Issue
Block a user