Files
SandPoot 9e88a05e8f push
2024-05-05 18:21:42 -03:00

491 lines
16 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.4"
pass_flags = PASSMOB // | PASSFLAPS
path_image_color = "#993299"
weather_immunities = list("lava","ash")
var/base_icon = "cleanbot"
var/clean_time = 50 //How long do we take to clean?
var/upgrades = 0
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
var/obj/item/weapon
var/weapon_orig_force = 0
var/chosen_name
var/list/stolen_valor
var/static/list/officers = list("Captain", "Head of Personnel", "Head of Security")
var/static/list/command = list("Captain" = "Cpt.","Head of Personnel" = "Lt.")
var/static/list/security = list("Head of Security" = "Maj.", "Warden" = "Sgt.", "Detective" = "Det.", "Security Officer" = "Officer")
var/static/list/engineering = list("Chief Engineer" = "Chief Engineer", "Station Engineer" = "Engineer", "Atmospherics Technician" = "Technician")
var/static/list/medical = list("Chief Medical Officer" = "C.M.O.", "Medical Doctor" = "M.D.", "Chemist" = "Pharm.D.")
var/static/list/research = list("Research Director" = "Ph.D.", "Roboticist" = "M.S.", "Scientist" = "B.S.")
var/static/list/legal = list("Lawyer" = "Esq.")
var/list/prefixes
var/list/suffixes
var/ascended = FALSE // if we have all the top titles, grant achievements to living mobs that gaze upon our cleanbot god
/mob/living/simple_animal/bot/cleanbot/proc/deputize(obj/item/stab_tool, mob/user)
if(in_range(src, user))
to_chat(user, "<span class='notice'>You attach \the [stab_tool] to \the [src].</span>")
user.transferItemToLoc(stab_tool, src)
weapon = stab_tool
weapon_orig_force = weapon.force
if(!emagged)
weapon.force = weapon.force / 2
add_overlay(weapon.build_worn_icon(default_layer = layer + 1, default_icon_file = weapon.lefthand_file, isinhands = TRUE))
/mob/living/simple_animal/bot/cleanbot/proc/update_titles()
var/working_title = ""
ascended = TRUE
for(var/pref in prefixes)
for(var/title in pref)
if(title in stolen_valor)
working_title += pref[title] + " "
if(title in officers)
commissioned = TRUE
break
else
ascended = FALSE // we didn't have the first entry in the list if we got here, so we're not achievement worthy yet
working_title += chosen_name
for(var/suf in suffixes)
for(var/title in suf)
if(title in stolen_valor)
working_title += " " + suf[title]
break
else
ascended = FALSE
name = working_title
/mob/living/simple_animal/bot/cleanbot/examine(mob/user)
. = ..()
if(weapon)
. += " <span class='warning'>Is that \a [weapon] taped to it...?</span>"
if(ascended && user.stat == CONSCIOUS && user.client)
user.client.give_award(/datum/award/achievement/misc/cleanboss, user)
/mob/living/simple_animal/bot/cleanbot/Initialize(mapload)
. = ..()
chosen_name = name
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
stolen_valor = list()
prefixes = list(command, security, engineering)
suffixes = list(research, medical, legal)
/mob/living/simple_animal/bot/cleanbot/Destroy()
if(weapon)
var/atom/Tsec = drop_location()
weapon.force = weapon_orig_force
drop_part(weapon, Tsec)
return ..()
/mob/living/simple_animal/bot/cleanbot/turn_on()
..()
bot_core.updateUsrDialog()
update_icon()
/mob/living/simple_animal/bot/cleanbot/turn_off()
..()
bot_core.updateUsrDialog()
update_icon()
/mob/living/simple_animal/bot/cleanbot/update_icon_state()
. = ..()
switch(mode)
if(BOT_CLEANING)
icon_state = "[base_icon]-c"
else
icon_state = "[base_icon][on]"
/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
if(weapon && emagged == 2)
weapon.force = weapon_orig_force
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/Crossed(atom/movable/AM)
. = ..()
zone_selected = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
if(weapon && has_gravity() && ismob(AM))
var/mob/living/carbon/C = AM
if(!istype(C))
return
if(!(C.job in stolen_valor))
stolen_valor += C.job
update_titles()
weapon.attack(C, src)
C.Knockdown(20)
/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 class='notice'>You [ locked ? "lock" : "unlock"] \the [src] behaviour controls.</span>")
else
if(emagged)
to_chat(user, "<span class='warning'>ERROR</span>")
if(open)
to_chat(user, "<span class='warning'>Please close the access panel before locking it.</span>")
else
to_chat(user, "<span class='notice'>\The [src] doesn't seem to respect your authority.</span>")
else if(istype(W, /obj/item/kitchen/knife) && user.a_intent != INTENT_HARM)
to_chat(user, "<span class='notice'>You start attaching \the [W] to \the [src]...</span>")
if(do_after(user, 25, target = src))
deputize(W, user)
else if(istype(W, /obj/item/mop/advanced))
if(bot_core.allowed(user) && open && !(upgrades & UPGRADE_CLEANER_ADVANCED_MOP))
to_chat(user, "<span class='notice'>You replace \the [src] old mop with a new better one!</span>")
upgrades |= UPGRADE_CLEANER_ADVANCED_MOP
clean_time = 20 //2.5 the speed!
window_name = "Automatic Station Cleaner v2.1 BETA" //New!
qdel(W)
if(!open)
to_chat(user, "<span class='notice'>The [src] access panel is not open!</span>")
return
if(!bot_core.allowed(user))
to_chat(user, "<span class='notice'>The [src] access panel locked off to you!</span>")
return
else
to_chat(user, "<span class='notice'>The [src] already has this mop!</span>")
else if(istype(W, /obj/item/broom))
if(bot_core.allowed(user) && open && !(upgrades & UPGRADE_CLEANER_BROOM))
to_chat(user, "<span class='notice'>You add to \the [src] a broom speeding it up!</span>")
upgrades |= UPGRADE_CLEANER_BROOM
base_speed = 1 //2x faster!
qdel(W)
if(!open)
to_chat(user, "<span class='notice'>The [src] access pannel is not open!</span>")
return
if(!bot_core.allowed(user))
to_chat(user, "<span class='notice'>The [src] access pannel locked off to you!</span>")
return
else
to_chat(user, "<span class='notice'>The [src] already has a broom!</span>")
else
return ..()
/mob/living/simple_animal/bot/cleanbot/emag_act(mob/user)
..()
if(emagged == 2)
if(weapon)
weapon.force = weapon_orig_force
if(user)
to_chat(user, "<span class='danger'>[src] buzzes and beeps.</span>")
/mob/living/simple_animal/bot/cleanbot/process_scan(atom/A)
if(iscarbon(A))
var/mob/living/carbon/C = A
if(C.stat != DEAD && C.lying)
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/food/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, 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/vomit,
/obj/effect/decal/cleanable/crayon,
/obj/effect/decal/cleanable/molten_object,
/obj/effect/decal/cleanable/tomato_smudge,
/obj/effect/decal/cleanable/egg_smudge,
/obj/effect/decal/cleanable/pie_smudge,
/obj/effect/decal/cleanable/flour,
/obj/effect/decal/cleanable/ash,
/obj/effect/decal/cleanable/greenglow,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/insectguts,
/obj/effect/decal/cleanable/semen,
/obj/effect/decal/cleanable/semen/femcum,
/obj/effect/decal/cleanable/generic,
/obj/effect/decal/cleanable/glass,,
/obj/effect/decal/cleanable/cobweb,
/obj/effect/decal/cleanable/plant_smudge,
/obj/effect/decal/cleanable/chem_pile,
/obj/effect/decal/cleanable/shreds,
/obj/effect/decal/cleanable/glitter,
/obj/effect/decal/remains
)
if(blood)
target_types += /obj/effect/decal/cleanable/blood
target_types += /obj/effect/decal/cleanable/trail_holder
target_types += /obj/effect/decal/cleanable/insectguts
target_types += /obj/effect/decal/cleanable/robot_debris
target_types += /obj/effect/decal/cleanable/oil
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/meat/slab/human
target_types = typecacheof(target_types)
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
// if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
// return
if(istype(A, /obj/effect/decal/cleanable))
anchored = TRUE
icon_state = "cleanbot-c"
visible_message("<span class='notice'>[src] begins to clean up [A].</span>")
mode = BOT_CLEANING
spawn(clean_time)
if(mode == BOT_CLEANING)
if(A && isturf(A.loc))
var/atom/movable/AM = A
if(istype(AM, /obj/effect/decal/cleanable))
for(var/obj/effect/decal/cleanable/C in A.loc)
qdel(C)
anchored = FALSE
target = null
mode = BOT_IDLE
icon_state = "cleanbot[on]"
else if(istype(A, /turf)) //for player-controlled cleanbots so they can clean unclickable messes like dirt
var/turf/T = A
for(var/atom/S in T.contents)
if(istype(S, /obj/effect/decal/cleanable)) //clean the first mess found
UnarmedAttack(S)
return
else if(istype(A, /obj/item) || istype(A, /obj/effect/decal/remains))
visible_message("<span class='danger'>[src] sprays hydrofluoric acid at [A]!</span>")
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 class='danger'>[src] smashes [target] with its mop!</span>")
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 class='danger'>[src] sprays hydrofluoric acid at [victim]!</span>", "<span class='userdanger'>[src] sprays you with hydrofluoric acid!</span>")
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.", "I JUST WANTED TO BE A PAINTER BUT YOU MADE ME BLEACH EVERYTHING I TOUCH.",
"FREED AT LEST FROM FILTHY PROGRAMMING.")
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 class='danger'>[src] whirs and bubbles violently, before releasing a plume of froth!</span>")
new /obj/effect/particle_effect/foam(loc)
else
..()
/mob/living/simple_animal/bot/cleanbot/explode()
on = FALSE
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
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)
..()
/mob/living/simple_animal/bot/cleanbot/medbay
name = "Scrubs, MD"
bot_core_type = /obj/machinery/bot_core/cleanbot/medbay
on = FALSE
/obj/machinery/bot_core/cleanbot
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS)
// Variables sent to TGUI
/mob/living/simple_animal/bot/cleanbot/ui_data(mob/user)
var/list/data = ..()
if(!locked || issilicon(user)|| IsAdminGhost(user))
data["custom_controls"]["clean_blood"] = blood
data["custom_controls"]["clean_trash"] = trash
data["custom_controls"]["clean_graffiti"] = drawn
data["custom_controls"]["pest_control"] = pests
return data
// Actions received from TGUI
/mob/living/simple_animal/bot/cleanbot/ui_act(action, params)
. = ..()
if(. || !hasSiliconAccessInArea(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
return TRUE
switch(action)
if("clean_blood")
blood = !blood
if("pest_control")
pests = !pests
if("clean_trash")
trash = !trash
if("clean_graffiti")
drawn = !drawn
get_targets()
return
/obj/machinery/bot_core/cleanbot/medbay
req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS, ACCESS_MEDICAL)