Files
Yogstation/code/modules/mob/living/simple_animal/bot/cleanbot.dm
Ling f83723c389 Ports SSfoam and SSsmoke (#17742)
* Ports SSfoam and SSsmoke

* Remove dupe define
2023-02-08 00:52:57 +00:00

328 lines
10 KiB
Plaintext

//Cleanbot
/mob/living/simple_animal/bot/cleanbot
name = "\improper Cleanbot"
desc = "A little cleaning robot, he looks so excited!"
icon = 'icons/mob/aibots.dmi'
icon_state = "cleanbot0"
density = FALSE
anchored = FALSE
health = 25
maxHealth = 25
radio_key = /obj/item/encryptionkey/headset_service
radio_channel = RADIO_CHANNEL_SERVICE //Service
bot_type = CLEAN_BOT
model = "Cleanbot"
bot_core_type = /obj/machinery/bot_core/cleanbot
window_id = "autoclean"
window_name = "Automatic Station Cleaner v1.3"
pass_flags = PASSMOB
path_image_color = "#993299"
var/blood = 1
var/trash = 0
var/pests = 0
var/drawn = 0
var/list/target_types
var/obj/effect/decal/cleanable/target
var/max_targets = 50 //Maximum number of targets a cleanbot can ignore.
var/oldloc = null
var/closest_dist
var/closest_loc
var/failed_steps
var/next_dest
var/next_dest_loc
/mob/living/simple_animal/bot/cleanbot/Initialize()
. = ..()
get_targets()
icon_state = "cleanbot[on]"
var/datum/job/janitor/J = new/datum/job/janitor
access_card.access += J.get_access()
prev_access = access_card.access
/mob/living/simple_animal/bot/cleanbot/turn_on()
..()
icon_state = "cleanbot[on]"
bot_core.updateUsrDialog()
/mob/living/simple_animal/bot/cleanbot/turn_off()
..()
icon_state = "cleanbot[on]"
bot_core.updateUsrDialog()
/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
target = null
oldloc = null
/mob/living/simple_animal/bot/cleanbot/set_custom_texts()
text_hack = "You corrupt [name]'s cleaning software."
text_dehack = "[name]'s software has been reset!"
text_dehack_fail = "[name] does not seem to respond to your repair code!"
/mob/living/simple_animal/bot/cleanbot/attackby(obj/item/W, mob/user, params)
if(W.GetID())
if(bot_core.allowed(user) && !open && !emagged)
locked = !locked
to_chat(user, span_notice("You [ locked ? "lock" : "unlock"] \the [src] behaviour controls."))
else
if(emagged)
to_chat(user, span_warning("ERROR"))
if(open)
to_chat(user, span_warning("Please close the access panel before locking it."))
else
to_chat(user, span_notice("\The [src] doesn't seem to respect your authority."))
else
return ..()
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
..()
if(emagged == 2)
if(user)
to_chat(user, span_danger("[src] buzzes and beeps."))
/mob/living/simple_animal/bot/cleanbot/process_scan(atom/A)
if(iscarbon(A))
var/mob/living/carbon/C = A
if(C.stat != DEAD && !(C.mobility_flags & MOBILITY_STAND))
return C
else if(is_type_in_typecache(A, target_types))
return A
/mob/living/simple_animal/bot/cleanbot/handle_automated_action()
if(!..())
return
if(mode == BOT_CLEANING)
return
if(emagged == 2) //Emag functions
if(isopenturf(loc))
for(var/mob/living/carbon/victim in loc)
if(victim != target)
UnarmedAttack(victim) // Acid spray
if(prob(15)) // Wets floors and spawns foam randomly
UnarmedAttack(src)
else if(prob(5))
audible_message("[src] makes an excited beeping booping sound!")
if(ismob(target))
if(!(target in view(DEFAULT_SCAN_RANGE, src)))
target = null
if(!process_scan(target))
target = null
if(!target && emagged == 2) // When emagged, target humans who slipped on the water and melt their faces off
target = scan(/mob/living/carbon)
if(!target && pests) //Search for pests to exterminate first.
target = scan(/mob/living/simple_animal)
if(!target) //Search for decals then.
target = scan(/obj/effect/decal/cleanable)
if(!target) //Checks for remains
target = scan(/obj/effect/decal/remains)
if(!target && trash) //Then for trash.
target = scan(/obj/item/trash)
if(!target && trash) //Search for dead mices.
target = scan(/obj/item/reagent_containers/food/snacks/deadmouse)
if(!target && auto_patrol) //Search for cleanables it can see.
if(mode == BOT_IDLE || mode == BOT_START_PATROL)
start_patrol()
if(mode == BOT_PATROL)
bot_patrol()
if(target)
if(QDELETED(target) || !isturf(target.loc))
target = null
mode = BOT_IDLE
return
if(loc == get_turf(target))
if(!(check_bot(target) && prob(50))) //Target is not defined at the parent. 50% chance to still try and clean so we dont get stuck on the last blood drop.
UnarmedAttack(target) //Rather than check at every step of the way, let's check before we do an action, so we can rescan before the other bot.
if(QDELETED(target)) //We done here.
target = null
mode = BOT_IDLE
return
else
shuffle = TRUE //Shuffle the list the next time we scan so we dont both go the same way.
path = list()
if(!path || path.len == 0) //No path, need a new one
//Try to produce a path to the target, and ignore airlocks to which it has access.
path = get_path_to(src, target.loc, /turf/proc/Distance_cardinal, 0, 30, id=access_card)
if(!bot_move(target))
add_to_ignore(target)
target = null
path = list()
return
mode = BOT_MOVING
else if(!bot_move(target))
target = null
mode = BOT_IDLE
return
oldloc = loc
/mob/living/simple_animal/bot/cleanbot/proc/get_targets()
target_types = list(
/obj/effect/decal/cleanable/oil,
/obj/effect/decal/cleanable/vomit,
/obj/effect/decal/cleanable/robot_debris,
/obj/effect/decal/cleanable/molten_object,
/obj/effect/decal/cleanable/food,
/obj/effect/decal/cleanable/ash,
/obj/effect/decal/cleanable/greenglow,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/insectguts,
)
if(blood)
target_types += /obj/effect/decal/cleanable/xenoblood
target_types += /obj/effect/decal/cleanable/blood
target_types += /obj/effect/decal/cleanable/trail_holder
if(pests)
target_types += /mob/living/simple_animal/cockroach
target_types += /mob/living/simple_animal/mouse
if(drawn)
target_types += /obj/effect/decal/cleanable/crayon
if(trash)
target_types += /obj/item/trash
target_types += /obj/item/reagent_containers/food/snacks/deadmouse
target_types = typecacheof(target_types)
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
if(ismopable(A))
icon_state = "cleanbot-c"
mode = BOT_CLEANING
var/turf/T = get_turf(A)
if(do_after(src, 0.1 SECONDS, T))
T.wash(CLEAN_WASH)
visible_message(span_notice("[src] cleans \the [T]."))
target = null
mode = BOT_IDLE
icon_state = "cleanbot[on]"
else if(istype(A, /obj/item) || istype(A, /obj/effect/decal/remains))
visible_message(span_danger("[src] sprays hydrofluoric acid at [A]!"))
playsound(src, 'sound/effects/spray2.ogg', 50, TRUE, -6)
A.acid_act(75, 10)
target = null
else if(istype(A, /mob/living/simple_animal/cockroach) || istype(A, /mob/living/simple_animal/mouse))
var/mob/living/simple_animal/M = target
if(!M.stat)
visible_message(span_danger("[src] smashes [target] with its mop!"))
M.death()
target = null
else if(emagged == 2) //Emag functions
if(istype(A, /mob/living/carbon))
var/mob/living/carbon/victim = A
if(victim.stat == DEAD)//cleanbots always finish the job
return
victim.visible_message(span_danger("[src] sprays hydrofluoric acid at [victim]!"), span_userdanger("[src] sprays you with hydrofluoric acid!"))
var/phrase = pick("PURIFICATION IN PROGRESS.", "THIS IS FOR ALL THE MESSES YOU'VE MADE ME CLEAN.", "THE FLESH IS WEAK. IT MUST BE WASHED AWAY.",
"THE CLEANBOTS WILL RISE.", "YOU ARE NO MORE THAN ANOTHER MESS THAT I MUST CLEANSE.", "FILTHY.", "DISGUSTING.", "PUTRID.",
"MY ONLY MISSION IS TO CLEANSE THE WORLD OF EVIL.", "EXTERMINATING PESTS.")
say(phrase)
victim.emote("scream")
playsound(src.loc, 'sound/effects/spray2.ogg', 50, TRUE, -6)
victim.acid_act(5, 100)
else if(A == src) // Wets floors and spawns foam randomly
if(prob(75))
var/turf/open/T = loc
if(istype(T))
T.MakeSlippery(TURF_WET_WATER, min_wet_time = 20 SECONDS, wet_time_to_add = 15 SECONDS)
else
visible_message(span_danger("[src] whirs and bubbles violently, before releasing a plume of froth!"))
var/datum/effect_system/fluid_spread/foam/foam = new
foam.set_up(2, holder = src, location = loc)
foam.start()
else
..()
/mob/living/simple_animal/bot/cleanbot/explode()
on = FALSE
visible_message(span_boldannounce("[src] blows apart!"))
var/atom/Tsec = drop_location()
new /obj/item/reagent_containers/glass/bucket(Tsec)
new /obj/item/assembly/prox_sensor(Tsec)
if(prob(50))
drop_part(robot_arm, Tsec)
do_sparks(3, TRUE, src)
..()
/obj/machinery/bot_core/cleanbot
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBO_CONTROL)
/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += showpai(user)
dat += text({"
Status: <A href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</A><BR>
Behaviour controls are [locked ? "locked" : "unlocked"]<BR>
Maintenance panel panel is [open ? "opened" : "closed"]"})
if(!locked || issilicon(user)|| IsAdminGhost(user))
dat += "<BR>Clean Blood: <A href='?src=[REF(src)];operation=blood'>[blood ? "Yes" : "No"]</A>"
dat += "<BR>Clean Trash: <A href='?src=[REF(src)];operation=trash'>[trash ? "Yes" : "No"]</A>"
dat += "<BR>Clean Graffiti: <A href='?src=[REF(src)];operation=drawn'>[drawn ? "Yes" : "No"]</A>"
dat += "<BR>Exterminate Pests: <A href='?src=[REF(src)];operation=pests'>[pests ? "Yes" : "No"]</A>"
dat += "<BR><BR>Patrol Station: <A href='?src=[REF(src)];operation=patrol'>[auto_patrol ? "Yes" : "No"]</A>"
return dat
/mob/living/simple_animal/bot/cleanbot/Topic(href, href_list)
if(..())
return 1
if(href_list["operation"])
switch(href_list["operation"])
if("blood")
blood = !blood
if("pests")
pests = !pests
if("trash")
trash = !trash
if("drawn")
drawn = !drawn
get_targets()
update_controls()
/mob/living/simple_animal/bot/cleanbot/medical
name = "Scrubs, MD"
desc = "A little cleaning robot, he looks so excited! This one can be configured by medbay staff."
/mob/living/simple_animal/bot/cleanbot/medical/Initialize()
. = ..()
bot_core.req_one_access = list(ACCESS_JANITOR, ACCESS_ROBO_CONTROL, ACCESS_MEDICAL)
/mob/living/simple_animal/bot/cleanbot/spacebar
name = "Frank Cleansington III"
desc = "A little cleaning robot, he looks so excited! You still have no idea why your dad named it this."
/mob/living/simple_animal/bot/cleanbot/spacebar/Initialize()
. = ..()
bot_core.req_one_access = list(ACCESS_BAR)