Updates bots to be mobs. Several changes.

General:
Bots are now /mob/living/bot. They support player control fully. Just in
case an admin feels like letting a ghost take control of beepsky or
something.
Since they are bots, spooders and whatnot will attack them.
They now don't need an open panel to be emagged.
Spawns replaced with do_after, meaning that they will stop
injecting/cleaning/repairing/arresting if pulled away.

Medbot:
Emagger is added to ignore list.
Will now inject spaceacilin regardeless of disease type and level.
Previously: only if disease was past stage 1 or airbone.

Cleanbot:
Patrolling rewritten. They now find a closest beacon, and go to the NEXT
beacon after the closest one.
They will not wiggle out when pulled.
They will now ignore (for a while) the gibs they make if odd button is
pressed.
They will now freely claim cleanables. Previously, they would not target
ones targeted by other bots.

Floorbot:
This was a helluva buggy one.
They will now build bridges (but still won't do random repairs) in space
area.
They will now build bridges even if the tile directly next to them in
that direction is tiled.
They will now ignore for a while a tile they can't reach. This is to
stop them from hopelessly targeting tiles under grilles for upgrades and
getting stuck.
They will now slowly (200 ticks for a tile) build new tiles on their
own.
They will now preserve tile's icon when repairing it like a player
would.
They will now place first rods, then tile when fixing space breaches.
Rod costs two tiles.
When emagged, they will first always tear off the tile, then will (over
triple the normal amount of time) breach the tile to space. There are
noticeable warnings for both actions.

Secbot:
Will no longer run away to patrol when panel is open.
Now deals stamina damage instead of instastuns.
Small delay between approaching the target and stunning them.
Laserbots axed.
Removed their weird EMP act.
Will no longer stun lying people, just cuff.
They will also demand surrenderring (lying down) before smacking you. If
target moves, or 5 seconds pass, it will attack.

Farmbot:
It's alive!
It has settings to: water trays, refill its own water, uproot weeds, add
nutriment (ammonia, internal synthesizer), collect produce, and remove
dead plants.
This commit is contained in:
Kelenius
2015-04-26 15:30:11 +03:00
parent c7a4a77f50
commit 6d1614cb7a
27 changed files with 2352 additions and 3206 deletions

View File

@@ -366,12 +366,7 @@
#include "code\game\machinery\atmoalter\pump.dm"
#include "code\game\machinery\atmoalter\scrubber.dm"
#include "code\game\machinery\bots\bots.dm"
#include "code\game\machinery\bots\cleanbot.dm"
#include "code\game\machinery\bots\ed209bot.dm"
#include "code\game\machinery\bots\floorbot.dm"
#include "code\game\machinery\bots\medbot.dm"
#include "code\game\machinery\bots\mulebot.dm"
#include "code\game\machinery\bots\secbot.dm"
#include "code\game\machinery\camera\camera.dm"
#include "code\game\machinery\camera\camera_assembly.dm"
#include "code\game\machinery\camera\motion.dm"
@@ -1073,6 +1068,13 @@
#include "code\modules\mob\living\logout.dm"
#include "code\modules\mob\living\say.dm"
#include "code\modules\mob\living\blob\blob.dm"
#include "code\modules\mob\living\bot\bot.dm"
#include "code\modules\mob\living\bot\cleanbot.dm"
#include "code\modules\mob\living\bot\ed209bot.dm"
#include "code\modules\mob\living\bot\farmbot.dm"
#include "code\modules\mob\living\bot\floorbot.dm"
#include "code\modules\mob\living\bot\medbot.dm"
#include "code\modules\mob\living\bot\secbot.dm"
#include "code\modules\mob\living\carbon\breathe.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
#include "code\modules\mob\living\carbon\carbon_defines.dm"

View File

@@ -1,363 +0,0 @@
//Cleanbot assembly
/obj/item/weapon/bucket_sensor
desc = "It's a bucket. With a sensor attached."
name = "proxy bucket"
icon = 'icons/obj/aibots.dmi'
icon_state = "bucket_proxy"
force = 3.0
throwforce = 10.0
throw_speed = 2
throw_range = 5
w_class = 3.0
var/created_name = "Cleanbot"
//Cleanbot
/obj/machinery/bot/cleanbot
name = "Cleanbot"
desc = "A little cleaning robot, he looks so excited!"
icon = 'icons/obj/aibots.dmi'
icon_state = "cleanbot0"
layer = 5.0
density = 0
anchored = 0
//weight = 1.0E7
health = 25
maxhealth = 25
var/cleaning = 0
var/screwloose = 0
var/oddbutton = 0
var/blood = 1
var/list/target_types = list()
var/obj/effect/decal/cleanable/target
var/obj/effect/decal/cleanable/oldtarget
var/oldloc = null
req_access = list(access_janitor)
var/path[] = new()
var/patrol_path[] = null
var/beacon_freq = 1445 // navigation beacon frequency
var/closest_dist
var/closest_loc
var/failed_steps
var/should_patrol
var/next_dest
var/next_dest_loc
/obj/machinery/bot/cleanbot/New()
..()
src.get_targets()
src.icon_state = "cleanbot[src.on]"
should_patrol = 1
src.botcard = new /obj/item/weapon/card/id(src)
src.botcard.access = list(access_janitor, access_maint_tunnels)
src.locked = 0 // Start unlocked so roboticist can set them to patrol.
if(radio_controller)
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
/obj/machinery/bot/cleanbot/turn_on()
. = ..()
src.icon_state = "cleanbot[src.on]"
src.updateUsrDialog()
/obj/machinery/bot/cleanbot/turn_off()
..()
if(!isnull(src.target))
target.targeted_by = null
src.target = null
src.oldtarget = null
src.oldloc = null
src.icon_state = "cleanbot[src.on]"
src.path = new()
src.updateUsrDialog()
/obj/machinery/bot/cleanbot/attack_hand(mob/user as mob)
. = ..()
if (.)
return
usr.set_machine(src)
interact(user)
/obj/machinery/bot/cleanbot/interact(mob/user as mob)
var/dat
dat += text({"
<TT><B>Automatic Station Cleaner v1.0</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [src.locked ? "locked" : "unlocked"]<BR>
Maintenance panel is [src.open ? "opened" : "closed"]"},
text("<A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A>"))
if(!src.locked || issilicon(user))
dat += text({"<BR>Cleans Blood: []<BR>"}, text("<A href='?src=\ref[src];operation=blood'>[src.blood ? "Yes" : "No"]</A>"))
dat += text({"<BR>Patrol station: []<BR>"}, text("<A href='?src=\ref[src];operation=patrol'>[src.should_patrol ? "Yes" : "No"]</A>"))
// dat += text({"<BR>Beacon frequency: []<BR>"}, text("<A href='?src=\ref[src];operation=freq'>[src.beacon_freq]</A>"))
if(src.open && !src.locked)
dat += text({"
Odd looking screw twiddled: []<BR>
Weird button pressed: []"},
text("<A href='?src=\ref[src];operation=screw'>[src.screwloose ? "Yes" : "No"]</A>"),
text("<A href='?src=\ref[src];operation=oddbutton'>[src.oddbutton ? "Yes" : "No"]</A>"))
user << browse("<HEAD><TITLE>Cleaner v1.0 controls</TITLE></HEAD>[dat]", "window=autocleaner")
onclose(user, "autocleaner")
return
/obj/machinery/bot/cleanbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
switch(href_list["operation"])
if("start")
if (src.on)
turn_off()
else
turn_on()
if("blood")
src.blood =!src.blood
src.get_targets()
src.updateUsrDialog()
if("patrol")
src.should_patrol =!src.should_patrol
src.patrol_path = null
src.updateUsrDialog()
if("freq")
var/freq = text2num(input("Select frequency for navigation beacons", "Frequnecy", num2text(beacon_freq / 10))) * 10
if (freq > 0)
src.beacon_freq = freq
src.updateUsrDialog()
if("screw")
src.screwloose = !src.screwloose
usr << "<span class='notice>You twiddle the screw.</span>"
src.updateUsrDialog()
if("oddbutton")
src.oddbutton = !src.oddbutton
usr << "<span class='notice'>You press the weird button.</span>"
src.updateUsrDialog()
/obj/machinery/bot/cleanbot/attackby(obj/item/weapon/W, mob/user as mob)
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if(src.allowed(usr) && !open && !emagged)
src.locked = !src.locked
user << "<span class='notice'>You [ src.locked ? "lock" : "unlock"] the [src] behaviour controls.</span>"
else
if(emagged)
user << "<span class='warning'>ERROR</span>"
if(open)
user << "<span class='warning'>Please close the access panel before locking it.</span>"
else
user << "<span class='notice'>This [src] doesn't seem to respect your authority.</span>"
else
return ..()
/obj/machinery/bot/cleanbot/Emag(mob/user as mob)
..()
if(open && !locked)
if(user) user << "<span class='notice'>The [src] buzzes and beeps.</span>"
src.oddbutton = 1
src.screwloose = 1
/obj/machinery/bot/cleanbot/process()
set background = 1
if(!src.on)
return
if(src.cleaning)
return
if(!src.screwloose && !src.oddbutton && prob(5))
visible_message("[src] makes an excited beeping booping sound!")
if(src.screwloose && prob(5))
if(istype(loc,/turf/simulated))
var/turf/simulated/T = src.loc
if(T.wet < 1)
T.wet = 1
if(T.wet_overlay)
T.overlays -= T.wet_overlay
T.wet_overlay = null
T.wet_overlay = image('icons/effects/water.dmi',T,"wet_floor")
T.overlays += T.wet_overlay
spawn(800)
if (istype(T) && T.wet < 2)
T.wet = 0
if(T.wet_overlay)
T.overlays -= T.wet_overlay
T.wet_overlay = null
if(src.oddbutton && prob(5))
visible_message("Something flies out of [src]. He seems to be acting oddly.")
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(src.loc)
//gib.streak(list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
src.oldtarget = gib
if(!src.target || src.target == null)
for (var/obj/effect/decal/cleanable/D in view(7,src))
for(var/T in src.target_types)
if(isnull(D.targeted_by) && istype(D, T) && D != src.oldtarget) // If the mess isn't targeted (D.type == T || D.parent_type == T)
src.oldtarget = D // or if it is but the bot is gone.
src.target = D // and it's stuff we clean? Clean it.
D.targeted_by = src // Claim the mess we are targeting.
return
if(!src.target || src.target == null)
if(src.loc != src.oldloc)
src.oldtarget = null
if (!should_patrol)
return
if (!patrol_path || patrol_path.len < 1)
var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq)
if(!frequency) return
closest_dist = 9999
closest_loc = null
next_dest_loc = null
var/datum/signal/signal = new()
signal.source = src
signal.transmission_method = 1
signal.data = list("findbeacon" = "patrol")
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
spawn(5)
if (!next_dest_loc)
next_dest_loc = closest_loc
if (next_dest_loc)
src.patrol_path = AStar(src.loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=null)
else
patrol_move()
return
if(target && path.len == 0)
spawn(0)
if(!src || !target) return
src.path = AStar(src.loc, src.target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id=botcard)
if (!path) path = list()
if(src.path.len == 0)
src.oldtarget = src.target
target.targeted_by = null
src.target = null
return
if(src.path.len > 0 && src.target && (src.target != null))
step_to(src, src.path[1])
src.path -= src.path[1]
else if(src.path.len == 1)
step_to(src, target)
if(src.target && (src.target != null))
patrol_path = null
if(src.loc == src.target.loc)
clean(src.target)
src.path = new()
src.target = null
return
src.oldloc = src.loc
/obj/machinery/bot/cleanbot/proc/patrol_move()
if (src.patrol_path.len <= 0)
return
var/next = src.patrol_path[1]
src.patrol_path -= next
if (next == src.loc)
return
var/moved = step_towards(src, next)
if (!moved)
failed_steps++
if (failed_steps > 4)
patrol_path = null
next_dest = null
failed_steps = 0
else
failed_steps = 0
/obj/machinery/bot/cleanbot/receive_signal(datum/signal/signal)
var/recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!recv || !valid)
return
var/dist = get_dist(src, signal.source.loc)
if (dist < closest_dist && signal.source.loc != src.loc)
closest_dist = dist
closest_loc = signal.source.loc
next_dest = signal.data["next_patrol"]
if (recv == next_dest)
next_dest_loc = signal.source.loc
next_dest = signal.data["next_patrol"]
/obj/machinery/bot/cleanbot/proc/get_targets()
src.target_types = new/list()
target_types += /obj/effect/decal/cleanable/blood/oil
target_types += /obj/effect/decal/cleanable/vomit
target_types += /obj/effect/decal/cleanable/crayon
target_types += /obj/effect/decal/cleanable/liquid_fuel
target_types += /obj/effect/decal/cleanable/mucus
target_types += /obj/effect/decal/cleanable/dirt
if(src.blood)
target_types += /obj/effect/decal/cleanable/blood/
/obj/machinery/bot/cleanbot/proc/clean(var/obj/effect/decal/cleanable/target)
anchored = 1
icon_state = "cleanbot-c"
visible_message("\red [src] begins to clean up the [target]")
cleaning = 1
var/cleantime = 50
if(istype(target,/obj/effect/decal/cleanable/dirt)) // Clean Dirt much faster
cleantime = 10
spawn(cleantime)
if(istype(loc,/turf/simulated))
var/turf/simulated/f = loc
f.dirt = 0
cleaning = 0
del(target)
icon_state = "cleanbot[on]"
anchored = 0
target = null
/obj/machinery/bot/cleanbot/explode()
src.on = 0
src.visible_message("\red <B>[src] blows apart!</B>", 1)
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
new /obj/item/device/assembly/prox_sensor(Tsec)
if (prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/obj/item/weapon/bucket_sensor/attackby(var/obj/item/W, mob/user as mob)
..()
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
user.drop_item()
del(W)
var/turf/T = get_turf(src.loc)
var/obj/machinery/bot/cleanbot/A = new /obj/machinery/bot/cleanbot(T)
A.name = src.created_name
user << "<span class='notice'>You add the robot arm to the bucket and sensor assembly. Beep boop!</span>"
user.drop_from_inventory(src)
del(src)
else if (istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if (!t)
return
if (!in_range(src, usr) && src.loc != usr)
return
src.created_name = t

View File

@@ -1,210 +0,0 @@
/obj/machinery/bot/secbot/ed209
name = "ED-209 Security Robot"
desc = "A security robot. He looks less than thrilled."
icon = 'icons/obj/aibots.dmi'
icon_state = "ed2090"
density = 1
health = 100
maxhealth = 100
bot_version = "2.5"
search_range = 12
has_laser = 1
preparing_arrest_sounds = new()
secbot_assembly = /obj/item/weapon/secbot_assembly/ed209_assembly
/obj/item/weapon/secbot_assembly/ed209_assembly
name = "ED-209 assembly"
desc = "Some sort of bizarre assembly."
icon = 'icons/obj/aibots.dmi'
icon_state = "ed209_frame"
item_state = "ed209_frame"
created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess
var/lasercolor = ""
/obj/machinery/bot/secbot/ed209/update_icon()
if(on && is_attacking)
src.icon_state = "[lasercolor]ed209-c"
else
src.icon_state = "[lasercolor]ed209[src.on]"
/obj/machinery/bot/secbot/ed209/on_explosion(var/turf/Tsec)
if(!lasercolor)
var/obj/item/weapon/gun/energy/taser/G = new /obj/item/weapon/gun/energy/taser(Tsec)
G.power_supply.charge = 0
else if(lasercolor == "b")
var/obj/item/weapon/gun/energy/lasertag/blue/G = new (Tsec)
G.power_supply.charge = 0
else if(lasercolor == "r")
var/obj/item/weapon/gun/energy/lasertag/red/G = new (Tsec)
G.power_supply.charge = 0
if (prob(50))
new /obj/item/robot_parts/l_leg(Tsec)
if (prob(25))
new /obj/item/robot_parts/r_leg(Tsec)
if (prob(25))//50% chance for a helmet OR vest
if (prob(50))
new /obj/item/clothing/head/helmet(Tsec)
else
if(!lasercolor)
new /obj/item/clothing/suit/armor/vest(Tsec)
if(lasercolor == "b")
new /obj/item/clothing/suit/bluetag(Tsec)
if(lasercolor == "r")
new /obj/item/clothing/suit/redtag(Tsec)
/obj/item/weapon/secbot_assembly/ed209_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if(istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if(!t) return
if(!in_range(src, usr) && src.loc != usr) return
created_name = t
return
switch(build_step)
if(0,1)
if( istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg) )
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the robot leg to [src].</span>"
name = "legs/frame assembly"
if(build_step == 1)
item_state = "ed209_leg"
icon_state = "ed209_leg"
else
item_state = "ed209_legs"
icon_state = "ed209_legs"
if(2)
if( istype(W, /obj/item/clothing/suit/redtag) )
lasercolor = "r"
else if( istype(W, /obj/item/clothing/suit/bluetag) )
lasercolor = "b"
if( lasercolor || istype(W, /obj/item/clothing/suit/storage/vest) )
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the armor to [src].</span>"
name = "vest/legs/frame assembly"
item_state = "[lasercolor]ed209_shell"
icon_state = "[lasercolor]ed209_shell"
if(3)
if( istype(W, /obj/item/weapon/weldingtool) )
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0,user))
build_step++
name = "shielded frame assembly"
user << "<span class='notice'>You welded the vest to [src].</span>"
if(4)
if( istype(W, /obj/item/clothing/head/helmet) )
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the helmet to [src].</span>"
name = "covered and shielded frame assembly"
item_state = "[lasercolor]ed209_hat"
icon_state = "[lasercolor]ed209_hat"
if(5)
if( isprox(W) )
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the prox sensor to [src].</span>"
name = "covered, shielded and sensored frame assembly"
item_state = "[lasercolor]ed209_prox"
icon_state = "[lasercolor]ed209_prox"
if(6)
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if (C.get_amount() < 1)
user << "<span class='warning'>You need one coil of wire to do wire [src].</span>"
return
user << "<span class='notice'>You start to wire [src].</span>"
if (do_after(user, 40) && build_step == 6)
if (C.use(1))
build_step++
user << "<span class='notice'>You wire the ED-209 assembly.</span>"
name = "wired ED-209 assembly"
return
if(7)
switch(lasercolor)
if("b")
if( !istype(W, /obj/item/weapon/gun/energy/lasertag/blue) )
return
name = "bluetag ED-209 assembly"
if("r")
if( !istype(W, /obj/item/weapon/gun/energy/lasertag/red) )
return
name = "redtag ED-209 assembly"
if("")
if( !istype(W, /obj/item/weapon/gun/energy/taser) )
return
name = "taser ED-209 assembly"
else
return
build_step++
user << "<span class='notice'>You add [W] to [src].</span>"
src.item_state = "[lasercolor]ed209_taser"
src.icon_state = "[lasercolor]ed209_taser"
user.drop_item()
del(W)
if(8)
if( istype(W, /obj/item/weapon/screwdriver) )
playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
var/turf/T = get_turf(user)
user << "<span class='notice'>Now attaching the gun to the frame...</span>"
sleep(40)
if(get_turf(user) == T && build_step == 8)
build_step++
name = "armed [name]"
user << "<span class='notice'>Taser gun attached.</span>"
if(9)
if( istype(W, /obj/item/weapon/cell) )
build_step++
user << "<span class='notice'>You complete the ED-209.</span>"
var/turf/T = get_turf(src)
new /obj/machinery/bot/secbot/ed209(T,created_name,lasercolor)
user.drop_item()
del(W)
user.drop_from_inventory(src)
del(src)
/obj/machinery/bot/secbot/ed209/bullet_act(var/obj/item/projectile/Proj)
if((src.lasercolor == "b") && (src.disabled == 0))
if(istype(Proj, /obj/item/projectile/beam/lastertag/red))
src.disabled = 1
del (Proj)
sleep(100)
src.disabled = 0
else
..()
else if((src.lasercolor == "r") && (src.disabled == 0))
if(istype(Proj, /obj/item/projectile/beam/lastertag/blue))
src.disabled = 1
del (Proj)
sleep(100)
src.disabled = 0
else
..()
else
..()
/obj/machinery/bot/secbot/ed209/bluetag/New()//If desired, you spawn red and bluetag bots easily
new /obj/machinery/bot/secbot/ed209(get_turf(src),null,"b")
del(src)
/obj/machinery/bot/secbot/ed209/redtag/New()
new /obj/machinery/bot/secbot/ed209(get_turf(src),null,"r")
del(src)

View File

@@ -1,595 +0,0 @@
//Farmbots by GauHelldragon - 12/30/2012
// A new type of buildable aiBot that helps out in hydroponics
// Made by using a robot arm on a water tank and then adding:
// A plant analyzer, a bucket, a mini-hoe and then a proximity sensor (in that order)
// Will water, weed and fertilize plants that need it
// When emagged, it will "water", "weed" and "fertilize" humans instead
// Holds up to 10 fertilizers (only the type dispensed by the machines, not chemistry bottles)
// It will fill up it's water tank at a sink when low.
// The behavior panel can be unlocked with hydroponics access and be modified to disable certain behaviors
// By default, it will ignore weeds and mushrooms, but can be set to tend to these types of plants as well.
#define FARMBOT_MODE_WATER 1
#define FARMBOT_MODE_FERTILIZE 2
#define FARMBOT_MODE_WEED 3
#define FARMBOT_MODE_REFILL 4
#define FARMBOT_MODE_WAITING 5
#define FARMBOT_ANIMATION_TIME 25 //How long it takes to use one of the action animations
#define FARMBOT_EMAG_DELAY 60 //How long of a delay after doing one of the emagged attack actions
#define FARMBOT_ACTION_DELAY 35 //How long of a delay after doing one of the normal actions
/obj/machinery/bot/farmbot
name = "Farmbot"
desc = "The botanist's best friend."
icon = 'icons/obj/aibots.dmi'
icon_state = "farmbot0"
layer = 5.0
density = 1
anchored = 0
health = 50
maxhealth = 50
req_access =list(access_hydroponics)
var/Max_Fertilizers = 10
var/setting_water = 1
var/setting_refill = 1
var/setting_fertilize = 1
var/setting_weed = 1
var/setting_ignoreWeeds = 1
var/setting_ignoreMushrooms = 1
var/atom/target //Current target, can be a human, a hydroponics tray, or a sink
var/mode //Which mode is being used, 0 means it is looking for work
var/obj/structure/reagent_dispensers/watertank/tank // the water tank that was used to make it, remains inside the bot.
var/path[] = new() // used for pathing
var/frustration
/obj/machinery/bot/farmbot/New()
..()
src.icon_state = "farmbot[src.on]"
spawn (4)
src.botcard = new /obj/item/weapon/card/id(src)
src.botcard.access = req_access
if ( !tank ) //Should be set as part of making it... but lets check anyway
tank = locate(/obj/structure/reagent_dispensers/watertank/) in contents
if ( !tank ) //An admin must have spawned the farmbot! Better give it a tank.
tank = new /obj/structure/reagent_dispensers/watertank(src)
/obj/machinery/bot/farmbot/Bump(M as mob|obj) //Leave no door unopened!
spawn(0)
if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
var/obj/machinery/door/D = M
if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard))
D.open()
src.frustration = 0
return
return
/obj/machinery/bot/farmbot/turn_on()
. = ..()
src.icon_state = "farmbot[src.on]"
src.updateUsrDialog()
/obj/machinery/bot/farmbot/turn_off()
..()
src.path = new()
src.icon_state = "farmbot[src.on]"
src.updateUsrDialog()
/obj/machinery/bot/farmbot/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/machinery/bot/farmbot/proc/get_total_ferts()
var total_fert = 0
for (var/obj/item/nutrient/fert in contents)
total_fert++
return total_fert
/obj/machinery/bot/farmbot/attack_hand(mob/user as mob)
. = ..()
if (.)
return
var/dat
dat += "<TT><B>Automatic Hyrdoponic Assisting Unit v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</A><BR>"
dat += "Water Tank: "
if ( tank )
dat += "\[[tank.reagents.total_volume]/[tank.reagents.maximum_volume]\]"
else
dat += "Error: Water Tank not Found"
dat += "<br>Fertilizer Storage: <A href='?src=\ref[src];eject=1'>\[[get_total_ferts()]/[Max_Fertilizers]\]</a>"
dat += "<br>Behaviour controls are [src.locked ? "locked" : "unlocked"]<hr>"
if(!src.locked)
dat += "<TT>Watering Controls:<br>"
dat += " Water Plants : <A href='?src=\ref[src];water=1'>[src.setting_water ? "Yes" : "No"]</A><BR>"
dat += " Refill Watertank : <A href='?src=\ref[src];refill=1'>[src.setting_refill ? "Yes" : "No"]</A><BR>"
dat += "<br>Fertilizer Controls:<br>"
dat += " Fertilize Plants : <A href='?src=\ref[src];fertilize=1'>[src.setting_fertilize ? "Yes" : "No"]</A><BR>"
dat += "<br>Weeding Controls:<br>"
dat += " Weed Plants : <A href='?src=\ref[src];weed=1'>[src.setting_weed ? "Yes" : "No"]</A><BR>"
dat += "<br>Ignore Weeds : <A href='?src=\ref[src];ignoreWeed=1'>[src.setting_ignoreWeeds ? "Yes" : "No"]</A><BR>"
dat += "Ignore Mushrooms : <A href='?src=\ref[src];ignoreMush=1'>[src.setting_ignoreMushrooms ? "Yes" : "No"]</A><BR>"
dat += "</TT>"
user << browse("<HEAD><TITLE>Farmbot v1.0 controls</TITLE></HEAD>[dat]", "window=autofarm")
onclose(user, "autofarm")
return
/obj/machinery/bot/farmbot/Topic(href, href_list)
if(..())
return
usr.machine = src
src.add_fingerprint(usr)
if ((href_list["power"]) && (src.allowed(usr)))
if (src.on)
turn_off()
else
turn_on()
else if((href_list["water"]) && (!src.locked))
setting_water = !setting_water
else if((href_list["refill"]) && (!src.locked))
setting_refill = !setting_refill
else if((href_list["fertilize"]) && (!src.locked))
setting_fertilize = !setting_fertilize
else if((href_list["weed"]) && (!src.locked))
setting_weed = !setting_weed
else if((href_list["ignoreWeed"]) && (!src.locked))
setting_ignoreWeeds = !setting_ignoreWeeds
else if((href_list["ignoreMush"]) && (!src.locked))
setting_ignoreMushrooms = !setting_ignoreMushrooms
else if (href_list["eject"] )
flick("farmbot_hatch",src)
for (var/obj/item/nutrient/fert in contents)
fert.loc = get_turf(src)
src.updateUsrDialog()
return
/obj/machinery/bot/farmbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if (src.allowed(user))
src.locked = !src.locked
user << "Controls are now [src.locked ? "locked." : "unlocked."]"
src.updateUsrDialog()
else
user << "\red Access denied."
else if (istype(W, /obj/item/nutrient))
if ( get_total_ferts() >= Max_Fertilizers )
user << "The fertilizer storage is full!"
return
user.drop_item()
W.loc = src
user << "You insert [W]."
flick("farmbot_hatch",src)
src.updateUsrDialog()
return
else
..()
/obj/machinery/bot/farmbot/Emag(mob/user as mob)
..()
if(user) user << "\red You short out [src]'s plant identifier circuits."
spawn(0)
for(var/mob/O in hearers(src, null))
O.show_message("\red <B>[src] buzzes oddly!</B>", 1)
flick("farmbot_broke", src)
src.emagged = 1
src.on = 1
src.icon_state = "farmbot[src.on]"
target = null
mode = FARMBOT_MODE_WAITING //Give the emagger a chance to get away! 15 seconds should be good.
spawn(150)
mode = 0
/obj/machinery/bot/farmbot/explode()
src.on = 0
visible_message("\red <B>[src] blows apart!</B>", 1)
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/minihoe(Tsec)
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/device/analyzer/plant_analyzer(Tsec)
if ( tank )
tank.loc = Tsec
for ( var/obj/item/nutrient/fert in contents )
if ( prob(50) )
fert.loc = Tsec
if (prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/obj/machinery/bot/farmbot/process()
set background = 1
if(!src.on)
return
if ( emagged && prob(1) )
flick("farmbot_broke", src)
if ( mode == FARMBOT_MODE_WAITING )
return
if ( !mode || !target || !(target in view(7,src)) ) //Don't bother chasing down targets out of view
mode = 0
target = null
if ( !find_target() )
// Couldn't find a target, wait a while before trying again.
mode = FARMBOT_MODE_WAITING
spawn(100)
mode = 0
return
if ( mode && target )
if ( get_dist(target,src) <= 1 || ( emagged && mode == FARMBOT_MODE_FERTILIZE ) )
// If we are in emagged fertilize mode, we throw the fertilizer, so distance doesn't matter
frustration = 0
use_farmbot_item()
else
move_to_target()
return
/obj/machinery/bot/farmbot/proc/use_farmbot_item()
if ( !target )
mode = 0
return 0
if ( emagged && !ismob(target) ) // Humans are plants!
mode = 0
target = null
return 0
if ( !emagged && !istype(target,/obj/machinery/hydroponics) && !istype(target,/obj/structure/sink) ) // Humans are not plants!
mode = 0
target = null
return 0
if ( mode == FARMBOT_MODE_FERTILIZE )
//Find which fertilizer to use
var/obj/item/nutrient/fert
for ( var/obj/item/nutrient/nut in contents )
fert = nut
break
if ( !fert )
target = null
mode = 0
return
fertilize(fert)
if ( mode == FARMBOT_MODE_WEED )
weed()
if ( mode == FARMBOT_MODE_WATER )
water()
if ( mode == FARMBOT_MODE_REFILL )
refill()
/obj/machinery/bot/farmbot/proc/find_target()
if ( emagged ) //Find a human and help them!
for ( var/mob/living/carbon/human/human in view(7,src) )
if (human.stat == 2)
continue
var list/options = list(FARMBOT_MODE_WEED)
if ( get_total_ferts() )
options.Add(FARMBOT_MODE_FERTILIZE)
if ( tank && tank.reagents.total_volume >= 1 )
options.Add(FARMBOT_MODE_WATER)
mode = pick(options)
target = human
return mode
return 0
else
if ( setting_refill && tank && tank.reagents.total_volume < 100 )
for ( var/obj/structure/sink/source in view(7,src) )
target = source
mode = FARMBOT_MODE_REFILL
return 1
for ( var/obj/machinery/hydroponics/tray in view(7,src) )
var newMode = GetNeededMode(tray)
if ( newMode )
mode = newMode
target = tray
return 1
return 0
/obj/machinery/bot/farmbot/proc/GetNeededMode(obj/machinery/hydroponics/tray)
if ( !tray.planted || tray.dead )
return 0
if ( tray.myseed.plant_type == 1 && setting_ignoreWeeds )
return 0
if ( tray.myseed.plant_type == 2 && setting_ignoreMushrooms )
return 0
if ( setting_water && tray.waterlevel <= 10 && tank && tank.reagents.total_volume >= 1 )
return FARMBOT_MODE_WATER
if ( setting_weed && tray.weedlevel >= 5 )
return FARMBOT_MODE_WEED
if ( setting_fertilize && tray.nutrilevel <= 2 && get_total_ferts() )
return FARMBOT_MODE_FERTILIZE
return 0
/obj/machinery/bot/farmbot/proc/move_to_target()
//Mostly copied from medibot code.
if(src.frustration > 8)
target = null
mode = 0
frustration = 0
src.path = new()
if(src.target && (src.path.len) && (get_dist(src.target,src.path[src.path.len]) > 2))
src.path = new()
if(src.target && src.path.len == 0 && (get_dist(src,src.target) > 1))
spawn(0)
var/turf/dest = get_step_towards(target,src) //Can't pathfind to a tray, as it is dense, so pathfind to the spot next to the tray
src.path = AStar(src.loc, dest, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30,id=botcard)
if(src.path.len == 0)
for ( var/turf/spot in orange(1,target) ) //The closest one is unpathable, try the other spots
if ( spot == dest ) //We already tried this spot
continue
if ( spot.density )
continue
src.path = AStar(src.loc, spot, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30,id=botcard)
src.path = reverselist(src.path)
if ( src.path.len > 0 )
break
if ( src.path.len == 0 )
target = null
mode = 0
return
if(src.path.len > 0 && src.target)
step_to(src, src.path[1])
src.path -= src.path[1]
spawn(3)
if(src.path.len)
step_to(src, src.path[1])
src.path -= src.path[1]
if(src.path.len > 8 && src.target)
src.frustration++
/obj/machinery/bot/farmbot/proc/fertilize(obj/item/nutrient/fert)
if ( !fert )
target = null
mode = 0
return 0
if ( emagged ) // Warning, hungry humans detected: throw fertilizer at them
spawn(0)
fert.loc = src.loc
fert.throw_at(target, 16, 3, src)
src.visible_message("\red <b>[src] launches [fert.name] at [target.name]!</b>")
flick("farmbot_broke", src)
spawn (FARMBOT_EMAG_DELAY)
mode = 0
target = null
return 1
else // feed them plants~
var /obj/machinery/hydroponics/tray = target
tray.nutrilevel = 10
tray.yieldmod = fert.yieldmod
tray.mutmod = fert.mutmod
del fert
tray.updateicon()
icon_state = "farmbot_fertile"
mode = FARMBOT_MODE_WAITING
spawn (FARMBOT_ACTION_DELAY)
mode = 0
target = null
spawn (FARMBOT_ANIMATION_TIME)
icon_state = "farmbot[src.on]"
return 1
/obj/machinery/bot/farmbot/proc/weed()
icon_state = "farmbot_hoe"
spawn(FARMBOT_ANIMATION_TIME)
icon_state = "farmbot[src.on]"
if ( emagged ) // Warning, humans infested with weeds!
mode = FARMBOT_MODE_WAITING
spawn(FARMBOT_EMAG_DELAY)
mode = 0
if ( prob(50) ) // better luck next time little guy
src.visible_message("\red <b>[src] swings wildly at [target] with a minihoe, missing completely!</b>")
else // yayyy take that weeds~
var/attackVerb = pick("slashed", "sliced", "cut", "clawed")
var /mob/living/carbon/human/human = target
src.visible_message("\red <B>[src] [attackVerb] [human]!</B>")
var/damage = 5
var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
var/datum/organ/external/affecting = human.get_organ(ran_zone(dam_zone))
var/armor = human.run_armor_check(affecting, "melee")
human.apply_damage(damage,BRUTE,affecting,armor,sharp=1,edge=1)
else // warning, plants infested with weeds!
mode = FARMBOT_MODE_WAITING
spawn(FARMBOT_ACTION_DELAY)
mode = 0
var /obj/machinery/hydroponics/tray = target
tray.weedlevel = 0
tray.updateicon()
/obj/machinery/bot/farmbot/proc/water()
if ( !tank || tank.reagents.total_volume < 1 )
mode = 0
target = null
return 0
icon_state = "farmbot_water"
spawn(FARMBOT_ANIMATION_TIME)
icon_state = "farmbot[src.on]"
if ( emagged ) // warning, humans are thirsty!
var splashAmount = min(70,tank.reagents.total_volume)
src.visible_message("\red [src] splashes [target] with a bucket of water!")
playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1)
if ( prob(50) )
tank.reagents.reaction(target, TOUCH) //splash the human!
else
tank.reagents.reaction(target.loc, TOUCH) //splash the human's roots!
spawn(5)
tank.reagents.remove_any(splashAmount)
mode = FARMBOT_MODE_WAITING
spawn(FARMBOT_EMAG_DELAY)
mode = 0
else
var /obj/machinery/hydroponics/tray = target
var/b_amount = tank.reagents.get_reagent_amount("water")
if(b_amount > 0 && tray.waterlevel < 100)
if(b_amount + tray.waterlevel > 100)
b_amount = 100 - tray.waterlevel
tank.reagents.remove_reagent("water", b_amount)
tray.waterlevel += b_amount
playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1)
// Toxicity dilutation code. The more water you put in, the lesser the toxin concentration.
tray.toxic -= round(b_amount/4)
if (tray.toxic < 0 ) // Make sure it won't go overboard
tray.toxic = 0
tray.updateicon()
mode = FARMBOT_MODE_WAITING
spawn(FARMBOT_ACTION_DELAY)
mode = 0
/obj/machinery/bot/farmbot/proc/refill()
if ( !tank || !tank.reagents.total_volume > 600 || !istype(target,/obj/structure/sink) )
mode = 0
target = null
return
mode = FARMBOT_MODE_WAITING
playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1)
src.visible_message("\blue [src] starts filling it's tank from [target].")
spawn(300)
src.visible_message("\blue [src] finishes filling it's tank.")
src.mode = 0
tank.reagents.add_reagent("water", tank.reagents.maximum_volume - tank.reagents.total_volume )
playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1)
/obj/item/weapon/farmbot_arm_assembly
name = "water tank/robot arm assembly"
desc = "A water tank with a robot arm permanently grafted to it."
icon = 'icons/obj/aibots.dmi'
icon_state = "water_arm"
var/build_step = 0
var/created_name = "Farmbot" //To preserve the name if it's a unique farmbot I guess
w_class = 3.0
New()
..()
spawn(4) // If an admin spawned it, it won't have a watertank it, so lets make one for em!
var tank = locate(/obj/structure/reagent_dispensers/watertank) in contents
if( !tank )
new /obj/structure/reagent_dispensers/watertank(src)
/obj/structure/reagent_dispensers/watertank/attackby(var/obj/item/robot_parts/S, mob/user as mob)
if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
..()
return
//Making a farmbot!
var/obj/item/weapon/farmbot_arm_assembly/A = new /obj/item/weapon/farmbot_arm_assembly
A.loc = src.loc
user << "You add the robot arm to the [src]"
src.loc = A //Place the water tank into the assembly, it will be needed for the finished bot
user.remove_from_mob(S)
del(S)
/obj/item/weapon/farmbot_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if((istype(W, /obj/item/device/analyzer/plant_analyzer)) && (!src.build_step))
src.build_step++
user << "You add the plant analyzer to [src]!"
src.name = "farmbot assembly"
user.remove_from_mob(W)
del(W)
else if(( istype(W, /obj/item/weapon/reagent_containers/glass/bucket)) && (src.build_step == 1))
src.build_step++
user << "You add a bucket to [src]!"
src.name = "farmbot assembly with bucket"
user.remove_from_mob(W)
del(W)
else if(( istype(W, /obj/item/weapon/minihoe)) && (src.build_step == 2))
src.build_step++
user << "You add a minihoe to [src]!"
src.name = "farmbot assembly with bucket and minihoe"
user.remove_from_mob(W)
del(W)
else if((isprox(W)) && (src.build_step == 3))
src.build_step++
user << "You complete the Farmbot! Beep boop."
var/obj/machinery/bot/farmbot/S = new /obj/machinery/bot/farmbot
for ( var/obj/structure/reagent_dispensers/watertank/wTank in src.contents )
wTank.loc = S
S.tank = wTank
S.loc = get_turf(src)
S.name = src.created_name
user.remove_from_mob(W)
del(W)
del(src)
else if(istype(W, /obj/item/weapon/pen))
var/t = input(user, "Enter new robot name", src.name, src.created_name) as text
t = sanitize(t, MAX_NAME_LEN)
if (!t)
return
if (!in_range(src, usr) && src.loc != usr)
return
src.created_name = t
/obj/item/weapon/farmbot_arm_assembly/attack_hand(mob/user as mob)
return //it's a converted watertank, no you cannot pick it up and put it in your backpack

View File

@@ -1,449 +0,0 @@
//Floorbot assemblies
/obj/item/weapon/toolbox_tiles
desc = "It's a toolbox with tiles sticking out the top"
name = "tiles and toolbox"
icon = 'icons/obj/aibots.dmi'
icon_state = "toolbox_tiles"
force = 3.0
throwforce = 10.0
throw_speed = 2
throw_range = 5
w_class = 3.0
var/created_name = "Floorbot"
/obj/item/weapon/toolbox_tiles_sensor
desc = "It's a toolbox with tiles sticking out the top and a sensor attached"
name = "tiles, toolbox and sensor arrangement"
icon = 'icons/obj/aibots.dmi'
icon_state = "toolbox_tiles_sensor"
force = 3.0
throwforce = 10.0
throw_speed = 2
throw_range = 5
w_class = 3.0
var/created_name = "Floorbot"
//Floorbot
/obj/machinery/bot/floorbot
name = "Floorbot"
desc = "A little floor repairing robot, he looks so excited!"
icon = 'icons/obj/aibots.dmi'
icon_state = "floorbot0"
layer = 5.0
density = 0
anchored = 0
health = 25
maxhealth = 25
//weight = 1.0E7
var/amount = 10
var/repairing = 0
var/improvefloors = 0
var/eattiles = 0
var/maketiles = 0
var/turf/target
var/turf/oldtarget
var/oldloc = null
req_access = list(access_construction)
var/path[] = new()
var/targetdirection
/obj/machinery/bot/floorbot/New()
..()
src.updateicon()
/obj/machinery/bot/floorbot/turn_on()
. = ..()
src.updateicon()
src.updateUsrDialog()
/obj/machinery/bot/floorbot/turn_off()
..()
src.target = null
src.oldtarget = null
src.oldloc = null
src.updateicon()
src.path = new()
src.updateUsrDialog()
/obj/machinery/bot/floorbot/attack_hand(mob/user as mob)
. = ..()
if (.)
return
usr.set_machine(src)
interact(user)
/obj/machinery/bot/floorbot/interact(mob/user as mob)
var/dat
dat += "<TT><B>Automatic Station Floor Repairer v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A><BR>"
dat += "Maintenance panel is [src.open ? "opened" : "closed"]<BR>"
dat += "Tiles left: [src.amount]<BR>"
dat += "Behvaiour controls are [src.locked ? "locked" : "unlocked"]<BR>"
if(!src.locked || issilicon(user))
dat += "Improves floors: <A href='?src=\ref[src];operation=improve'>[src.improvefloors ? "Yes" : "No"]</A><BR>"
dat += "Finds tiles: <A href='?src=\ref[src];operation=tiles'>[src.eattiles ? "Yes" : "No"]</A><BR>"
dat += "Make singles pieces of metal into tiles when empty: <A href='?src=\ref[src];operation=make'>[src.maketiles ? "Yes" : "No"]</A><BR>"
var/bmode
if (src.targetdirection)
bmode = dir2text(src.targetdirection)
else
bmode = "Disabled"
dat += "<BR><BR>Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
user << browse("<HEAD><TITLE>Repairbot v1.0 controls</TITLE></HEAD>[dat]", "window=autorepair")
onclose(user, "autorepair")
return
/obj/machinery/bot/floorbot/attackby(var/obj/item/W , mob/user as mob)
if(istype(W, /obj/item/stack/tile/plasteel))
var/obj/item/stack/tile/plasteel/T = W
if(src.amount >= 50)
return
var/loaded = min(50-src.amount, T.get_amount())
T.use(loaded)
src.amount += loaded
user << "<span class='notice'>You load [loaded] tiles into the floorbot. He now contains [src.amount] tiles.</span>"
src.updateicon()
else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if(src.allowed(usr) && !open && !emagged)
src.locked = !src.locked
user << "<span class='notice'>You [src.locked ? "lock" : "unlock"] the [src] behaviour controls.</span>"
else
if(emagged)
user << "<span class='warning'>ERROR</span>"
if(open)
user << "<span class='warning'>Please close the access panel before locking it.</span>"
else
user << "<span class='warning'>Access denied.</span>"
src.updateUsrDialog()
else
..()
/obj/machinery/bot/floorbot/Emag(mob/user as mob)
..()
if(open && !locked)
if(user) user << "<span class='notice'>The [src] buzzes and beeps.</span>"
/obj/machinery/bot/floorbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
switch(href_list["operation"])
if("start")
if (src.on)
turn_off()
else
turn_on()
if("improve")
src.improvefloors = !src.improvefloors
src.updateUsrDialog()
if("tiles")
src.eattiles = !src.eattiles
src.updateUsrDialog()
if("make")
src.maketiles = !src.maketiles
src.updateUsrDialog()
if("bridgemode")
switch(src.targetdirection)
if(null)
targetdirection = 1
if(1)
targetdirection = 2
if(2)
targetdirection = 4
if(4)
targetdirection = 8
if(8)
targetdirection = null
else
targetdirection = null
src.updateUsrDialog()
/obj/machinery/bot/floorbot/process()
set background = 1
if(!src.on)
return
if(src.repairing)
return
var/list/floorbottargets = list()
if(src.amount <= 0 && ((src.target == null) || !src.target))
if(src.eattiles)
for(var/obj/item/stack/tile/plasteel/T in view(7, src))
if(T != src.oldtarget && !(target in floorbottargets))
src.oldtarget = T
src.target = T
break
if(src.target == null || !src.target)
if(src.maketiles)
if(src.target == null || !src.target)
for(var/obj/item/stack/sheet/metal/M in view(7, src))
if(!(M in floorbottargets) && M != src.oldtarget && M.amount == 1 && !(istype(M.loc, /turf/simulated/wall)))
src.oldtarget = M
src.target = M
break
else
return
if(prob(5))
visible_message("[src] makes an excited booping beeping sound!")
if((!src.target || src.target == null) && emagged < 2)
if(targetdirection != null)
/*
for (var/turf/space/D in view(7,src))
if(!(D in floorbottargets) && D != src.oldtarget) // Added for bridging mode -- TLE
if(get_dir(src, D) == targetdirection)
src.oldtarget = D
src.target = D
break
*/
var/turf/T = get_step(src, targetdirection)
if(istype(T, /turf/space))
src.oldtarget = T
src.target = T
if(!src.target || src.target == null)
for (var/turf/space/D in view(7,src))
if(!(D in floorbottargets) && D != src.oldtarget && (D.loc.name != "Space"))
src.oldtarget = D
src.target = D
break
if((!src.target || src.target == null ) && src.improvefloors)
for (var/turf/simulated/floor/F in view(7,src))
if(!(F in floorbottargets) && F != src.oldtarget && F.icon_state == "Floor1" && !(istype(F, /turf/simulated/floor/plating)))
src.oldtarget = F
src.target = F
break
if((!src.target || src.target == null) && src.eattiles)
for(var/obj/item/stack/tile/plasteel/T in view(7, src))
if(!(T in floorbottargets) && T != src.oldtarget)
src.oldtarget = T
src.target = T
break
if((!src.target || src.target == null) && emagged == 2)
if(!src.target || src.target == null)
for (var/turf/simulated/floor/D in view(7,src))
if(!(D in floorbottargets) && D != src.oldtarget && D.floor_type)
src.oldtarget = D
src.target = D
break
if(!src.target || src.target == null)
if(src.loc != src.oldloc)
src.oldtarget = null
return
if(src.target && (src.target != null) && src.path.len == 0)
spawn(0)
if(!istype(src.target, /turf/))
src.path = AStar(src.loc, src.target.loc, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard)
else
src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard)
if (!src.path) src.path = list()
if(src.path.len == 0)
src.oldtarget = src.target
src.target = null
return
if(src.path.len > 0 && src.target && (src.target != null))
step_to(src, src.path[1])
src.path -= src.path[1]
else if(src.path.len == 1)
step_to(src, target)
src.path = new()
if(src.loc == src.target || src.loc == src.target.loc)
if(istype(src.target, /obj/item/stack/tile/plasteel))
src.eattile(src.target)
else if(istype(src.target, /obj/item/stack/sheet/metal))
src.maketile(src.target)
else if(istype(src.target, /turf/) && emagged < 2)
repair(src.target)
else if(emagged == 2 && istype(src.target,/turf/simulated/floor))
var/turf/simulated/floor/F = src.target
src.anchored = 1
src.repairing = 1
if(prob(90))
F.break_tile_to_plating()
else
F.ReplaceWithLattice()
visible_message("\red [src] makes an excited booping sound.")
spawn(50)
src.amount ++
src.anchored = 0
src.repairing = 0
src.target = null
src.path = new()
return
src.oldloc = src.loc
/obj/machinery/bot/floorbot/proc/repair(var/turf/target)
if(istype(target, /turf/space/))
if(target.loc.name == "Space")
return
else if(!istype(target, /turf/simulated/floor))
return
if(src.amount <= 0)
return
src.anchored = 1
src.icon_state = "floorbot-c"
if(istype(target, /turf/space/))
visible_message("\red [src] begins to repair the hole")
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
src.repairing = 1
spawn(50)
T.build(src.loc)
src.repairing = 0
src.amount -= 1
src.updateicon()
src.anchored = 0
src.target = null
else
visible_message("\red [src] begins to improve the floor.")
src.repairing = 1
spawn(50)
src.loc.icon_state = "floor"
src.repairing = 0
src.amount -= 1
src.updateicon()
src.anchored = 0
src.target = null
/obj/machinery/bot/floorbot/proc/eattile(var/obj/item/stack/tile/plasteel/T)
if(!istype(T, /obj/item/stack/tile/plasteel))
return
visible_message("\red [src] begins to collect tiles.")
src.repairing = 1
spawn(20)
if(isnull(T))
src.target = null
src.repairing = 0
return
if(src.amount + T.get_amount() > 50)
var/i = 50 - src.amount
src.amount += i
T.use(i)
else
src.amount += T.get_amount()
del(T)
src.updateicon()
src.target = null
src.repairing = 0
/obj/machinery/bot/floorbot/proc/maketile(var/obj/item/stack/sheet/metal/M)
if(!istype(M, /obj/item/stack/sheet/metal))
return
if(M.get_amount() > 1)
return
visible_message("\red [src] begins to create tiles.")
src.repairing = 1
spawn(20)
if(isnull(M))
src.target = null
src.repairing = 0
return
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel
T.amount = 4
T.loc = M.loc
del(M)
src.target = null
src.repairing = 0
/obj/machinery/bot/floorbot/proc/updateicon()
if(src.amount > 0)
src.icon_state = "floorbot[src.on]"
else
src.icon_state = "floorbot[src.on]e"
/obj/machinery/bot/floorbot/explode()
src.on = 0
src.visible_message("\red <B>[src] blows apart!</B>", 1)
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
N.contents = list()
new /obj/item/device/assembly/prox_sensor(Tsec)
if (prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
while (amount)//Dumps the tiles into the appropriate sized stacks
if(amount >= 16)
var/obj/item/stack/tile/plasteel/T = new (Tsec)
T.amount = 16
amount -= 16
else
var/obj/item/stack/tile/plasteel/T = new (Tsec)
T.amount = src.amount
amount = 0
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/plasteel/T, mob/user as mob)
if(!istype(T, /obj/item/stack/tile/plasteel))
..()
return
if(src.contents.len >= 1)
user << "<span class='notice'>They wont fit in as there is already stuff inside.</span>"
return
if(user.s_active)
user.s_active.close(user)
if (T.use(10))
var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles
user.put_in_hands(B)
user << "<span class='notice'>You add the tiles into the empty toolbox. They protrude from the top.</span>"
user.drop_from_inventory(src)
del(src)
else
user << "<span class='warning'>You need 10 floortiles for a floorbot.</span>"
return
/obj/item/weapon/toolbox_tiles/attackby(var/obj/item/W, mob/user as mob)
..()
if(isprox(W))
del(W)
var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor()
B.created_name = src.created_name
user.put_in_hands(B)
user << "<span class='notice'>You add the sensor to the toolbox and tiles!</span>"
user.drop_from_inventory(src)
del(src)
else if (istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if (!t)
return
if (!in_range(src, usr) && src.loc != usr)
return
src.created_name = t
/obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/W, mob/user as mob)
..()
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
del(W)
var/turf/T = get_turf(user.loc)
var/obj/machinery/bot/floorbot/A = new /obj/machinery/bot/floorbot(T)
A.name = src.created_name
user << "<span class='notice'>You add the robot arm to the odd looking toolbox assembly! Boop beep!</span>"
user.drop_from_inventory(src)
del(src)
else if (istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if (!t)
return
if (!in_range(src, usr) && src.loc != usr)
return
src.created_name = t

View File

@@ -1,596 +0,0 @@
//MEDBOT
//MEDBOT PATHFINDING
//MEDBOT ASSEMBLY
/obj/machinery/bot/medbot
name = "Medibot"
desc = "A little medical robot. He looks somewhat underwhelmed."
icon = 'icons/obj/aibots.dmi'
icon_state = "medibot0"
layer = 5.0
density = 0
anchored = 0
health = 20
maxhealth = 20
req_access =list(access_medical)
var/stunned = 0 //It can be stunned by tasers. Delicate circuits.
//var/emagged = 0
var/list/botcard_access = list(access_medical)
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
var/frustration = 0
var/path[] = new()
var/mob/living/carbon/patient = null
var/mob/living/carbon/oldpatient = null
var/oldloc = null
var/last_found = 0
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
var/currently_healing = 0
var/injection_amount = 15 //How much reagent do we inject at a time?
var/heal_threshold = 10 //Start healing when they have this much damage in a category
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
//Setting which reagents to use to treat what by default. By id.
var/treatment_brute = "tricordrazine"
var/treatment_oxy = "tricordrazine"
var/treatment_fire = "tricordrazine"
var/treatment_tox = "tricordrazine"
var/treatment_virus = "spaceacillin"
var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds?
var/shut_up = 0 //self explanatory :)
/obj/machinery/bot/medbot/mysterious
name = "Mysterious Medibot"
desc = "International Medibot of mystery."
skin = "bezerk"
treatment_oxy = "dexalinp"
treatment_brute = "bicaridine"
treatment_fire = "kelotane"
treatment_tox = "anti_toxin"
/obj/item/weapon/firstaid_arm_assembly
name = "first aid/robot arm assembly"
desc = "A first aid kit with a robot arm permanently grafted to it."
icon = 'icons/obj/aibots.dmi'
icon_state = "firstaid_arm"
var/build_step = 0
var/created_name = "Medibot" //To preserve the name if it's a unique medbot I guess
var/skin = null //Same as medbot, set to tox or ointment for the respective kits.
w_class = 3.0
New()
..()
spawn(5)
if(src.skin)
src.overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]")
/obj/machinery/bot/medbot/New()
..()
src.icon_state = "medibot[src.on]"
spawn(4)
if(src.skin)
src.overlays += image('icons/obj/aibots.dmi', "medskin_[src.skin]")
src.botcard = new /obj/item/weapon/card/id(src)
if(isnull(src.botcard_access) || (src.botcard_access.len < 1))
src.botcard.access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics)
else
src.botcard.access = src.botcard_access
/obj/machinery/bot/medbot/turn_on()
. = ..()
src.icon_state = "medibot[src.on]"
src.updateUsrDialog()
/obj/machinery/bot/medbot/turn_off()
..()
src.patient = null
src.oldpatient = null
src.oldloc = null
src.path = new()
src.currently_healing = 0
src.last_found = world.time
src.icon_state = "medibot[src.on]"
src.updateUsrDialog()
/obj/machinery/bot/medbot/attack_hand(mob/user as mob)
. = ..()
if (.)
return
var/dat
dat += "<TT><B>Automatic Medical Unit v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</A><BR>"
dat += "Maintenance panel is [src.open ? "opened" : "closed"]<BR>"
dat += "Beaker: "
if (src.reagent_glass)
dat += "<A href='?src=\ref[src];eject=1'>Loaded \[[src.reagent_glass.reagents.total_volume]/[src.reagent_glass.reagents.maximum_volume]\]</a>"
else
dat += "None Loaded"
dat += "<br>Behaviour controls are [src.locked ? "locked" : "unlocked"]<hr>"
if(!src.locked || issilicon(user))
dat += "<TT>Healing Threshold: "
dat += "<a href='?src=\ref[src];adj_threshold=-10'>--</a> "
dat += "<a href='?src=\ref[src];adj_threshold=-5'>-</a> "
dat += "[src.heal_threshold] "
dat += "<a href='?src=\ref[src];adj_threshold=5'>+</a> "
dat += "<a href='?src=\ref[src];adj_threshold=10'>++</a>"
dat += "</TT><br>"
dat += "<TT>Injection Level: "
dat += "<a href='?src=\ref[src];adj_inject=-5'>-</a> "
dat += "[src.injection_amount] "
dat += "<a href='?src=\ref[src];adj_inject=5'>+</a> "
dat += "</TT><br>"
dat += "Reagent Source: "
dat += "<a href='?src=\ref[src];use_beaker=1'>[src.use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]</a><br>"
dat += "Treatment report is [src.declare_treatment ? "on" : "off"]. <a href='?src=\ref[src];declaretreatment=[1]'>Toggle</a><br>"
dat += "The speaker switch is [src.shut_up ? "off" : "on"]. <a href='?src=\ref[src];togglevoice=[1]'>Toggle</a><br>"
user << browse("<HEAD><TITLE>Medibot v1.0 controls</TITLE></HEAD>[dat]", "window=automed")
onclose(user, "automed")
return
/obj/machinery/bot/medbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
if ((href_list["power"]) && (src.allowed(usr)))
if (src.on)
turn_off()
else
turn_on()
else if((href_list["adj_threshold"]) && (!src.locked || issilicon(usr)))
var/adjust_num = text2num(href_list["adj_threshold"])
src.heal_threshold += adjust_num
if(src.heal_threshold < 5)
src.heal_threshold = 5
if(src.heal_threshold > 75)
src.heal_threshold = 75
else if((href_list["adj_inject"]) && (!src.locked || issilicon(usr)))
var/adjust_num = text2num(href_list["adj_inject"])
src.injection_amount += adjust_num
if(src.injection_amount < 5)
src.injection_amount = 5
if(src.injection_amount > 15)
src.injection_amount = 15
else if((href_list["use_beaker"]) && (!src.locked || issilicon(usr)))
src.use_beaker = !src.use_beaker
else if (href_list["eject"] && (!isnull(src.reagent_glass)))
if(!src.locked)
src.reagent_glass.loc = get_turf(src)
src.reagent_glass = null
else
usr << "<span class='notice'>You cannot eject the beaker because the panel is locked.</span>"
else if ((href_list["togglevoice"]) && (!src.locked || issilicon(usr)))
src.shut_up = !src.shut_up
else if ((href_list["declaretreatment"]) && (!src.locked || issilicon(usr)))
src.declare_treatment = !src.declare_treatment
src.updateUsrDialog()
return
/obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if (src.allowed(user) && !open && !emagged)
src.locked = !src.locked
user << "<span class='notice'>Controls are now [src.locked ? "locked." : "unlocked."]</span>"
src.updateUsrDialog()
else
if(emagged)
user << "<span class='warning'>ERROR</span>"
if(open)
user << "<span class='warning'>Please close the access panel before locking it.</span>"
else
user << "<span class='warning'>Access denied.</span>"
else if (istype(W, /obj/item/weapon/reagent_containers/glass))
if(src.locked)
user << "<span class='notice'>You cannot insert a beaker because the panel is locked.</span>"
return
if(!isnull(src.reagent_glass))
user << "<span class='notice'>There is already a beaker loaded.</span>"
return
user.drop_item()
W.loc = src
src.reagent_glass = W
user << "<span class='notice'>You insert [W].</span>"
src.updateUsrDialog()
return
else
..()
if (health < maxhealth && !istype(W, /obj/item/weapon/screwdriver) && W.force)
step_to(src, (get_step_away(src,user)))
/obj/machinery/bot/medbot/Emag(mob/user as mob)
..()
if(open && !locked)
if(user) user << "<span class='warning'>You short out [src]'s reagent synthesis circuits.</span>"
spawn(0)
for(var/mob/O in hearers(src, null))
O.show_message("\red <B>[src] buzzes oddly!</B>", 1)
flick("medibot_spark", src)
src.patient = null
if(user) src.oldpatient = user
src.currently_healing = 0
src.last_found = world.time
src.anchored = 0
src.emagged = 2
src.on = 1
src.icon_state = "medibot[src.on]"
/obj/machinery/bot/medbot/process()
set background = 1
if(!src.on)
src.stunned = 0
return
if(src.stunned)
src.icon_state = "medibota"
src.stunned--
src.oldpatient = src.patient
src.patient = null
src.currently_healing = 0
if(src.stunned <= 0)
src.icon_state = "medibot[src.on]"
src.stunned = 0
return
if(src.frustration > 8)
src.oldpatient = src.patient
src.patient = null
src.currently_healing = 0
src.last_found = world.time
src.path = new()
if(!src.patient)
if(!src.shut_up && prob(1))
var/message = pick("Radar, put a mask on!","There's always a catch, and it's the best there is.","I knew it, I should've been a plastic surgeon.","What kind of medbay is this? Everyone's dropping like dead flies.","Delicious!")
src.speak(message)
for (var/mob/living/carbon/C in view(7,src)) //Time to find a patient!
if ((C.stat == 2) || !istype(C, /mob/living/carbon/human))
continue
if ((C == src.oldpatient) && (world.time < src.last_found + 100))
continue
if(src.assess_patient(C))
src.patient = C
src.oldpatient = C
src.last_found = world.time
if((src.last_newpatient_speak + 300) < world.time) //Don't spam these messages!
var/message = pick("Hey, [C.name]! Hold on, I'm coming.","Wait [C.name]! I want to help!","[C.name], you appear to be injured!")
src.speak(message)
src.visible_message("<b>[src]</b> points at [C.name]!")
src.last_newpatient_speak = world.time
break
else
continue
if(src.patient && Adjacent(patient))
if(!src.currently_healing)
src.currently_healing = 1
src.frustration = 0
src.medicate_patient(src.patient)
return
else if(src.patient && (src.path.len) && (get_dist(src.patient,src.path[src.path.len]) > 2))
src.path = new()
src.currently_healing = 0
src.last_found = world.time
if(src.patient && src.path.len == 0 && (get_dist(src,src.patient) > 1))
spawn(0)
src.path = AStar(src.loc, get_turf(src.patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30,id=botcard)
if (!path) path = list()
if(src.path.len == 0)
src.oldpatient = src.patient
src.patient = null
src.currently_healing = 0
src.last_found = world.time
return
if(src.path.len > 0 && src.patient)
step_to(src, src.path[1])
src.path -= src.path[1]
spawn(3)
if(src.path.len)
step_to(src, src.path[1])
src.path -= src.path[1]
if(src.path.len > 8 && src.patient)
src.frustration++
return
/obj/machinery/bot/medbot/proc/assess_patient(mob/living/carbon/C as mob)
//Time to see if they need medical help!
if(C.stat == 2)
return 0 //welp too late for them!
if(C.suiciding)
return 0 //Kevorkian school of robotic medical assistants.
if(src.emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
return 1
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
if((src.reagent_glass) && (src.use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
for(var/datum/reagent/R in src.reagent_glass.reagents.reagent_list)
if(!C.reagents.has_reagent(R))
return 1
continue
//They're injured enough for it!
if((C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_brute)))
return 1 //If they're already medicated don't bother!
if((C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(src.treatment_oxy)))
return 1
if((C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_fire)))
return 1
if((C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(src.treatment_tox)))
return 1
for(var/datum/disease/D in C.viruses)
if((D.stage > 1) || (D.spread_type == AIRBORNE))
if (!C.reagents.has_reagent(src.treatment_virus))
return 1 //STOP DISEASE FOREVER
return 0
/obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C as mob)
if(!src.on)
return
if(!istype(C))
src.oldpatient = src.patient
src.patient = null
src.currently_healing = 0
src.last_found = world.time
return
if(C.stat == 2)
var/death_message = pick("No! NO!","Live, damnit! LIVE!","I...I've never lost a patient before. Not today, I mean.")
src.speak(death_message)
src.oldpatient = src.patient
src.patient = null
src.currently_healing = 0
src.last_found = world.time
return
var/reagent_id = null
//Use whatever is inside the loaded beaker. If there is one.
if((src.use_beaker) && (src.reagent_glass) && (src.reagent_glass.reagents.total_volume))
reagent_id = "internal_beaker"
if(src.emagged == 2) //Emagged! Time to poison everybody.
reagent_id = "toxin"
var/virus = 0
for(var/datum/disease/D in C.viruses)
virus = 1
if (!reagent_id && (virus))
if(!C.reagents.has_reagent(src.treatment_virus))
reagent_id = src.treatment_virus
if (!reagent_id && (C.getBruteLoss() >= heal_threshold))
if(!C.reagents.has_reagent(src.treatment_brute))
reagent_id = src.treatment_brute
if (!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
if(!C.reagents.has_reagent(src.treatment_oxy))
reagent_id = src.treatment_oxy
if (!reagent_id && (C.getFireLoss() >= heal_threshold))
if(!C.reagents.has_reagent(src.treatment_fire))
reagent_id = src.treatment_fire
if (!reagent_id && (C.getToxLoss() >= heal_threshold))
if(!C.reagents.has_reagent(src.treatment_tox))
reagent_id = src.treatment_tox
if(!reagent_id) //If they don't need any of that they're probably cured!
src.oldpatient = src.patient
src.patient = null
src.currently_healing = 0
src.last_found = world.time
var/message = pick("All patched up!","An apple a day keeps me away.","Feel better soon!")
src.speak(message)
return
else
src.icon_state = "medibots"
visible_message("\red <B>[src] is trying to inject [src.patient]!</B>")
spawn(30)
if ((get_dist(src, src.patient) <= 1) && (src.on))
if((reagent_id == "internal_beaker") && (src.reagent_glass) && (src.reagent_glass.reagents.total_volume))
src.reagent_glass.reagents.trans_to(src.patient,src.injection_amount) //Inject from beaker instead.
src.reagent_glass.reagents.reaction(src.patient, 2)
else
src.patient.reagents.add_reagent(reagent_id,src.injection_amount)
visible_message("\red <B>[src] injects [src.patient] with the syringe!</B>")
if(declare_treatment)
var/area/location = get_area(src)
broadcast_medical_hud_message("[src.name] is treating <b>[C]</b> in <b>[location]</b>", src)
src.icon_state = "medibot[src.on]"
src.currently_healing = 0
return
// src.speak(reagent_id)
reagent_id = null
return
/obj/machinery/bot/medbot/proc/speak(var/message)
if((!src.on) || (!message))
return
visible_message("[src] beeps, \"[message]\"")
return
/obj/machinery/bot/medbot/bullet_act(var/obj/item/projectile/Proj)
if(Proj.taser_effect)
src.stunned = min(stunned+10,20)
..()
/obj/machinery/bot/medbot/explode()
src.on = 0
visible_message("\red <B>[src] blows apart!</B>", 1)
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/storage/firstaid(Tsec)
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/device/healthanalyzer(Tsec)
if(src.reagent_glass)
src.reagent_glass.loc = Tsec
src.reagent_glass = null
if (prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/obj/machinery/bot/medbot/Bump(M as mob|obj) //Leave no door unopened!
if ((istype(M, /obj/machinery/door)) && (!isnull(src.botcard)))
var/obj/machinery/door/D = M
if (!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/machinery/door/blast))
D.open()
src.frustration = 0
else if ((istype(M, /mob/living/)) && (!src.anchored))
src.loc = M:loc
src.frustration = 0
return
/* terrible
/obj/machinery/bot/medbot/Bumped(atom/movable/M as mob|obj)
spawn(0)
if (M)
var/turf/T = get_turf(src)
M:loc = T
*/
/*
* Pathfinding procs, allow the medibot to path through doors it has access to.
*/
//Pretty ugh
/*
/turf/proc/AdjacentTurfsAllowMedAccess()
var/L[] = new()
for(var/turf/t in oview(src,1))
if(!t.density)
if(!LinkBlocked(src, t) && !TurfBlockedNonWindowNonDoor(t,get_access("Medical Doctor")))
L.Add(t)
return L
//It isn't blocked if we can open it, man.
/proc/TurfBlockedNonWindowNonDoor(turf/loc, var/list/access)
for(var/obj/O in loc)
if(O.density && !istype(O, /obj/structure/window) && !istype(O, /obj/machinery/door))
return 1
if (O.density && (istype(O, /obj/machinery/door)) && (access.len))
var/obj/machinery/door/D = O
for(var/req in D.req_access)
if(!(req in access)) //doesn't have this access
return 1
return 0
*/
/*
* Medbot Assembly -- Can be made out of all three medkits.
*/
/obj/item/weapon/storage/firstaid/attackby(var/obj/item/robot_parts/S, mob/user as mob)
if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
..()
return
//Making a medibot!
if(src.contents.len >= 1)
user << "<span class='notice'>You need to empty [src] out first.</span>"
return
var/obj/item/weapon/firstaid_arm_assembly/A = new /obj/item/weapon/firstaid_arm_assembly
if(istype(src,/obj/item/weapon/storage/firstaid/fire))
A.skin = "ointment"
else if(istype(src,/obj/item/weapon/storage/firstaid/toxin))
A.skin = "tox"
else if(istype(src,/obj/item/weapon/storage/firstaid/o2))
A.skin = "o2"
del(S)
user.put_in_hands(A)
user << "<span class='notice'>You add the robot arm to the first aid kit.</span>"
user.drop_from_inventory(src)
del(src)
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if(istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if (!t)
return
if (!in_range(src, usr) && src.loc != usr)
return
src.created_name = t
else
switch(build_step)
if(0)
if(istype(W, /obj/item/device/healthanalyzer))
user.drop_item()
del(W)
src.build_step++
user << "<span class='notice'>You add the health sensor to [src].</span>"
src.name = "First aid/robot arm/health analyzer assembly"
src.overlays += image('icons/obj/aibots.dmi', "na_scanner")
if(1)
if(isprox(W))
user.drop_item()
del(W)
src.build_step++
user << "<span class='notice'>You complete the Medibot! Beep boop.</span>"
var/turf/T = get_turf(src)
var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot(T)
S.skin = src.skin
S.name = src.created_name
user.drop_from_inventory(src)
del(src)

View File

@@ -1,924 +0,0 @@
/obj/machinery/bot/secbot
name = "Securitron"
desc = "A little security robot. He looks less than thrilled."
icon = 'icons/obj/aibots.dmi'
icon_state = "secbot0"
layer = 5.0
density = 0
anchored = 0
health = 25
maxhealth = 25
fire_dam_coeff = 0.7
brute_dam_coeff = 0.5
req_one_access = list(access_security, access_forensics_lockers)
var/mob/target
var/oldtarget_name
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
var/frustration = 0
var/idcheck = 0 //If false, all station IDs are authorized for weapons.
var/check_records = 0 //Does it check security records?
var/check_arrest = 1 //Does it check arrest status?
var/arrest_type = 0 //If true, don't handcuff
var/declare_arrests = 0 //When making an arrest, should it notify everyone wearing sechuds?
var/has_laser = 0
var/next_harm_time = 0
var/lastfired = 0
var/shot_delay = 3 //.3 seconds between shots
var/lasercolor = ""
var/projectile = null//Holder for projectile type, to avoid so many else if chains
var/disabled = 0//A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag
var/mode = 0
#define SECBOT_IDLE 0 // idle
#define SECBOT_HUNT 1 // found target, hunting
#define SECBOT_PREP_ARREST 2 // at target, preparing to arrest
#define SECBOT_ARREST 3 // arresting target
#define SECBOT_START_PATROL 4 // start patrol
#define SECBOT_PATROL 5 // patrolling
#define SECBOT_SUMMON 6 // summoned by PDA
var/auto_patrol = 0 // set to make bot automatically patrol
var/beacon_freq = 1445 // navigation beacon frequency
var/control_freq = AI_FREQ // bot control frequency
var/turf/patrol_target // this is turf to navigate to (location of beacon)
var/new_destination // pending new destination (waiting for beacon response)
var/destination // destination description tag
var/next_destination // the next destination in the patrol route
var/list/path = new // list of path turfs
var/blockcount = 0 //number of times retried a blocked path
var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
var/nearest_beacon // the nearest beacon's tag
var/turf/nearest_beacon_loc // the nearest beacon's location
var/bot_version = "1.3"
var/search_range = 7
var/is_attacking = 0
var/obj/item/weapon/secbot_assembly = /obj/item/weapon/secbot_assembly
var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
/obj/machinery/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
idcheck = 0
auto_patrol = 1
/obj/item/weapon/secbot_assembly
name = "helmet/signaler assembly"
desc = "Some sort of bizarre assembly."
icon = 'icons/obj/aibots.dmi'
icon_state = "helmet_signaler"
item_state = "helmet"
var/build_step = 0
var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
/obj/machinery/bot/secbot/New(loc, created_name, created_lasercolor)
..()
if(created_name) name = created_name
if(created_lasercolor) lasercolor = created_lasercolor
update_icon()
spawn(3)
src.botcard = new /obj/item/weapon/card/id(src)
src.botcard.access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
if(radio_controller)
radio_controller.add_object(src, control_freq, filter = RADIO_SECBOT)
radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
if(lasercolor)
shot_delay = 6 //Longer shot delay because JESUS CHRIST
check_arrest = 0
check_records = 0 //Don't actively target people set to arrest
arrest_type = 1 //Don't even try to cuff
req_access = list(access_maint_tunnels)
arrest_type = 1
if((lasercolor == "b") && (name == created_name))//Picks a name if there isn't already a custome one
name = pick("BLUE BALLER","SANIC","BLUE KILLDEATH MURDERBOT")
if((lasercolor == "r") && (name == created_name))
name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT")
/obj/machinery/bot/secbot/update_icon()
if(on && is_attacking)
src.icon_state = "secbot-c"
else
src.icon_state = "secbot[src.on]"
/obj/machinery/bot/secbot/turn_on()
..()
update_icon()
src.updateUsrDialog()
/obj/machinery/bot/secbot/turn_off()
..()
src.target = null
src.oldtarget_name = null
src.anchored = 0
src.mode = SECBOT_IDLE
walk_to(src,0)
update_icon()
src.updateUsrDialog()
/obj/machinery/bot/secbot/attack_hand(mob/user as mob)
. = ..()
if(.)
return
usr.set_machine(src)
interact(user)
/obj/machinery/bot/secbot/interact(mob/user as mob)
var/dat
dat += text({"
<TT><B>Automatic Security Unit v[bot_version]</B></TT><BR><BR>
Status: []<BR>
Behaviour controls are [src.locked ? "locked" : "unlocked"]<BR>
Maintenance panel is [src.open ? "opened" : "closed"]"},
"<A href='?src=\ref[src];power=1'>[src.on ? "On" : "Off"]</A>" )
if(!src.locked || issilicon(user))
dat += text({"<BR>
Check for Weapon Authorization: []<BR>
Check Security Records: []<BR>
Check Arrest Status: []<BR>
Operating Mode: []<BR>
Report Arrests: []<BR>
Auto Patrol: []"},
"<A href='?src=\ref[src];operation=idcheck'>[src.idcheck ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=ignorerec'>[src.check_records ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=ignorearr'>[src.check_arrest ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=switchmode'>[src.arrest_type ? "Detain" : "Arrest"]</A>",
"<A href='?src=\ref[src];operation=declarearrests'>[src.declare_arrests ? "Yes" : "No"]</A>",
"<A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>" )
user << browse("<HEAD><TITLE>Securitron v[bot_version] controls</TITLE></HEAD>[dat]", "window=autosec")
onclose(user, "autosec")
return
/obj/machinery/bot/secbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
if(lasercolor && (istype(usr,/mob/living/carbon/human)))
var/mob/living/carbon/human/H = usr
if((lasercolor == "b") && (istype(H.wear_suit, /obj/item/clothing/suit/redtag)))//Opposing team cannot operate it
return
else if((lasercolor == "r") && (istype(H.wear_suit, /obj/item/clothing/suit/bluetag)))
return
if((href_list["power"]) && (src.allowed(usr)))
if(src.on)
turn_off()
else
turn_on()
src.updateUsrDialog()
return
switch(href_list["operation"])
if("idcheck")
src.idcheck = !src.idcheck
if("ignorerec")
src.check_records = !src.check_records
if("ignorearr")
src.check_arrest = !src.check_arrest
if("switchmode")
src.arrest_type = !src.arrest_type
if("patrol")
auto_patrol = !auto_patrol
mode = SECBOT_IDLE
if("declarearrests")
src.declare_arrests = !src.declare_arrests
src.updateUsrDialog()
/obj/machinery/bot/secbot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
if(src.allowed(user) && !open && !emagged)
src.locked = !src.locked
user << "<span class='notice'>Controls are now [src.locked ? "locked" : "unlocked"].</span>"
else
if(emagged)
user << "<span class='warning'>ERROR</span>"
if(open)
user << "<span class='warning'>Please close the access panel before locking it.</span>"
else
user << "<span class='notice'>Access denied.</span>"
else
..()
if(!istype(W, /obj/item/weapon/screwdriver) && W.force && !src.target)
src.target = user
if(lasercolor)//To make up for the fact that lasertag bots don't hunt
src.shootAt(user)
src.mode = SECBOT_HUNT
/obj/machinery/bot/secbot/Emag(mob/user as mob)
..()
if(open && !locked)
if(user) user << "<span class='warning'>You short out [src]'s target assessment circuits.</span>"
spawn(0)
for(var/mob/O in hearers(src, null))
O.show_message("\red <B>[src] buzzes oddly!</B>", 1)
src.target = null
if(user) src.oldtarget_name = user.name
src.last_found = world.time
src.anchored = 0
src.emagged = 2
src.on = 1
update_icon()
src.projectile = null
mode = SECBOT_IDLE
/obj/machinery/bot/secbot/process()
set background = 1
if(!src.on)
return
switch(mode)
if(SECBOT_IDLE) // idle
walk_to(src,0)
look_for_perp() // see if any criminals are in range
if(!mode && auto_patrol) // still idle, and set to patrol
mode = SECBOT_START_PATROL // switch to patrol mode
if(SECBOT_HUNT) // hunting for perp
// if can't reach perp for long enough, go idle
if(src.frustration >= 8)
// for(var/mob/O in hearers(src, null))
// O << "<span class='game say'><span class='name'>[src]</span> beeps, \"Backup requested! Suspect has evaded arrest.\""
src.target = null
src.last_found = world.time
src.frustration = 0
src.mode = 0
walk_to(src,0)
if(target) // make sure target exists
// We re-assess human targets, before bashing their head in, in case their credentials change
if(istype(target, /mob/living/carbon/human))
var/threat = src.assess_perp(target, idcheck, check_records, check_arrest)
if(threat < 4)
frustration = 8
return
// The target must remain in view to complete the desire to bash its head in
if(!(target in view(search_range,src)))
frustration++
return
if(!lasercolor && Adjacent(target)) // If right next to perp. Lasertag bots do not arrest anyone, just patrol and shoot and whatnot
if(istype(src.target,/mob/living/carbon))
playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
is_attacking = 1
update_icon()
spawn(2)
is_attacking = 0
update_icon()
var/mob/living/carbon/M = src.target
var/maxstuns = 4
if(istype(M, /mob/living/carbon/human))
if(M.stuttering < 10 && (!(HULK in M.mutations)))
M.stuttering = 10
M.Stun(10)
M.Weaken(10)
else
M.Weaken(10)
M.stuttering = 10
M.Stun(10)
maxstuns--
if(maxstuns <= 0)
target = null
if(declare_arrests)
var/area/location = get_area(src)
broadcast_security_hud_message("[src.name] is [arrest_type ? "detaining" : "arresting"] level [threatlevel] suspect <b>[target]</b> in <b>[location]</b>", src)
visible_message("\red <B>[src.target] has been stunned by [src]!</B>")
mode = SECBOT_PREP_ARREST
src.anchored = 1
src.target_lastloc = M.loc
return
else if(istype(src.target,/mob/living/simple_animal))
//just harmbaton them until dead
if(world.time > next_harm_time)
next_harm_time = world.time + 15
playsound(src.loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
visible_message("\red <B>[src] beats [src.target] with the stun baton!</B>")
update_icon()
spawn(2)
is_attacking = 0
update_icon()
var/mob/living/simple_animal/S = src.target
S.AdjustStunned(10)
S.adjustBruteLoss(15)
if(S.stat)
src.frustration = 8
if(preparing_arrest_sounds.len > 0)
playsound(src.loc, pick(preparing_arrest_sounds), 50, 0)
else // not next to perp
var/turf/olddist = get_dist(src, src.target)
walk_to(src, target,1,4)
shootAt(target)
if((get_dist(src, src.target)) >= (olddist))
src.frustration++
else
src.frustration = 0
else
src.frustration = 8
if(SECBOT_PREP_ARREST) // preparing to arrest target
if(src.lasercolor)
mode = SECBOT_IDLE
return
if(!target)
mode = SECBOT_IDLE
src.anchored = 0
return
// see if he got away
if((get_dist(src, src.target) > 1) || ((src.target.loc != src.target_lastloc) && src.target.weakened < 2))
src.anchored = 0
mode = SECBOT_HUNT
return
if(istype(src.target,/mob/living/carbon))
var/mob/living/carbon/C = target
var/wearing_hardsuit
if(istype(C,/mob/living/carbon/human))
var/mob/living/carbon/human/H = C
if(istype(H.back, /obj/item/weapon/rig) && istype(H.gloves,/obj/item/clothing/gloves/rig))
wearing_hardsuit = 1
if(!wearing_hardsuit && !C.handcuffed && !src.arrest_type)
playsound(src.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
mode = SECBOT_ARREST
visible_message("\red <B>[src] is trying to put handcuffs on [src.target]!</B>")
spawn(60)
if(get_dist(src, src.target) <= 1)
/*if(src.target.handcuffed)
return*/
if(istype(src.target,/mob/living/carbon))
C = target
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/handcuffs(target)
C.update_inv_handcuffed() //update the handcuffs overlay
mode = SECBOT_IDLE
src.target = null
src.anchored = 0
src.last_found = world.time
src.frustration = 0
if(preparing_arrest_sounds.len > 0)
playsound(src.loc, pick(preparing_arrest_sounds), 50, 0)
// var/arrest_message = pick("Have a secure day!","I AM THE LAW.", "God made tomorrow for the crooks we don't catch today.","You can't outrun a radio.")
// src.speak(arrest_message)
else
mode = SECBOT_IDLE
src.target = null
src.anchored = 0
src.last_found = world.time
src.frustration = 0
if(SECBOT_ARREST) // arresting
if(src.lasercolor)
mode = SECBOT_IDLE
return
if(!target || !istype(target, /mob/living/carbon))
src.anchored = 0
mode = SECBOT_IDLE
return
else
var/mob/living/carbon/C = target
if(!C.handcuffed)
src.anchored = 0
mode = SECBOT_IDLE
return
if(SECBOT_START_PATROL) // start a patrol
if(path.len > 0 && patrol_target) // have a valid path, so just resume
mode = SECBOT_PATROL
return
else if(patrol_target) // has patrol target already
spawn(0)
calc_path() // so just find a route to it
if(path.len == 0)
patrol_target = 0
return
mode = SECBOT_PATROL
else // no patrol target, so need a new one
find_patrol_target()
speak("Engaging patrol mode.")
if(SECBOT_PATROL) // patrol mode
patrol_step()
spawn(5)
if(mode == SECBOT_PATROL)
patrol_step()
if(SECBOT_SUMMON) // summoned to PDA
patrol_step()
spawn(4)
if(mode == SECBOT_SUMMON)
patrol_step()
sleep(4)
patrol_step()
return
// perform a single patrol step
/obj/machinery/bot/secbot/proc/patrol_step()
if(loc == patrol_target) // reached target
at_patrol_target()
return
else if(path.len > 0 && patrol_target) // valid path
var/turf/next = path[1]
if(next == loc)
path -= next
return
if(istype( next, /turf/simulated))
var/moved = step_towards(src, next) // attempt to move
if(moved) // successful move
blockcount = 0
path -= loc
look_for_perp()
if(lasercolor)
sleep(20)
else // failed to move
blockcount++
if(blockcount > 5) // attempt 5 times before recomputing
// find new path excluding blocked turf
spawn(2)
calc_path(next)
if(path.len == 0)
find_patrol_target()
else
blockcount = 0
return
return
else // not a valid turf
mode = SECBOT_IDLE
return
else // no path, so calculate new one
mode = SECBOT_START_PATROL
// finds a new patrol target
/obj/machinery/bot/secbot/proc/find_patrol_target()
send_status()
if(awaiting_beacon) // awaiting beacon response
awaiting_beacon++
if(awaiting_beacon > 5) // wait 5 secs for beacon response
find_nearest_beacon() // then go to nearest instead
return
if(next_destination)
set_destination(next_destination)
else
find_nearest_beacon()
return
// finds the nearest beacon to self
// signals all beacons matching the patrol code
/obj/machinery/bot/secbot/proc/find_nearest_beacon()
nearest_beacon = null
new_destination = "__nearest__"
post_signal(beacon_freq, "findbeacon", "patrol")
awaiting_beacon = 1
spawn(10)
awaiting_beacon = 0
if(nearest_beacon)
set_destination(nearest_beacon)
else
auto_patrol = 0
mode = SECBOT_IDLE
speak("Disengaging patrol mode.")
send_status()
/obj/machinery/bot/secbot/proc/at_patrol_target()
find_patrol_target()
return
// sets the current destination
// signals all beacons matching the patrol code
// beacons will return a signal giving their locations
/obj/machinery/bot/secbot/proc/set_destination(var/new_dest)
new_destination = new_dest
post_signal(beacon_freq, "findbeacon", "patrol")
awaiting_beacon = 1
// receive a radio signal
// used for beacon reception
/obj/machinery/bot/secbot/receive_signal(datum/signal/signal)
//log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/bot/secbot/receive_signal([signal.debug_print()])")
if(!on)
return
/*
world << "rec signal: [signal.source]"
for(var/x in signal.data)
world << "* [x] = [signal.data[x]]"
*/
var/recv = signal.data["command"]
// process all-bot input
if(recv=="bot_status")
send_status()
// check to see if we are the commanded bot
if(signal.data["active"] == src)
// process control input
switch(recv)
if("stop")
mode = SECBOT_IDLE
auto_patrol = 0
return
if("go")
mode = SECBOT_IDLE
auto_patrol = 1
return
if("summon")
patrol_target = signal.data["target"]
next_destination = destination
destination = null
awaiting_beacon = 0
mode = SECBOT_SUMMON
calc_path()
speak("Responding.")
return
// receive response from beacon
recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!recv || !valid)
return
if(recv == new_destination) // if the recvd beacon location matches the set destination
// the we will navigate there
destination = new_destination
patrol_target = signal.source.loc
next_destination = signal.data["next_patrol"]
awaiting_beacon = 0
// if looking for nearest beacon
else if(new_destination == "__nearest__")
var/dist = get_dist(src,signal.source.loc)
if(nearest_beacon)
// note we ignore the beacon we are located at
if(dist>1 && dist<get_dist(src,nearest_beacon_loc))
nearest_beacon = recv
nearest_beacon_loc = signal.source.loc
return
else
return
else if(dist > 1)
nearest_beacon = recv
nearest_beacon_loc = signal.source.loc
return
// send a radio signal with a single data key/value pair
/obj/machinery/bot/secbot/proc/post_signal(var/freq, var/key, var/value)
post_signal_multiple(freq, list("[key]" = value) )
// send a radio signal with multiple data key/values
/obj/machinery/bot/secbot/proc/post_signal_multiple(var/freq, var/list/keyval)
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
if(!frequency) return
var/datum/signal/signal = new()
signal.source = src
signal.transmission_method = 1
//for(var/key in keyval)
// signal.data[key] = keyval[key]
signal.data = keyval
//world << "sent [key],[keyval[key]] on [freq]"
if(signal.data["findbeacon"])
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
else if(signal.data["type"] == "secbot")
frequency.post_signal(src, signal, filter = RADIO_SECBOT)
else
frequency.post_signal(src, signal)
// signals bot status etc. to controller
/obj/machinery/bot/secbot/proc/send_status()
var/list/kv = list(
"type" = "secbot",
"name" = name,
"loca" = loc.loc, // area
"mode" = mode
)
post_signal_multiple(control_freq, kv)
// calculates a path to the current destination
// given an optional turf to avoid
/obj/machinery/bot/secbot/proc/calc_path(var/turf/avoid = null)
src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
if(!path) path = list()
// look for a criminal in view of the bot
/obj/machinery/bot/secbot/proc/look_for_perp()
if(src.disabled)
return
src.anchored = 0
for(var/mob/living/M in view(search_range,src)) //Let's find us a criminal
if(M.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var
continue
if(istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if(C.stat || C.handcuffed)
continue
if(src.lasercolor && C.lying)
continue//Does not shoot at people lying down when in lasertag mode, because it's just annoying, and they can fire once they get up.
if(C.name == src.oldtarget_name && world.time < src.last_found + 100)
continue
if(istype(C, /mob/living/carbon/human))
src.threatlevel = src.assess_perp(C, idcheck, check_records, check_arrest)
else if(istype(M, /mob/living/simple_animal/hostile))
if(M.stat == DEAD)
continue
else
src.threatlevel = 4
if(!src.threatlevel)
continue
else if(M.stat != DEAD && src.threatlevel >= 4)
src.target = M
src.oldtarget_name = M.name
src.speak("Level [src.threatlevel] infraction alert!")
if(!src.lasercolor && threat_found_sounds.len > 0)
playsound(src.loc, pick(threat_found_sounds), 50, 0)
src.visible_message("<b>[src]</b> points at [M.name]!")
mode = SECBOT_HUNT
spawn(0)
process() // ensure bot quickly responds to a perp
break
else
continue
/obj/machinery/bot/secbot/on_assess_perp(mob/living/carbon/human/perp)
if(lasercolor)
return laser_check(perp, lasercolor)
var/threat = 0
threat -= laser_check(perp, "b")
threat -= laser_check(perp, "r")
return threat
/obj/machinery/bot/secbot/proc/laser_check(mob/living/carbon/human/perp, var/lasercolor)
var/target_suit
var/target_weapon
var/threat = 0
//Lasertag turrets target the opposing team, how great is that? -Sieve
switch(lasercolor)
if("b")
target_suit = /obj/item/clothing/suit/redtag
target_weapon = /obj/item/weapon/gun/energy/lasertag/red
if("r")
target_suit = /obj/item/clothing/suit/bluetag
target_weapon = /obj/item/weapon/gun/energy/lasertag/blue
if((istype(perp.r_hand, target_weapon)) || (istype(perp.l_hand, target_weapon)))
threat += 4
if(istype(perp, /mob/living/carbon/human))
if(istype(perp.wear_suit, target_suit))
threat += 4
if(istype(perp.belt, target_weapon))
threat += 2
return threat
/obj/machinery/bot/secbot/is_assess_emagged()
return emagged == 2
/obj/machinery/bot/secbot/Bump(M as mob|obj) //Leave no door unopened!
if((istype(M, /obj/machinery/door)) && !isnull(src.botcard))
var/obj/machinery/door/D = M
if(!istype(D, /obj/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/machinery/door/blast))
D.open()
src.frustration = 0
else if(!src.anchored)
if((istype(M, /mob/living/)))
var/mob/living/O = M
src.loc = O.loc
src.frustration = 0
else if(istype(M, /obj/machinery/bot))
var/obj/machinery/bot/B = M
if(B.dir != src.dir) // Avoids issues if two bots are currently patrolling in the same direction
src.loc = B.loc
src.frustration = 0
return
/obj/machinery/bot/secbot/proc/speak(var/message)
for(var/mob/O in hearers(src, null))
O.show_message("<span class='game say'><span class='name'>[src]</span> beeps, \"[message]\"",2)
return
/obj/machinery/bot/secbot/explode()
walk_to(src,0)
src.visible_message("\red <B>[src] blows apart!</B>", 1)
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/secbot_assembly/Sa = new secbot_assembly(Tsec)
Sa.build_step = 1
Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole")
Sa.created_name = src.name
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/weapon/melee/baton(Tsec)
on_explosion()
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
new /obj/effect/decal/cleanable/blood/oil(src.loc)
del(src)
/obj/machinery/bot/secbot/proc/on_explosion(var/turf/Tsec)
new /obj/item/weapon/melee/baton(Tsec)
if(prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
//Secbot Construction
/obj/item/clothing/head/helmet/attackby(var/obj/item/device/assembly/signaler/S, mob/user as mob)
..()
if(!issignaler(S))
..()
return
if(src.type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
return
if(S.secured)
del(S)
var/obj/item/weapon/secbot_assembly/A = new /obj/item/weapon/secbot_assembly
user.put_in_hands(A)
user << "You add the signaler to the helmet."
user.drop_from_inventory(src)
del(src)
else
return
/obj/item/weapon/secbot_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if((istype(W, /obj/item/weapon/weldingtool)) && (!src.build_step))
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0,user))
src.build_step++
src.overlays += image('icons/obj/aibots.dmi', "hs_hole")
user << "You weld a hole in [src]!"
else if(isprox(W) && (src.build_step == 1))
user.drop_item()
src.build_step++
user << "You add the prox sensor to [src]!"
src.overlays += image('icons/obj/aibots.dmi', "hs_eye")
src.name = "helmet/signaler/prox sensor assembly"
del(W)
else if(((istype(W, /obj/item/robot_parts/l_arm)) || (istype(W, /obj/item/robot_parts/r_arm))) && (src.build_step == 2))
user.drop_item()
src.build_step++
user << "You add the robot arm to [src]!"
src.name = "helmet/signaler/prox sensor/robot arm assembly"
src.overlays += image('icons/obj/aibots.dmi', "hs_arm")
del(W)
else if((istype(W, /obj/item/weapon/melee/baton)) && (src.build_step >= 3))
user.drop_item()
src.build_step++
user << "You complete the Securitron! Beep boop."
var/obj/machinery/bot/secbot/S = new /obj/machinery/bot/secbot
S.loc = get_turf(src)
S.name = src.created_name
del(W)
del(src)
else if(istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && src.loc != usr)
return
src.created_name = t
/obj/machinery/bot/secbot/proc/shootAt(var/mob/target)
if(!has_laser || (lastfired && world.time - lastfired < shot_delay))
return
lastfired = world.time
var/turf/T = loc
var/atom/U = (istype(target, /atom/movable) ? target.loc : target)
if((!( U ) || !( T )))
return
while(!( istype(U, /turf) ))
U = U.loc
if(!( istype(T, /turf) ))
return
if(!projectile)
if(!lasercolor)
if(src.emagged == 2)
projectile = /obj/item/projectile/beam
else
projectile = /obj/item/projectile/beam/stun
else if(lasercolor == "b")
if(src.emagged == 2)
projectile = /obj/item/projectile/beam/lastertag/omni
else
projectile = /obj/item/projectile/beam/lastertag/blue
else if(lasercolor == "r")
if(src.emagged == 2)
projectile = /obj/item/projectile/beam/lastertag/omni
else
projectile = /obj/item/projectile/beam/lastertag/red
if(!( istype(U, /turf) ))
return
playsound(src.loc, src.emagged == 2 ? 'sound/weapons/Laser.ogg' : 'sound/weapons/Taser.ogg', 50, 1)
var/obj/item/projectile/A = new projectile (loc)
A.current = U
A.yo = U.y - T.y
A.xo = U.x - T.x
spawn( 0 )
A.process()
return
return
/obj/machinery/bot/secbot/emp_act(severity)
if(severity==2 && prob(70))
..(severity-1)
else
var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc )
pulse2.icon = 'icons/effects/effects.dmi'
pulse2.icon_state = "empdisable"
pulse2.name = "emp sparks"
pulse2.anchored = 1
pulse2.set_dir(pick(cardinal))
spawn(10)
pulse2.delete()
var/list/mob/living/carbon/targets = new
for(var/mob/living/carbon/C in view(12,src))
if(C.stat==2)
continue
targets += C
if(targets.len)
if(prob(50))
var/mob/toshoot = pick(targets)
if(toshoot)
targets-=toshoot
if(prob(50) && emagged < 2)
emagged = 2
shootAt(toshoot)
emagged = 0
else
shootAt(toshoot)
else if(prob(50))
if(targets.len)
var/mob/toarrest = pick(targets)
if(toarrest)
src.target = toarrest
src.mode = SECBOT_HUNT

View File

@@ -124,7 +124,7 @@
dat += "<a href='?src=\ref[src];screen=1'>Back</a>"
dat += "<br><b>Medical Robots:</b>"
var/bdat = null
for(var/obj/machinery/bot/medbot/M in world)
for(var/mob/living/bot/medbot/M in world)
if(M.z != src.z) continue //only find medibots on the same z-level as the computer
var/turf/bl = get_turf(M)

View File

@@ -136,7 +136,7 @@
dat += "<a href='?src=\ref[src];screen=1'>Back</a>"
dat += "<br><b>Medical Robots:</b>"
var/bdat = null
for(var/obj/machinery/bot/medbot/M in world)
for(var/mob/living/bot/medbot/M in world)
if(M.z != computer.z) continue //only find medibots on the same z-level as the computer
var/turf/bl = get_turf(M)

View File

@@ -103,8 +103,8 @@
bumpopen(M)
return
if(istype(AM, /obj/machinery/bot))
var/obj/machinery/bot/bot = AM
if(istype(AM, /mob/living/bot))
var/mob/living/bot/bot = AM
if(src.check_access(bot.botcard))
if(density)
open()

View File

@@ -58,7 +58,7 @@
/obj/machinery/door/window/Bumped(atom/movable/AM as mob|obj)
if (!( ismob(AM) ))
var/obj/machinery/bot/bot = AM
var/mob/living/bot/bot = AM
if(istype(bot))
if(density && src.check_access(bot.botcard))
open()

View File

@@ -333,51 +333,3 @@ Class Procs:
I.loc = loc
del(src)
return 1
/obj/machinery/proc/on_assess_perp(mob/living/carbon/human/perp)
return 0
/obj/machinery/proc/is_assess_emagged()
return emagged
/obj/machinery/proc/assess_perp(mob/living/carbon/human/perp, var/auth_weapons, var/check_records, var/check_arrest)
var/threatcount = 0 //the integer returned
if(is_assess_emagged())
return 10 //if emagged, always return 10.
threatcount += on_assess_perp(perp)
if(threatcount >= 10)
return threatcount
//Agent cards lower threatlevel.
var/obj/item/weapon/card/id/id = GetIdCard(perp)
if(id && istype(id, /obj/item/weapon/card/id/syndicate))
threatcount -= 2
if(auth_weapons && !src.allowed(perp))
if(istype(perp.l_hand, /obj/item/weapon/gun) || istype(perp.l_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(perp.r_hand, /obj/item/weapon/gun) || istype(perp.r_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(perp.belt, /obj/item/weapon/gun) || istype(perp.belt, /obj/item/weapon/melee))
threatcount += 2
if(perp.species.name != "Human") //beepsky so racist.
threatcount += 2
if(check_records || check_arrest)
var/perpname = perp.name
if(id)
perpname = id.registered_name
var/datum/data/record/R = find_security_record("name", perpname)
if(check_records && !R)
threatcount += 4
if(check_arrest && R && (R.fields["criminal"] == "*Arrest*"))
threatcount += 4
return threatcount

View File

@@ -494,7 +494,7 @@
return check_anomalies ? TURRET_PRIORITY_TARGET : TURRET_NOT_TARGET
if(ishuman(L)) //if the target is a human, analyze threat level
if(assess_perp(L, check_weapons, check_records, check_arrest) < 4)
if(assess_perp(L) < 4)
return TURRET_NOT_TARGET //if threat level < 4, keep going
if(L.lying) //if the perp is lying down, it's still a target but a less-important target
@@ -502,6 +502,45 @@
return TURRET_PRIORITY_TARGET //if the perp has passed all previous tests, congrats, it is now a "shoot-me!" nominee
/obj/machinery/porta_turret/proc/assess_perp(var/mob/living/carbon/human/H)
if(!H || !istype(H))
return
if(emagged)
return 10
var/threatcount = 0
var/obj/item/weapon/card/id/id = GetIdCard(H) //Agent cards lower threatlevel.
if(id && istype(id, /obj/item/weapon/card/id/syndicate))
threatcount -= 2
if(check_weapons && !allowed(H))
if(istype(H.l_hand, /obj/item/weapon/gun) || istype(H.l_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(H.r_hand, /obj/item/weapon/gun) || istype(H.r_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(H.belt, /obj/item/weapon/gun) || istype(H.belt, /obj/item/weapon/melee))
threatcount += 2
if(H.species.name != "Human")
threatcount += 2
if(check_records || check_arrest)
var/perpname = H.name
if(id)
perpname = id.registered_name
var/datum/data/record/R = find_security_record("name", perpname)
if(check_records && !R)
threatcount += 4
if(check_arrest && R && (R.fields["criminal"] == "*Arrest*"))
threatcount += 4
return threatcount
/obj/machinery/porta_turret/proc/tryToShootAt(var/list/mob/living/targets)
if(targets.len && last_target && (last_target in targets) && target(last_target))
return 1
@@ -549,12 +588,14 @@
update_icon()
/*
/obj/machinery/porta_turret/on_assess_perp(mob/living/carbon/human/perp)
if((check_access || attacked) && !allowed(perp))
//if the turret has been attacked or is angry, target all non-authorized personnel, see req_access
return 10
return ..()
*/
/obj/machinery/porta_turret/proc/target(var/mob/living/target)

View File

@@ -1,6 +1,5 @@
/obj/effect/decal/cleanable
var/list/random_icon_states = list()
var/targeted_by = null // Used so cleanbots can't claim a mess.
/obj/effect/decal/cleanable/New()
if (random_icon_states && length(src.random_icon_states) > 0)

View File

@@ -331,7 +331,7 @@
beepskyData["botstatus"] = list("loca" = null, "mode" = -1)
var/botsCount=0
if(SC.botlist && SC.botlist.len)
for(var/obj/machinery/bot/B in SC.botlist)
for(var/mob/living/bot/B in SC.botlist)
botsCount++
if(B.loc)
botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
@@ -465,7 +465,7 @@
BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
var/CbotData[0]
for(var/obj/machinery/bot/cleanbot/B in world)
for(var/mob/living/bot/cleanbot/B in world)
var/turf/bl = get_turf(B)
if(bl)
if(bl.z != cl.z)

View File

@@ -37,7 +37,7 @@
/obj/item/radio/integrated/beepsky
var/list/botlist = null // list of bots
var/obj/machinery/bot/secbot/active // the active bot; if null, show bot list
var/mob/living/bot/secbot/active // the active bot; if null, show bot list
var/list/botstatus // the status signal sent by the bot
var/control_freq = AI_FREQ

View File

@@ -128,12 +128,12 @@
if(istype(W, /obj/item/stack/sheet/metal) && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head)
var/obj/item/stack/sheet/metal/M = W
if (M.use(1))
var/obj/item/weapon/secbot_assembly/ed209_assembly/B = new /obj/item/weapon/secbot_assembly/ed209_assembly
B.loc = get_turf(src)
//var/obj/item/weapon/secbot_assembly/ed209_assembly/B = new /obj/item/weapon/secbot_assembly/ed209_assembly
//B.loc = get_turf(src)
user << "<span class='notice'>You armed the robot frame.</span>"
if (user.get_inactive_hand()==src)
user.remove_from_mob(src)
user.put_in_inactive_hand(B)
// user.put_in_inactive_hand(B)
del(src)
else
user << "<span class='warning'>You need one sheet of metal to arm the robot frame.</span>"

View File

@@ -97,7 +97,7 @@
/obj/machinery/shieldgen,
/obj/machinery/turretid,
/obj/machinery/vending,
/obj/machinery/bot,
/mob/living/bot,
/obj/machinery/door,
/obj/machinery/telecomms,
/obj/machinery/mecha_part_fabricator,

View File

@@ -0,0 +1,123 @@
/mob/living/bot
name = "Bot"
health = 20
maxHealth = 20
icon = 'icons/obj/aibots.dmi'
layer = MOB_LAYER
universal_speak = 1
density = 0
var/obj/item/weapon/card/id/botcard = null
var/list/botcard_access = list()
var/on = 1
var/open = 0
var/locked = 1
var/emagged = 0
var/light_strength = 3
var/obj/access_scanner = null
var/list/req_access = list()
/mob/living/bot/New()
..()
update_icons()
botcard = new /obj/item/weapon/card/id(src)
botcard.access = botcard_access.Copy()
access_scanner = new /obj(src)
access_scanner.req_access = req_access.Copy()
/mob/living/bot/Life()
..()
weakened = 0
stunned = 0
paralysis = 0
if(health <= 0)
death()
/mob/living/bot/updatehealth()
if(status_flags & GODMODE)
health = maxHealth
stat = CONSCIOUS
else
health = maxHealth - getFireLoss() - getBruteLoss()
oxyloss = 0
toxloss = 0
cloneloss = 0
halloss = 0
/mob/living/bot/death()
explode()
/mob/living/bot/attackby(var/obj/item/O, var/mob/user)
if(O.GetID())
if(access_scanner.allowed(user) && !open && !emagged)
locked = !locked
user << "<span class='notice'>Controls are now [locked ? "locked." : "unlocked."]</span>"
attack_hand(user)
else
if(emagged)
user << "<span class='warning'>ERROR</span>"
if(open)
user << "<span class='warning'>Please close the access panel before locking it.</span>"
else
user << "<span class='warning'>Access denied.</span>"
return
else if(istype(O, /obj/item/weapon/screwdriver))
if(!locked)
open = !open
user << "<span class='notice'>Maintenance panel is now [open ? "opened" : "closed"].</span>"
else
user << "<span class='notice'>You need to unlock the controls first.</span>"
return
else if(istype(O, /obj/item/weapon/weldingtool))
if(health < maxHealth)
if(open)
health = min(maxHealth, health + 10)
user.visible_message("<span class='notice'>[user] repairs [src].</span>","<span class='notice'>You repair [src].</span>")
else
user << "<span class='notice'>Unable to repair with the maintenance panel closed.</span>"
else
user << "<span class='notice'>[src] does not need a repair.</span>"
return
else if (istype(O, /obj/item/weapon/card/emag) && !emagged)
Emag(user)
return
else
..()
/mob/living/bot/attack_ai(var/mob/user)
return attack_hand(user)
/mob/living/bot/say(var/message)
var/verb = "beeps"
message = sanitize(message)
..(message, null, verb)
/mob/living/bot/Bump(var/atom/A)
if(istype(A, /obj/machinery/door) && botcard)
var/obj/machinery/door/D = A
if(!istype(D, /obj/machinery/door/firedoor) && !istype(D, /obj/machinery/door/blast) && D.check_access(botcard))
D.open()
/mob/living/bot/proc/Emag(var/mob/user)
log_and_message_admins("emagged [src]")
return
/mob/living/bot/proc/turn_on()
if(stat)
return 0
on = 1
SetLuminosity(light_strength)
update_icons()
return 1
/mob/living/bot/proc/turn_off()
on = 0
SetLuminosity(0)
update_icons()
/mob/living/bot/proc/explode()
del(src)

View File

@@ -0,0 +1,306 @@
/mob/living/bot/cleanbot
name = "Cleanbot"
desc = "A little cleaning robot, he looks so excited!"
icon_state = "cleanbot0"
req_access = list(access_janitor)
botcard_access = list(access_janitor, access_maint_tunnels)
locked = 0 // Start unlocked so roboticist can set them to patrol.
var/obj/effect/decal/cleanable/target
var/list/path = list()
var/list/patrol_path = list()
var/list/ignorelist = list()
var/obj/cleanbot_listener/listener = null
var/beacon_freq = 1445 // navigation beacon frequency
var/signal_sent = 0
var/closest_dist
var/next_dest
var/next_dest_loc
var/cleaning = 0
var/screwloose = 0
var/oddbutton = 0
var/should_patrol = 0
var/blood = 1
var/list/target_types = list()
/mob/living/bot/cleanbot/New()
..()
get_targets()
listener = new /obj/cleanbot_listener(src)
listener.cleanbot = src
if(radio_controller)
radio_controller.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS)
/mob/living/bot/cleanbot/Life()
..()
if(!on)
return
if(client)
return
if(cleaning)
return
if(!screwloose && !oddbutton && prob(5))
custom_emote(2, "makes an excited beeping booping sound!")
if(screwloose && prob(5)) // Make a mess
if(istype(loc, /turf/simulated))
var/turf/simulated/T = loc
if(T.wet < 1)
T.wet = 1
if(T.wet_overlay)
T.overlays -= T.wet_overlay
T.wet_overlay = null
T.wet_overlay = image('icons/effects/water.dmi', T, "wet_floor")
T.overlays += T.wet_overlay
spawn(800)
if(istype(T) && T.wet < 2)
T.wet = 0
if(T.wet_overlay)
T.overlays -= T.wet_overlay
T.wet_overlay = null
if(oddbutton && prob(5)) // Make a big mess
visible_message("Something flies out of [src]. He seems to be acting oddly.")
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc)
ignorelist += gib
spawn(600)
ignorelist -= gib
if(!target) // Find a target
for(var/obj/effect/decal/cleanable/D in view(7, src))
if(D in ignorelist)
continue
for(var/T in target_types)
if(istype(D, T))
target = D
patrol_path = list()
if(!target) // No targets in range
if(!should_patrol)
return
if(!patrol_path || !patrol_path.len)
if(!signal_sent || signal_sent > world.time + 200) // Waited enough or didn't send yet
var/datum/radio_frequency/frequency = radio_controller.return_frequency(beacon_freq)
if(!frequency)
return
closest_dist = 9999
next_dest = null
next_dest_loc = null
var/datum/signal/signal = new()
signal.source = src
signal.transmission_method = 1
signal.data = list("findbeakon" = "patrol")
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
signal_sent = world.time
else
if(next_dest)
next_dest_loc = listener.memorized[next_dest]
if(next_dest_loc)
patrol_path = AStar(loc, next_dest_loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id = botcard, exclude = null)
signal_sent = 0
else
if(pulledby) // Don't wiggle if someone pulls you
patrol_path = list()
return
if(patrol_path[1] == loc)
patrol_path -= patrol_path[1]
var/moved = step_towards(src, patrol_path[1])
if(moved)
patrol_path -= patrol_path[1]
if(target)
if(loc == target.loc)
if(!cleaning)
UnarmedAttack(target)
return
if(!path.len)
spawn(0)
path = AStar(loc, target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
return
if(path.len)
step_to(src, path[1])
path -= path[1]
return
/mob/living/bot/cleanbot/UnarmedAttack(var/obj/effect/decal/cleanable/D, var/proximity)
if(!..())
return
if(!istype(D))
return
if(D.loc != loc)
return
cleaning = 1
custom_emote(2, "begins to clean up the [D]")
update_icons()
var/cleantime = istype(D, /obj/effect/decal/cleanable/dirt) ? 10 : 50
if(do_after(src, cleantime))
if(istype(loc, /turf/simulated))
var/turf/simulated/f = loc
f.dirt = 0
if(!D)
return
del(D)
cleaning = 0
update_icons()
/mob/living/bot/cleanbot/explode()
on = 0
visible_message("<span class='danger'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
new /obj/item/device/assembly/prox_sensor(Tsec)
if(prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/mob/living/bot/cleanbot/update_icons()
if(cleaning)
icon_state = "cleanbot-c"
else
icon_state = "cleanbot[on]"
/mob/living/bot/cleanbot/turn_off()
..()
target = null
path = list()
patrol_path = list()
/mob/living/bot/cleanbot/attack_hand(var/mob/user)
var/dat
dat += "<TT><B>Automatic Station Cleaner v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];operation=start'>[on ? "On" : "Off"]</A><BR>"
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<BR>"
dat += "Maintenance panel is [open ? "opened" : "closed"]"
if(!locked || issilicon(user))
dat += "<BR>Cleans Blood: <A href='?src=\ref[src];operation=blood'>[blood ? "Yes" : "No"]</A><BR>"
dat += "<BR>Patrol station: <A href='?src=\ref[src];operation=patrol'>[should_patrol ? "Yes" : "No"]</A><BR>"
if(open && !locked)
dat += "Odd looking screw twiddled: <A href='?src=\ref[src];operation=screw'>[screwloose ? "Yes" : "No"]</A><BR>"
dat += "Weird button pressed: <A href='?src=\ref[src];operation=oddbutton'>[oddbutton ? "Yes" : "No"]</A>"
user << browse("<HEAD><TITLE>Cleaner v1.0 controls</TITLE></HEAD>[dat]", "window=autocleaner")
onclose(user, "autocleaner")
return
/mob/living/bot/cleanbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
switch(href_list["operation"])
if("start")
if(on)
turn_off()
else
turn_on()
if("blood")
blood = !blood
get_targets()
if("patrol")
should_patrol = !should_patrol
patrol_path = null
if("freq")
var/freq = text2num(input("Select frequency for navigation beacons", "Frequnecy", num2text(beacon_freq / 10))) * 10
if (freq > 0)
beacon_freq = freq
if("screw")
screwloose = !screwloose
usr << "<span class='notice>You twiddle the screw.</span>"
if("oddbutton")
oddbutton = !oddbutton
usr << "<span class='notice'>You press the weird button.</span>"
attack_hand(usr)
/mob/living/bot/cleanbot/Emag(var/mob/user)
..()
if(user)
user << "<span class='notice'>The [src] buzzes and beeps.</span>"
oddbutton = 1
screwloose = 1
/mob/living/bot/cleanbot/proc/get_targets()
target_types = list()
target_types += /obj/effect/decal/cleanable/blood/oil
target_types += /obj/effect/decal/cleanable/vomit
target_types += /obj/effect/decal/cleanable/crayon
target_types += /obj/effect/decal/cleanable/liquid_fuel
target_types += /obj/effect/decal/cleanable/mucus
target_types += /obj/effect/decal/cleanable/dirt
if(blood)
target_types += /obj/effect/decal/cleanable/blood
/* Radio object that listens to signals */
/obj/cleanbot_listener
var/mob/living/bot/cleanbot/cleanbot = null
var/list/memorized = list()
/obj/cleanbot_listener/receive_signal(var/datum/signal/signal)
var/recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!recv || !valid || !cleanbot)
return
var/dist = get_dist(cleanbot, signal.source.loc)
memorized[recv] = signal.source.loc
if(dist < cleanbot.closest_dist) // We check all signals, choosing the closest beakon; then we move to the NEXT one after the closest one
cleanbot.closest_dist = dist
cleanbot.next_dest = signal.data["next_patrol"]
/* Assembly */
/obj/item/weapon/bucket_sensor
desc = "It's a bucket. With a sensor attached."
name = "proxy bucket"
icon = 'icons/obj/aibots.dmi'
icon_state = "bucket_proxy"
force = 3.0
throwforce = 10.0
throw_speed = 2
throw_range = 5
w_class = 3.0
var/created_name = "Cleanbot"
/obj/item/weapon/bucket_sensor/attackby(var/obj/item/O, var/mob/user)
..()
if(istype(O, /obj/item/robot_parts/l_arm) || istype(O, /obj/item/robot_parts/r_arm))
user.drop_item()
del(O)
var/turf/T = get_turf(loc)
var/mob/living/bot/cleanbot/A = new /mob/living/bot/cleanbot(T)
A.name = created_name
user << "<span class='notice'>You add the robot arm to the bucket and sensor assembly. Beep boop!</span>"
user.drop_from_inventory(src)
del(src)
else if(istype(O, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && src.loc != usr)
return
created_name = t

View File

@@ -0,0 +1,192 @@
/mob/living/bot/secbot/ed209
name = "ED-209 Security Robot"
desc = "A security robot. He looks less than thrilled."
icon = 'icons/obj/aibots.dmi'
icon_state = "ed2090"
density = 1
health = 100
maxHealth = 100
bot_version = "2.5"
is_ranged = 1
preparing_arrest_sounds = new()
var/shot_delay = 4
var/last_shot = 0
/mob/living/bot/secbot/ed209/update_icons()
if(on && is_attacking)
icon_state = "ed209-c"
else
icon_state = "ed209[on]"
/mob/living/bot/secbot/ed209/explode()
visible_message("<span class='warning'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/secbot_assembly/ed209_assembly(Tsec)
var/obj/item/weapon/gun/energy/taser/G = new /obj/item/weapon/gun/energy/taser(Tsec)
G.power_supply.charge = 0
if(prob(50))
new /obj/item/robot_parts/l_leg(Tsec)
if(prob(50))
new /obj/item/robot_parts/r_leg(Tsec)
if(prob(50))
if(prob(50))
new /obj/item/clothing/head/helmet(Tsec)
else
new /obj/item/clothing/suit/armor/vest(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
new /obj/effect/decal/cleanable/blood/oil(Tsec)
del(src)
/mob/living/bot/secbot/ed209/RangedAttack(var/atom/A)
if(last_shot + shot_delay > world.time)
src << "You are not ready to fire yet!"
return
last_shot = world.time
var/turf/T = get_turf(src)
var/turf/U = get_turf(A)
var/projectile = /obj/item/projectile/beam/stun
if(emagged)
projectile = /obj/item/projectile/beam
playsound(loc, emagged ? 'sound/weapons/Laser.ogg' : 'sound/weapons/Taser.ogg', 50, 1)
var/obj/item/projectile/P = new projectile(loc)
P.original = A
P.starting = T
P.current = T
P.yo = U.y - T.y
P.xo = U.x - T.x
spawn()
P.process()
return
// Assembly
/obj/item/weapon/secbot_assembly/ed209_assembly
name = "ED-209 assembly"
desc = "Some sort of bizarre assembly."
icon = 'icons/obj/aibots.dmi'
icon_state = "ed209_frame"
item_state = "ed209_frame"
created_name = "ED-209 Security Robot"
var/lasercolor = ""
/obj/item/weapon/secbot_assembly/ed209_assembly/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
..()
if(istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && src.loc != usr)
return
created_name = t
return
switch(build_step)
if(0, 1)
if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg))
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the robot leg to [src].</span>"
name = "legs/frame assembly"
if(build_step == 1)
item_state = "ed209_leg"
icon_state = "ed209_leg"
else
item_state = "ed209_legs"
icon_state = "ed209_legs"
if(2)
if(istype(W, /obj/item/clothing/suit/storage/vest))
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the armor to [src].</span>"
name = "vest/legs/frame assembly"
item_state = "ed209_shell"
icon_state = "ed209_shell"
if(3)
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0, user))
build_step++
name = "shielded frame assembly"
user << "<span class='notice'>You welded the vest to [src].</span>"
if(4)
if(istype(W, /obj/item/clothing/head/helmet))
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the helmet to [src].</span>"
name = "covered and shielded frame assembly"
item_state = "ed209_hat"
icon_state = "ed209_hat"
if(5)
if(isprox(W))
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the prox sensor to [src].</span>"
name = "covered, shielded and sensored frame assembly"
item_state = "ed209_prox"
icon_state = "ed209_prox"
if(6)
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if (C.get_amount() < 1)
user << "<span class='warning'>You need one coil of wire to wire [src].</span>"
return
user << "<span class='notice'>You start to wire [src].</span>"
if(do_after(user, 40) && build_step == 6)
if(C.use(1))
build_step++
user << "<span class='notice'>You wire the ED-209 assembly.</span>"
name = "wired ED-209 assembly"
return
if(7)
if(istype(W, /obj/item/weapon/gun/energy/taser))
name = "taser ED-209 assembly"
build_step++
user << "<span class='notice'>You add [W] to [src].</span>"
item_state = "ed209_taser"
icon_state = "ed209_taser"
user.drop_item()
del(W)
if(8)
if(istype(W, /obj/item/weapon/screwdriver))
playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
var/turf/T = get_turf(user)
user << "<span class='notice'>Now attaching the gun to the frame...</span>"
sleep(40)
if(get_turf(user) == T && build_step == 8)
build_step++
name = "armed [name]"
user << "<span class='notice'>Taser gun attached.</span>"
if(9)
if(istype(W, /obj/item/weapon/cell))
build_step++
user << "<span class='notice'>You complete the ED-209.</span>"
var/turf/T = get_turf(src)
new /mob/living/bot/secbot/ed209(T,created_name,lasercolor)
user.drop_item()
del(W)
user.drop_from_inventory(src)
del(src)

View File

@@ -0,0 +1,359 @@
#define FARMBOT_COLLECT 1
#define FARMBOT_WATER 2
#define FARMBOT_UPROOT 3
#define FARMBOT_NUTRIMENT 4
/mob/living/bot/farmbot
name = "Farmbot"
desc = "The botanist's best friend."
icon = 'icons/obj/aibots.dmi'
icon_state = "farmbot0"
health = 50
maxHealth = 50
req_access = list(access_hydroponics)
var/action = "" // Used to update icon
var/waters_trays = 1
var/refills_water = 1
var/uproots_weeds = 1
var/replaces_nutriment = 0
var/collects_produce = 0
var/removes_dead = 0
var/obj/structure/reagent_dispensers/watertank/tank
var/attacking = 0
var/list/path = list()
var/atom/target
var/frustration = 0
/mob/living/bot/farmbot/New()
..()
spawn(5)
tank = locate() in contents
if(!tank)
tank = new /obj/structure/reagent_dispensers/watertank(src)
/mob/living/bot/farmbot/attack_hand(var/mob/user as mob)
. = ..()
if(.)
return
var/dat = ""
dat += "<TT><B>Automatic Hyrdoponic Assisting Unit v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
dat += "Water Tank: "
if (tank)
dat += "[tank.reagents.total_volume]/[tank.reagents.maximum_volume]"
else
dat += "Error: Watertank not found"
dat += "<br>Behaviour controls are [locked ? "locked" : "unlocked"]<hr>"
if(!locked)
dat += "<TT>Watering controls:<br>"
dat += "Water plants : <A href='?src=\ref[src];water=1'>[waters_trays ? "Yes" : "No"]</A><BR>"
dat += "Refill watertank : <A href='?src=\ref[src];refill=1'>[refills_water ? "Yes" : "No"]</A><BR>"
dat += "<br>Weeding controls:<br>"
dat += "Weed plants: <A href='?src=\ref[src];weed=1'>[uproots_weeds ? "Yes" : "No"]</A><BR>"
dat += "<br>Nutriment controls:<br>"
dat += "Replace fertilizer: <A href='?src=\ref[src];replacenutri=1'>[replaces_nutriment ? "Yes" : "No"]</A><BR>"
dat += "<br>Plant controls:<br>"
dat += "Collect produce: <A href='?src=\ref[src];collect=1'>[collects_produce ? "Yes" : "No"]</A><BR>"
dat += "Remove dead plants: <A href='?src=\ref[src];removedead=1'>[removes_dead ? "Yes" : "No"]</A><BR>"
dat += "</TT>"
user << browse("<HEAD><TITLE>Farmbot v1.0 controls</TITLE></HEAD>[dat]", "window=autofarm")
onclose(user, "autofarm")
return
/mob/living/bot/farmbot/Emag(var/mob/user)
..()
if(user)
user << "<span class='notice'>You short out [src]'s plant identifier circuits.</span>"
spawn(rand(30, 50))
visible_message("<span class='warning'>[src] buzzes oddly.</span>")
emagged = 1
/mob/living/bot/farmbot/Topic(href, href_list)
if(..())
return
usr.machine = src
add_fingerprint(usr)
if((href_list["power"]) && (access_scanner.allowed(usr)))
if(on)
turn_off()
else
turn_on()
if(locked)
return
if(href_list["water"])
waters_trays = !waters_trays
else if(href_list["refill"])
refills_water = !refills_water
else if(href_list["weed"])
uproots_weeds = !uproots_weeds
else if(href_list["replacenutri"])
replaces_nutriment = !replaces_nutriment
else if(href_list["collect"])
collects_produce = !collects_produce
else if(href_list["removedead"])
removes_dead = !removes_dead
attack_hand(usr)
return
/mob/living/bot/farmbot/update_icons()
if(on && action)
icon_state = "farmbot_[action]"
else
icon_state = "farmbot[on]"
/mob/living/bot/farmbot/Life()
..()
if(!on)
return
if(emagged && prob(1))
flick("farmbot_broke", src)
if(client)
return
if(target)
if(Adjacent(target))
UnarmedAttack(target)
path = list()
target = null
else
if(path.len && frustration < 5)
if(path[1] == loc)
path -= path[1]
var/t = step_towards(src, path[1])
if(t)
path -= path[1]
else
++frustration
else
path = list()
target = null
else
if(emagged)
for(var/mob/living/carbon/human/H in view(7, src))
target = H
break
else
for(var/obj/machinery/portable_atmospherics/hydroponics/tray in view(7, src))
if(process_tray(tray))
target = tray
frustration = 0
break
if(!target && refills_water && tank && tank.reagents.total_volume < tank.reagents.maximum_volume)
for(var/obj/structure/sink/source in view(7, src))
target = source
frustration = 0
break
if(target)
var/t = get_dir(target, src) // Turf with the tray is impassable, so a* can't navigate directly to it
path = AStar(loc, get_step(target, t), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
/mob/living/bot/farmbot/UnarmedAttack(var/atom/A, var/proximity)
if(!..())
return
if(attacking)
return
if(istype(A, /obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/T = A
var/t = process_tray(T)
switch(t)
if(0)
return
if(FARMBOT_COLLECT)
action = "water" // Needs a better one
update_icons()
visible_message("<span class='notice'>[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].</span>")
attacking = 1
if(do_after(src, 30))
visible_message("<span class='notice'>[src] [T.dead? "removes the plant from" : "harvests"] \the [A].</span>")
T.attack_hand(src)
if(FARMBOT_WATER)
action = "water"
update_icons()
visible_message("<span class='notice'>[src] starts watering \the [A].</span>")
attacking = 1
if(do_after(src, 30))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
visible_message("<span class='notice'>[src] waters \the [A].</span>")
tank.reagents.trans_to(T, 100 - T.waterlevel)
if(FARMBOT_UPROOT)
action = "hoe"
update_icons()
visible_message("<span class='notice'>[src] starts uprooting the weeds in \the [A].</span>")
attacking = 1
if(do_after(src, 30))
visible_message("<span class='notice'>[src] uproots the weeds in \the [A].</span>")
T.weedlevel = 0
if(FARMBOT_NUTRIMENT)
action = "fertile"
update_icons()
visible_message("<span class='notice'>[src] starts fertilizing \the [A].</span>")
attacking = 1
if(do_after(src, 30))
visible_message("<span class='notice'>[src] waters \the [A].</span>")
T.reagents.add_reagent("ammonia", 10)
attacking = 0
action = ""
update_icons()
T.update_icon()
else if(istype(A, /obj/structure/sink))
if(!tank || tank.reagents.total_volume >= tank.reagents.maximum_volume)
return
action = "water"
update_icons()
visible_message("<span class='notice'>[src] starts refilling its tank from \the [A].</span>")
attacking = 1
while(do_after(src, 10) && tank.reagents.total_volume < tank.reagents.maximum_volume)
tank.reagents.add_reagent("water", 10)
if(prob(5))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
attacking = 0
action = ""
update_icons()
visible_message("<span class='notice'>[src] finishes refilling its tank.</span>")
else if(emagged && ishuman(A))
var/action = pick("weed", "water")
attacking = 1
spawn(50) // Some delay
attacking = 0
switch(action)
if("weed")
flick("farmbot_hoe", src)
if(prob(50))
visible_message("<span class='danger'>[src] swings wildly at [A] with a minihoe, missing completely!</span>")
return
var/t = pick("slashed", "sliced", "cut", "clawed")
A.attack_generic(src, 5, t)
if("water")
flick("farmbot_water", src)
visible_message("<span class='danger'>[src] splashes [A] with water!</span>") // That's it. RP effect.
/mob/living/bot/farmbot/explode()
visible_message("<span class='danger'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/minihoe(Tsec)
new /obj/item/weapon/reagent_containers/glass/bucket(Tsec)
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/device/analyzer/plant_analyzer(Tsec)
if(tank)
tank.loc = Tsec
if(prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/mob/living/bot/farmbot/proc/process_tray(var/obj/machinery/portable_atmospherics/hydroponics/tray)
if(!tray || !istype(tray))
return 0
if(tray.closed_system || !tray.seed)
return 0
if(tray.dead && removes_dead || tray.harvest && collects_produce)
return FARMBOT_COLLECT
else if(refills_water && tray.waterlevel < 40 && !tray.reagents.has_reagent("water"))
return FARMBOT_WATER
else if(uproots_weeds && tray.weedlevel > 3)
return FARMBOT_UPROOT
else if(replaces_nutriment && tray.nutrilevel < 1 && tray.reagents.total_volume < 1)
return FARMBOT_NUTRIMENT
return 0
// Assembly
/obj/item/weapon/farmbot_arm_assembly
name = "water tank/robot arm assembly"
desc = "A water tank with a robot arm permanently grafted to it."
icon = 'icons/obj/aibots.dmi'
icon_state = "water_arm"
var/build_step = 0
var/created_name = "Farmbot"
w_class = 3.0
New()
..()
spawn(4) // If an admin spawned it, it won't have a watertank it, so lets make one for em!
var tank = locate(/obj/structure/reagent_dispensers/watertank) in contents
if(!tank)
new /obj/structure/reagent_dispensers/watertank(src)
/obj/structure/reagent_dispensers/watertank/attackby(var/obj/item/robot_parts/S, mob/user as mob)
if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
..()
return
var/obj/item/weapon/farmbot_arm_assembly/A = new /obj/item/weapon/farmbot_arm_assembly(loc)
user << "You add the robot arm to [src]."
loc = A //Place the water tank into the assembly, it will be needed for the finished bot
user.drop_from_inventory(S)
del(S)
/obj/item/weapon/farmbot_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if((istype(W, /obj/item/device/analyzer/plant_analyzer)) && (build_step == 0))
build_step++
user << "You add the plant analyzer to [src]."
name = "farmbot assembly"
user.remove_from_mob(W)
del(W)
else if((istype(W, /obj/item/weapon/reagent_containers/glass/bucket)) && (build_step == 1))
build_step++
user << "You add a bucket to [src]."
name = "farmbot assembly with bucket"
user.remove_from_mob(W)
del(W)
else if((istype(W, /obj/item/weapon/minihoe)) && (build_step == 2))
build_step++
user << "You add a minihoe to [src]."
name = "farmbot assembly with bucket and minihoe"
user.remove_from_mob(W)
del(W)
else if((isprox(W)) && (build_step == 3))
build_step++
user << "You complete the Farmbot! Beep boop."
var/mob/living/bot/farmbot/S = new /mob/living/bot/farmbot(get_turf(src))
for(var/obj/structure/reagent_dispensers/watertank/wTank in contents)
wTank.loc = S
S.tank = wTank
S.name = created_name
user.remove_from_mob(W)
del(W)
del(src)
else if(istype(W, /obj/item/weapon/pen))
var/t = input(user, "Enter new robot name", name, created_name) as text
t = sanitize(t, MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
return
created_name = t
/obj/item/weapon/farmbot_arm_assembly/attack_hand(mob/user as mob)
return //it's a converted watertank, no you cannot pick it up and put it in your backpack

View File

@@ -0,0 +1,365 @@
/mob/living/bot/floorbot
name = "Floorbot"
desc = "A little floor repairing robot, he looks so excited!"
icon_state = "floorbot0"
req_access = list(access_construction)
var/amount = 10 // 1 for tile, 2 for lattice
var/maxAmount = 60
var/tilemake = 0 // When it reaches 100, bot makes a tile
var/repairing = 0
var/improvefloors = 0
var/eattiles = 0
var/maketiles = 0
var/targetdirection = null
var/list/path = list()
var/list/ignorelist = list()
var/turf/target
/mob/living/bot/floorbot/update_icons()
if(repairing)
icon_state = "floorbot-c"
else if(amount > 0)
icon_state = "floorbot[on]"
else
icon_state = "floorbot[on]e"
/mob/living/bot/floorbot/attack_hand(var/mob/user)
user.set_machine(src)
var/dat
dat += "<TT><B>Automatic Station Floor Repairer v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A><BR>"
dat += "Maintenance panel is [open ? "opened" : "closed"]<BR>"
//dat += "Tiles left: [amount]<BR>"
dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]<BR>"
if(!locked || issilicon(user))
dat += "Improves floors: <A href='?src=\ref[src];operation=improve'>[improvefloors ? "Yes" : "No"]</A><BR>"
dat += "Finds tiles: <A href='?src=\ref[src];operation=tiles'>[eattiles ? "Yes" : "No"]</A><BR>"
dat += "Make singles pieces of metal into tiles when empty: <A href='?src=\ref[src];operation=make'>[maketiles ? "Yes" : "No"]</A><BR>"
var/bmode
if(targetdirection)
bmode = dir2text(targetdirection)
else
bmode = "Disabled"
dat += "<BR><BR>Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
user << browse("<HEAD><TITLE>Repairbot v1.0 controls</TITLE></HEAD>[dat]", "window=autorepair")
onclose(user, "autorepair")
return
/mob/living/bot/floorbot/Emag(var/mob/user)
..()
emagged = 1
if(user)
user << "<span class='notice'>The [src] buzzes and beeps.</span>"
/mob/living/bot/floorbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
switch(href_list["operation"])
if("start")
if (on)
turn_off()
else
turn_on()
if("improve")
improvefloors = !improvefloors
if("tiles")
eattiles = !eattiles
if("make")
maketiles = !maketiles
if("bridgemode")
switch(targetdirection)
if(null)
targetdirection = 1
if(1)
targetdirection = 2
if(2)
targetdirection = 4
if(4)
targetdirection = 8
if(8)
targetdirection = null
else
targetdirection = null
attack_hand(usr)
/mob/living/bot/floorbot/turn_off()
..()
target = null
path = list()
ignorelist = list()
/mob/living/bot/floorbot/Life()
..()
if(!on)
return
++tilemake
if(tilemake >= 100)
tilemake = 0
addTiles(1)
if(client)
return
if(prob(5))
custom_emote(2, "makes an excited booping beeping sound!")
if(ignorelist.len) // Don't stick forever
for(var/T in ignorelist)
if(prob(1))
ignorelist -= T
if(amount && !emagged)
if(!target && targetdirection) // Building a bridge
var/turf/T = get_step(src, targetdirection)
while(T in range(src))
if(istype(T, /turf/space))
target = T
break
T = get_step(T, targetdirection)
if(!target) // Fixing floors
for(var/turf/T in view(src))
if(T.loc.name == "Space")
continue
if(T in ignorelist)
continue
if(istype(T, /turf/space))
if(get_turf(T) == loc || prob(40)) // So they target the same tile all the time
target = T
if(improvefloors && istype(T, /turf/simulated/floor))
var/turf/simulated/floor/F = T
if(!F.floor_type && (get_turf(T) == loc || prob(40)))
target = T
if(emagged) // Time to griff
for(var/turf/simulated/floor/D in view(src))
if(D.loc.name == "Space")
continue
if(D in ignorelist)
continue
target = D
break
if(!target && amount < maxAmount && eattiles || maketiles) // Eat tiles
if(eattiles)
for(var/obj/item/stack/tile/plasteel/T in view(src))
if(T in ignorelist)
continue
target = T
break
if(maketiles && !target)
for(var/obj/item/stack/sheet/metal/T in view(src))
if(T in ignorelist)
continue
target = T
break
if(target && get_turf(target) == loc)
UnarmedAttack(target)
if(target && get_turf(target) != loc && !path.len)
spawn(0)
path = AStar(loc, get_turf(target), /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
ignorelist += target
target = null
if(path.len)
step_to(src, path[1])
path -= path[1]
/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity)
if(!..())
return
if(repairing)
return
if(get_turf(A) != loc)
return
if(emagged && istype(A, /turf/simulated/floor))
var/turf/simulated/floor/F = A
repairing = 1
update_icons()
if(F.is_plating())
visible_message("<span class='warning'>[src] begins to tear the floor tile from the floor!</span>")
if(do_after(src, 50))
F.break_tile_to_plating()
addTiles(1)
else
visible_message("<span class='danger'>[src] begins to tear through the floor!</span>")
if(do_after(src, 150)) // Extra time because this can and will kill.
F.ReplaceWithLattice()
addTiles(1)
target = null
repairing = 0
update_icons()
else if(istype(A, /turf/space))
var/building = 2
if(locate(/obj/structure/lattice, A))
building = 1
if(amount < building)
return
repairing = 1
update_icons()
visible_message("<span class='notice'>[src] begins to repair the hole.</span>")
if(do_after(src, 50))
if(A && (locate(/obj/structure/lattice, A) && building == 1 || !locate(/obj/structure/lattice, A) && building == 2)) // Make sure that it still needs repairs
var/obj/item/I
if(building == 1)
I = new /obj/item/stack/tile/plasteel(src)
else
I = new /obj/item/stack/rods(src)
A.attackby(I, src)
target = null
repairing = 0
update_icons()
else if(istype(A, /turf/simulated/floor))
var/turf/simulated/floor/F = A
if(!F.floor_type && amount)
repairing = 1
update_icons()
visible_message("<span class='notice'>[src] begins to improve the floor.</span>")
if(do_after(src, 50))
if(!F.floor_type)
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel(src)
F.attackby(T, src)
addTiles(-1)
target = null
repairing = 0
update_icons()
else if(istype(A, /obj/item/stack/tile/plasteel) && amount < maxAmount)
var/obj/item/stack/tile/plasteel/T = A
visible_message("<span class='notice'>[src] begins to collect tiles.</span>")
repairing = 1
update_icons()
if(do_after(src, 20))
if(T)
var/eaten = min(maxAmount - amount, T.get_amount())
T.use(eaten)
addTiles(eaten)
target = null
repairing = 0
update_icons()
else if(istype(A, /obj/item/stack/sheet/metal) && amount + 3 < maxAmount)
var/obj/item/stack/sheet/metal/M = A
visible_message("<span class='notice'>[src] begins to make tiles.</span>")
repairing = 1
update_icons()
if(do_after(50))
if(M)
M.use(1)
addTiles(4)
/mob/living/bot/floorbot/explode()
turn_off()
visible_message("<span class='danger'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
N.contents = list()
new /obj/item/device/assembly/prox_sensor(Tsec)
if(prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel(Tsec)
T.amount = amount
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
/mob/living/bot/floorbot/proc/addTiles(var/am)
amount += am
if(amount < 0)
amount = 0
else if(amount > maxAmount)
amount = maxAmount
/* Assembly */
/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/plasteel/T, mob/user as mob)
if(!istype(T, /obj/item/stack/tile/plasteel))
..()
return
if(contents.len >= 1)
user << "<span class='notice'>They wont fit in as there is already stuff inside.</span>"
return
if(user.s_active)
user.s_active.close(user)
if(T.use(10))
var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles
user.put_in_hands(B)
user << "<span class='notice'>You add the tiles into the empty toolbox. They protrude from the top.</span>"
user.drop_from_inventory(src)
del(src)
else
user << "<span class='warning'>You need 10 floor tiles for a floorbot.</span>"
return
/obj/item/weapon/toolbox_tiles
desc = "It's a toolbox with tiles sticking out the top"
name = "tiles and toolbox"
icon = 'icons/obj/aibots.dmi'
icon_state = "toolbox_tiles"
force = 3.0
throwforce = 10.0
throw_speed = 2
throw_range = 5
w_class = 3.0
var/created_name = "Floorbot"
/obj/item/weapon/toolbox_tiles/attackby(var/obj/item/W, mob/user as mob)
..()
if(isprox(W))
del(W)
var/obj/item/weapon/toolbox_tiles_sensor/B = new /obj/item/weapon/toolbox_tiles_sensor()
B.created_name = created_name
user.put_in_hands(B)
user << "<span class='notice'>You add the sensor to the toolbox and tiles!</span>"
user.drop_from_inventory(src)
del(src)
else if (istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, user) && loc != user)
return
created_name = t
/obj/item/weapon/toolbox_tiles_sensor
desc = "It's a toolbox with tiles sticking out the top and a sensor attached"
name = "tiles, toolbox and sensor arrangement"
icon = 'icons/obj/aibots.dmi'
icon_state = "toolbox_tiles_sensor"
force = 3.0
throwforce = 10.0
throw_speed = 2
throw_range = 5
w_class = 3.0
var/created_name = "Floorbot"
/obj/item/weapon/toolbox_tiles_sensor/attackby(var/obj/item/W, mob/user as mob)
..()
if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
del(W)
var/turf/T = get_turf(user.loc)
var/mob/living/bot/floorbot/A = new /mob/living/bot/floorbot(T)
A.name = created_name
user << "<span class='notice'>You add the robot arm to the odd looking toolbox assembly! Boop beep!</span>"
user.drop_from_inventory(src)
del(src)
else if(istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, user) && loc != user)
return
created_name = t

View File

@@ -0,0 +1,365 @@
/mob/living/bot/medbot
name = "Medbot"
desc = "A little medical robot. He looks somewhat underwhelmed."
icon_state = "medibot0"
req_access = list(access_medical)
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
botcard_access = list(access_medical, access_morgue, access_surgery, access_chemistry, access_virology, access_genetics)
//AI vars
var/frustration = 0
var/list/path = list()
var/mob/living/carbon/human/patient = null
var/mob/ignored = list() // Used by emag
var/last_newpatient_speak = 0
var/vocal = 1
//Healing vars
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
var/currently_healing = 0
var/injection_amount = 15 //How much reagent do we inject at a time?
var/heal_threshold = 10 //Start healing when they have this much damage in a category
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
var/treatment_brute = "tricordrazine"
var/treatment_oxy = "tricordrazine"
var/treatment_fire = "tricordrazine"
var/treatment_tox = "tricordrazine"
var/treatment_virus = "spaceacillin"
var/treatment_emag = "toxin"
var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds?
/mob/living/bot/medbot/Life()
..()
if(!on)
return
if(!client)
if(vocal && prob(1))
var/message = pick("Radar, put a mask on!", "There's always a catch, and it's the best there is.", "I knew it, I should've been a plastic surgeon.", "What kind of medbay is this? Everyone's dropping like dead flies.", "Delicious!")
say(message)
if(patient)
if(Adjacent(patient))
if(!currently_healing)
UnarmedAttack(patient)
else
if(path.len && (get_dist(patient, path[path.len]) > 2)) // We have a path, but it's off
path = list()
if(!path.len && (get_dist(src, patient) > 1))
spawn(0)
path = AStar(loc, get_turf(patient), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id = botcard)
if(!path)
path = list()
if(path.len)
step_to(src, path[1])
path -= path[1]
++frustration
if(get_dist(src, patient) > 7 || frustration > 8)
patient = null
else
for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
if(valid_healing_target(H))
patient = H
frustration = 0
if(last_newpatient_speak + 300 < world.time)
var/message = pick("Hey, [H.name]! Hold on, I'm coming.", "Wait [H.name]! I want to help!", "[H.name], you appear to be injured!")
say(message)
custom_emote(1, "points at [H.name].")
last_newpatient_speak = world.time
break
/mob/living/bot/medbot/UnarmedAttack(var/mob/living/carbon/human/H, var/proximity)
if(!..())
return
if(!on)
return
if(!istype(H))
return
if(H.stat == DEAD)
var/death_message = pick("No! NO!", "Live, damnit! LIVE!", "I... I've never lost a patient before. Not today, I mean.")
say(death_message)
patient = null
return
var/t = valid_healing_target(H)
if(!t)
var/message = pick("All patched up!", "An apple a day keeps me away.", "Feel better soon!")
say(message)
patient = null
return
icon_state = "medibots"
visible_message("<span class='warning'>[src] is trying to inject [H]!</span>")
if(declare_treatment)
var/area/location = get_area(src)
broadcast_medical_hud_message("[src] is treating <b>[H]</b> in <b>[location]</b>", src)
currently_healing = 1
update_icons()
if(do_mob(src, H, 30))
if(t == 1)
reagent_glass.reagents.trans_to(H, injection_amount)
reagent_glass.reagents.reaction(H, 2)
else
H.reagents.add_reagent(t, injection_amount)
visible_message("<span class='warning'>[src] injects [H] with the syringe!</span>")
currently_healing = 0
update_icons()
/mob/living/bot/medbot/update_icons()
overlays.Cut()
if(skin)
overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
if(currently_healing)
icon_state = "medibots"
else
icon_state = "medibot[on]"
/mob/living/bot/medbot/attack_hand(var/mob/user)
var/dat
dat += "<TT><B>Automatic Medical Unit v1.0</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
dat += "Maintenance panel is [open ? "opened" : "closed"]<BR>"
dat += "Beaker: "
if (reagent_glass)
dat += "<A href='?src=\ref[src];eject=1'>Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]</a>"
else
dat += "None Loaded"
dat += "<br>Behaviour controls are [locked ? "locked" : "unlocked"]<hr>"
if(!locked || issilicon(user))
dat += "<TT>Healing Threshold: "
dat += "<a href='?src=\ref[src];adj_threshold=-10'>--</a> "
dat += "<a href='?src=\ref[src];adj_threshold=-5'>-</a> "
dat += "[heal_threshold] "
dat += "<a href='?src=\ref[src];adj_threshold=5'>+</a> "
dat += "<a href='?src=\ref[src];adj_threshold=10'>++</a>"
dat += "</TT><br>"
dat += "<TT>Injection Level: "
dat += "<a href='?src=\ref[src];adj_inject=-5'>-</a> "
dat += "[injection_amount] "
dat += "<a href='?src=\ref[src];adj_inject=5'>+</a> "
dat += "</TT><br>"
dat += "Reagent Source: "
dat += "<a href='?src=\ref[src];use_beaker=1'>[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]</a><br>"
dat += "Treatment report is [declare_treatment ? "on" : "off"]. <a href='?src=\ref[src];declaretreatment=[1]'>Toggle</a><br>"
dat += "The speaker switch is [vocal ? "on" : "off"]. <a href='?src=\ref[src];togglevoice=[1]'>Toggle</a><br>"
user << browse("<HEAD><TITLE>Medibot v1.0 controls</TITLE></HEAD>[dat]", "window=automed")
onclose(user, "automed")
return
/mob/living/bot/medbot/attackby(var/obj/item/O, var/mob/user)
if(istype(O, /obj/item/weapon/reagent_containers/glass))
if(locked)
user << "<span class='notice'>You cannot insert a beaker because the panel is locked.</span>"
return
if(!isnull(reagent_glass))
user << "<span class='notice'>There is already a beaker loaded.</span>"
return
user.drop_item()
O.loc = src
reagent_glass = O
user << "<span class='notice'>You insert [O].</span>"
return
else
..()
/mob/living/bot/medbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
if ((href_list["power"]) && access_scanner.allowed(usr))
if (on)
turn_off()
else
turn_on()
else if((href_list["adj_threshold"]) && (!locked || issilicon(usr)))
var/adjust_num = text2num(href_list["adj_threshold"])
heal_threshold += adjust_num
if(heal_threshold < 5)
heal_threshold = 5
if(heal_threshold > 75)
heal_threshold = 75
else if((href_list["adj_inject"]) && (!locked || issilicon(usr)))
var/adjust_num = text2num(href_list["adj_inject"])
injection_amount += adjust_num
if(injection_amount < 5)
injection_amount = 5
if(injection_amount > 15)
injection_amount = 15
else if((href_list["use_beaker"]) && (!locked || issilicon(usr)))
use_beaker = !use_beaker
else if (href_list["eject"] && (!isnull(reagent_glass)))
if(!locked)
reagent_glass.loc = get_turf(src)
reagent_glass = null
else
usr << "<span class='notice'>You cannot eject the beaker because the panel is locked.</span>"
else if ((href_list["togglevoice"]) && (!locked || issilicon(usr)))
vocal = !vocal
else if ((href_list["declaretreatment"]) && (!locked || issilicon(usr)))
declare_treatment = !declare_treatment
attack_hand(usr)
return
/mob/living/bot/medbot/Emag(var/mob/user)
..()
if(!emagged)
if(user)
user << "<span class='warning'>You short out [src]'s reagent synthesis circuits.</span>"
visible_message("<span class='warning'>[src] buzzes oddly!</span>")
flick("medibot_spark", src)
patient = null
currently_healing = 0
emagged = 1
on = 1
update_icons()
ignored |= user
/mob/living/bot/medbot/explode()
on = 0
visible_message("<span class='danger'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
new /obj/item/weapon/storage/firstaid(Tsec)
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/device/healthanalyzer(Tsec)
if (prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
if(reagent_glass)
reagent_glass.loc = Tsec
reagent_glass = null
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
del(src)
return
/mob/living/bot/medbot/proc/valid_healing_target(var/mob/living/carbon/human/H)
if(H.stat == DEAD) // He's dead, Jim
return null
if(H.suiciding)
return null
if(H in ignored)
return null
if(emagged)
return treatment_emag
// If they're injured, we're using a beaker, and they don't have on of the chems in the beaker
if(reagent_glass && use_beaker && ((H.getBruteLoss() >= heal_threshold) || (H.getToxLoss() >= heal_threshold) || (H.getToxLoss() >= heal_threshold) || (H.getOxyLoss() >= (heal_threshold + 15))))
for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
if(!H.reagents.has_reagent(R))
return 1
continue
if((H.getBruteLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_brute)))
return treatment_brute //If they're already medicated don't bother!
if((H.getOxyLoss() >= (15 + heal_threshold)) && (!H.reagents.has_reagent(treatment_oxy)))
return treatment_oxy
if((H.getFireLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_fire)))
return treatment_fire
if((H.getToxLoss() >= heal_threshold) && (!H.reagents.has_reagent(treatment_tox)))
return treatment_tox
for(var/datum/disease/D in H.viruses)
if (!H.reagents.has_reagent(treatment_virus))
return treatment_virus // STOP DISEASE FOREVER
/* Construction */
/obj/item/weapon/storage/firstaid/attackby(var/obj/item/robot_parts/S, mob/user as mob)
if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
..()
return
if(contents.len >= 1)
user << "<span class='notice'>You need to empty [src] out first.</span>"
return
var/obj/item/weapon/firstaid_arm_assembly/A = new /obj/item/weapon/firstaid_arm_assembly
if(istype(src, /obj/item/weapon/storage/firstaid/fire))
A.skin = "ointment"
else if(istype(src, /obj/item/weapon/storage/firstaid/toxin))
A.skin = "tox"
else if(istype(src, /obj/item/weapon/storage/firstaid/o2))
A.skin = "o2"
del(S)
user.put_in_hands(A)
user << "<span class='notice'>You add the robot arm to the first aid kit.</span>"
user.drop_from_inventory(src)
del(src)
/obj/item/weapon/firstaid_arm_assembly
name = "first aid/robot arm assembly"
desc = "A first aid kit with a robot arm permanently grafted to it."
icon = 'icons/obj/aibots.dmi'
icon_state = "firstaid_arm"
var/build_step = 0
var/created_name = "Medibot" //To preserve the name if it's a unique medbot I guess
var/skin = null //Same as medbot, set to tox or ointment for the respective kits.
w_class = 3.0
/obj/item/weapon/firstaid_arm_assembly/New()
..()
spawn(5) // Terrible. TODO: fix
if(skin)
overlays += image('icons/obj/aibots.dmi', "kit_skin_[src.skin]")
/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
if(istype(W, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
return
created_name = t
else
switch(build_step)
if(0)
if(istype(W, /obj/item/device/healthanalyzer))
user.drop_item()
del(W)
build_step++
user << "<span class='notice'>You add the health sensor to [src].</span>"
name = "First aid/robot arm/health analyzer assembly"
overlays += image('icons/obj/aibots.dmi', "na_scanner")
if(1)
if(isprox(W))
user.drop_item()
del(W)
user << "<span class='notice'>You complete the Medibot! Beep boop.</span>"
var/turf/T = get_turf(src)
var/mob/living/bot/medbot/S = new /mob/living/bot/medbot(T)
S.skin = skin
S.name = created_name
user.drop_from_inventory(src)
del(src)

View File

@@ -0,0 +1,579 @@
/mob/living/bot/secbot
name = "Securitron"
desc = "A little security robot. He looks less than thrilled."
icon_state = "secbot0"
maxHealth = 50
health = 50
req_access = list(access_security, access_forensics_lockers)
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
var/mob/target
var/idcheck = 0 // If true, arrests for having weapons without authorization.
var/check_records = 0 // If true, arrests people without a record.
var/check_arrest = 1 // If true, arrests people who are set to arrest.
var/arrest_type = 0 // If true, doesn't handcuff. You monster.
var/declare_arrests = 0 // If true, announces arrests over sechuds.
var/auto_patrol = 0 // If true, patrols on its own
var/mode = 0
#define SECBOT_IDLE 0 // idle
#define SECBOT_HUNT 1 // found target, hunting
#define SECBOT_ARREST 2 // arresting target
#define SECBOT_START_PATROL 3 // start patrol
#define SECBOT_WAIT_PATROL 4 // waiting for signals
#define SECBOT_PATROL 5 // patrolling
#define SECBOT_SUMMON 6 // summoned by PDA
var/is_attacking = 0
var/is_ranged = 0
var/awaiting_surrender = 0
var/obj/secbot_listener/listener = null
var/beacon_freq = 1445 // Navigation beacon frequency
var/control_freq = AI_FREQ // Bot control frequency
var/list/path = list()
var/frustration = 0
var/turf/patrol_target = null // This is where we are headed
var/closest_dist // Used to find the closest beakon
var/destination = "__nearest__" // This is the current beacon's ID
var/next_destination = "__nearest__" // This is the next beacon's ID
var/nearest_beacon // Tag of the beakon that we assume to be the closest one
var/bot_version = 1.3
var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
/mob/living/bot/secbot/beepsky
name = "Officer Beepsky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
auto_patrol = 1
/mob/living/bot/secbot/New()
..()
listener = new /obj/secbot_listener(src)
listener.secbot = src
spawn(5) // Since beepsky is made on the start... this delay is necessary
if(radio_controller)
radio_controller.add_object(listener, control_freq, filter = RADIO_SECBOT)
radio_controller.add_object(listener, beacon_freq, filter = RADIO_NAVBEACONS)
/mob/living/bot/secbot/turn_off()
..()
target = null
frustration = 0
mode = SECBOT_IDLE
/mob/living/bot/secbot/update_icons()
if(on && is_attacking)
icon_state = "secbot-c"
else
icon_state = "secbot[on]"
/mob/living/bot/secbot/attack_hand(var/mob/user)
user.set_machine(src)
var/dat
dat += "<TT><B>Automatic Security Unit v[bot_version]</B></TT><BR><BR>"
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<BR>"
dat += "Maintenance panel is [open ? "opened" : "closed"]"
if(!locked || issilicon(user))
dat += "<BR>Check for Weapon Authorization: <A href='?src=\ref[src];operation=idcheck'>[idcheck ? "Yes" : "No"]</A><BR>"
dat += "Check Security Records: <A href='?src=\ref[src];operation=ignorerec'>[check_records ? "Yes" : "No"]</A><BR>"
dat += "Check Arrest Status: <A href='?src=\ref[src];operation=ignorearr'>[check_arrest ? "Yes" : "No"]</A><BR>"
dat += "Operating Mode: <A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A><BR>"
dat += "Report Arrests: <A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A><BR>"
dat += "Auto Patrol: <A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>"
user << browse("<HEAD><TITLE>Securitron v[bot_version] controls</TITLE></HEAD>[dat]", "window=autosec")
onclose(user, "autosec")
return
/mob/living/bot/secbot/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
if((href_list["power"]) && (access_scanner.allowed(usr)))
if(on)
turn_off()
else
turn_on()
return
switch(href_list["operation"])
if("idcheck")
idcheck = !idcheck
if("ignorerec")
check_records = !check_records
if("ignorearr")
check_arrest = !check_arrest
if("switchmode")
arrest_type = !arrest_type
if("patrol")
auto_patrol = !auto_patrol
mode = SECBOT_IDLE
if("declarearrests")
declare_arrests = !declare_arrests
attack_hand(usr)
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
var/curhealth = health
..()
if(health < curhealth)
target = user
awaiting_surrender = 5
mode = SECBOT_HUNT
/mob/living/bot/secbot/Life()
..()
if(!on)
return
if(client)
return
if(!target)
scan_view()
if(!locked && (mode == SECBOT_START_PATROL || mode == SECBOT_PATROL)) // Stop running away when we set you up
mode = SECBOT_IDLE
switch(mode)
if(SECBOT_IDLE)
if(auto_patrol && locked)
mode = SECBOT_START_PATROL
return
if(SECBOT_HUNT) // Target is in the view or has been recently - chase it
if(frustration > 7)
target = null
frustration = 0
awaiting_surrender = 0
mode = SECBOT_IDLE
return
if(target)
var/threat = check_threat(target)
if(threat < 4) // Re-evaluate in case they dropped the weapon or something
target = null
frustration = 0
awaiting_surrender = 0
mode = SECBOT_IDLE
return
if(!(target in view(7, src)))
++frustration
if(Adjacent(target))
mode = SECBOT_ARREST
return
else
if(is_ranged)
RangedAttack(target)
else
step_towards(src, target) // Melee bots chase a bit faster
spawn(8)
if(!Adjacent(target))
step_towards(src, target)
spawn(16)
if(!Adjacent(target))
step_towards(src, target)
if(SECBOT_ARREST) // Target is next to us - attack it
if(!target)
mode = SECBOT_IDLE
if(!Adjacent(target))
awaiting_surrender = 5 // I'm done playing nice
mode = SECBOT_HUNT
var/threat = check_threat(target)
if(threat < 4)
target = null
awaiting_surrender = 0
frustration = 0
mode = SECBOT_IDLE
return
if(awaiting_surrender < 5 && ishuman(target) && !target.lying)
if(awaiting_surrender == 0)
say("Down on the floor, [target]! You have five seconds to comply.")
++awaiting_surrender
else
UnarmedAttack(target)
if(ishuman(target) && declare_arrests)
var/area/location = get_area(src)
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [check_threat(target)] suspect <b>[target]</b> in <b>[location]</b>.", src)
return
if(SECBOT_START_PATROL)
if(path.len && patrol_target)
mode = SECBOT_PATROL
return
else if(patrol_target)
spawn(0)
calc_path()
if(!path.len)
patrol_target = null
mode = SECBOT_IDLE
else
mode = SECBOT_PATROL
if(!patrol_target)
if(next_destination)
find_next_target()
else
find_patrol_target()
say("Engaging patrol mode.")
mode = SECBOT_WAIT_PATROL
return
if(SECBOT_WAIT_PATROL)
if(patrol_target)
mode = SECBOT_START_PATROL
else
++frustration
if(frustration > 120)
frustration = 0
mode = SECBOT_IDLE
if(SECBOT_PATROL)
patrol_step()
spawn(10)
patrol_step()
return
if(SECBOT_SUMMON)
patrol_step()
spawn(8)
patrol_step()
spawn(16)
patrol_step()
return
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
if(!..())
return
if(!istype(M))
return
if(istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
var/cuff = 1
if(istype(C, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C
if(istype(H.back, /obj/item/weapon/rig) && istype(H.gloves,/obj/item/clothing/gloves/rig))
cuff = 0
if(!C.lying || C.handcuffed || arrest_type)
cuff = 0
if(!cuff)
C.stun_effect_act(0, 60, null)
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
is_attacking = 1
update_icons()
spawn(2)
is_attacking = 0
update_icons()
visible_message("<span class='warning'>[C] was prodded by [src] with a stun baton!</span>")
else
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
visible_message("<span class='warning'>[src] is trying to put handcuffs on [C]!</span>")
if(do_mob(src, C, 60))
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/handcuffs(C)
C.update_inv_handcuffed()
if(preparing_arrest_sounds.len)
playsound(loc, pick(preparing_arrest_sounds), 50, 0)
else if(istype(M, /mob/living/simple_animal))
var/mob/living/simple_animal/S = M
S.AdjustStunned(10)
S.adjustBruteLoss(15)
playsound(loc, "swing_hit", 50, 1, -1)
is_attacking = 1
update_icons()
spawn(2)
is_attacking = 0
update_icons()
visible_message("<span class='warning'>[M] was beaten by [src] with a stun baton!</span>")
/mob/living/bot/secbot/explode()
visible_message("<span class='warning'>[src] blows apart!</span>")
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
Sa.build_step = 1
Sa.overlays += image('icons/obj/aibots.dmi', "hs_hole")
Sa.created_name = name
new /obj/item/device/assembly/prox_sensor(Tsec)
new /obj/item/weapon/melee/baton(Tsec)
if(prob(50))
new /obj/item/robot_parts/l_arm(Tsec)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
new /obj/effect/decal/cleanable/blood/oil(Tsec)
del(src)
/mob/living/bot/secbot/proc/scan_view()
for(var/mob/living/M in view(7, src))
if(M.invisibility >= INVISIBILITY_LEVEL_ONE)
continue
if(M.stat)
continue
var/threat = check_threat(M)
if(threat >= 4)
target = M
say("Level [threat] infraction alert!")
custom_emote(1, "points at [M.name]!")
mode = SECBOT_HUNT
break
return
/mob/living/bot/secbot/proc/calc_path(var/turf/avoid = null)
path = AStar(loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid)
if(!path)
path = list()
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
if(M.stat == DEAD)
return 0
if(emagged)
return 10
var/threatcount = 0
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.handcuffed)
return 0
var/obj/item/weapon/card/id/id = GetIdCard(H) //Agent cards lower threatlevel.
if(id && istype(id, /obj/item/weapon/card/id/syndicate))
threatcount -= 2
if(idcheck && !access_scanner.allowed(H))
if(istype(H.l_hand, /obj/item/weapon/gun) || istype(H.l_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(H.r_hand, /obj/item/weapon/gun) || istype(H.r_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(H.belt, /obj/item/weapon/gun) || istype(H.belt, /obj/item/weapon/melee))
threatcount += 2
if(H.species.name != "Human") //beepsky so racist.
threatcount += 2
if(check_records || check_arrest)
var/perpname = H.name
if(id)
perpname = id.registered_name
var/datum/data/record/R = find_security_record("name", perpname)
if(check_records && !R)
threatcount += 4
if(check_arrest && R && (R.fields["criminal"] == "*Arrest*"))
threatcount += 4
else if(isanimal(M))
if(istype(M, /mob/living/simple_animal/hostile) && !istype(M, /mob/living/simple_animal/hostile/retaliate/goat))
threatcount += 4
return threatcount
/mob/living/bot/secbot/proc/patrol_step()
if(loc == patrol_target)
patrol_target = null
path = list()
mode = SECBOT_IDLE
return
if(path.len && patrol_target)
var/turf/next = path[1]
if(loc == next)
path -= next
return
var/moved = step_towards(src, next)
if(moved)
path -= next
frustration = 0
else
++frustration
if(frustration > 5) // Make a new path
mode = SECBOT_START_PATROL
return
else
mode = SECBOT_START_PATROL
/mob/living/bot/secbot/proc/find_patrol_target()
send_status()
nearest_beacon = null
next_destination = "__nearest__"
listener.post_signal(beacon_freq, "findbeacon", "patrol")
/mob/living/bot/secbot/proc/find_next_target()
send_status()
nearest_beacon = null
listener.post_signal(beacon_freq, "findbeacon", "patrol")
/mob/living/bot/secbot/proc/send_status()
var/list/kv = list(
"type" = "secbot",
"name" = name,
"loca" = get_area(loc),
"mode" = mode
)
listener.post_signal_multiple(control_freq, kv)
/obj/secbot_listener
var/mob/living/bot/secbot/secbot = null
/obj/secbot_listener/proc/post_signal(var/freq, var/key, var/value) // send a radio signal with a single data key/value pair
post_signal_multiple(freq, list("[key]" = value))
/obj/secbot_listener/proc/post_signal_multiple(var/freq, var/list/keyval) // send a radio signal with multiple data key/values
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
if(!frequency)
return
var/datum/signal/signal = new()
signal.source = secbot
signal.transmission_method = 1
signal.data = keyval.Copy()
if(signal.data["findbeacon"])
frequency.post_signal(secbot, signal, filter = RADIO_NAVBEACONS)
else if(signal.data["type"] == "secbot")
frequency.post_signal(secbot, signal, filter = RADIO_SECBOT)
else
frequency.post_signal(secbot, signal)
/obj/secbot_listener/receive_signal(datum/signal/signal)
if(!secbot || !secbot.on)
return
var/recv = signal.data["command"]
if(recv == "bot_status")
secbot.send_status()
return
if(signal.data["active"] == secbot)
switch(recv)
if("stop")
secbot.mode = SECBOT_IDLE
secbot.auto_patrol = 0
return
if("go")
secbot.mode = SECBOT_IDLE
secbot.auto_patrol = 1
return
if("summon")
secbot.patrol_target = signal.data["target"]
secbot.next_destination = secbot.destination
secbot.destination = null
//secbot.awaiting_beacon = 0
secbot.mode = SECBOT_SUMMON
secbot.calc_path()
secbot.say("Responding.")
return
recv = signal.data["beacon"]
var/valid = signal.data["patrol"]
if(!recv || !valid)
return
if(recv == secbot.next_destination) // This beacon is our target
secbot.destination = secbot.next_destination
secbot.patrol_target = signal.source.loc
secbot.next_destination = signal.data["next_patrol"]
else if(secbot.next_destination == "__nearest__")
var/dist = get_dist(secbot, signal.source.loc)
if(dist <= 1)
return
if(secbot.nearest_beacon)
if(dist < secbot.closest_dist)
secbot.nearest_beacon = recv
secbot.patrol_target = secbot.nearest_beacon
secbot.next_destination = signal.data["next_patrol"]
secbot.closest_dist = dist
return
else
secbot.nearest_beacon = recv
secbot.patrol_target = secbot.nearest_beacon
secbot.next_destination = signal.data["next_patrol"]
secbot.closest_dist = dist
//Secbot Construction
/obj/item/clothing/head/helmet/attackby(var/obj/item/device/assembly/signaler/S, mob/user as mob)
..()
if(!issignaler(S))
..()
return
if(type != /obj/item/clothing/head/helmet) //Eh, but we don't want people making secbots out of space helmets.
return
if(S.secured)
del(S)
var/obj/item/weapon/secbot_assembly/A = new /obj/item/weapon/secbot_assembly
user.put_in_hands(A)
user << "You add the signaler to the helmet."
user.drop_from_inventory(src)
del(src)
else
return
/obj/item/weapon/secbot_assembly
name = "helmet/signaler assembly"
desc = "Some sort of bizarre assembly."
icon = 'icons/obj/aibots.dmi'
icon_state = "helmet_signaler"
item_state = "helmet"
var/build_step = 0
var/created_name = "Securitron"
/obj/item/weapon/secbot_assembly/attackby(var/obj/item/O, var/mob/user)
..()
if(istype(O, /obj/item/weapon/weldingtool) && !build_step)
var/obj/item/weapon/weldingtool/WT = O
if(WT.remove_fuel(0, user))
build_step = 1
overlays += image('icons/obj/aibots.dmi', "hs_hole")
user << "You weld a hole in \the [src]."
else if(isprox(O) && (build_step == 1))
user.drop_item()
build_step = 2
user << "You add \the [O] to [src]."
overlays += image('icons/obj/aibots.dmi', "hs_eye")
name = "helmet/signaler/prox sensor assembly"
del(O)
else if((istype(O, /obj/item/robot_parts/l_arm) || istype(O, /obj/item/robot_parts/r_arm)) && build_step == 2)
user.drop_item()
build_step = 3
user << "You add \the [O] to [src]."
name = "helmet/signaler/prox sensor/robot arm assembly"
overlays += image('icons/obj/aibots.dmi', "hs_arm")
del(O)
else if(istype(O, /obj/item/weapon/melee/baton) && build_step == 3)
user.drop_item()
user << "You complete the Securitron! Beep boop."
var/mob/living/bot/secbot/S = new /mob/living/bot/secbot(get_turf(src))
S.name = created_name
del(O)
del(src)
else if(istype(O, /obj/item/weapon/pen))
var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
return
created_name = t

View File

@@ -28,7 +28,7 @@
/obj/machinery/atmospherics/unary/cryo_cell,
/obj/machinery/dna_scannernew,
/obj/item/weapon/grenade/chem_grenade,
/obj/machinery/bot/medbot,
/mob/living/bot/medbot,
/obj/machinery/computer/pandemic,
/obj/item/weapon/storage/secure/safe,
/obj/machinery/iv_drip,

View File

@@ -977,7 +977,7 @@
"asO" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0},/obj/machinery/door/firedoor/border_only{dir = 2},/obj/machinery/door/airlock/highsecurity{name = "Secure Armoury Section"; req_access = list(3)},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor,/area/security/warden)
"asP" = (/obj/structure/bed,/obj/machinery/flasher{id = "Cell 1"; pixel_x = 0; pixel_y = -28},/turf/simulated/floor{icon_state = "red"; dir = 4},/area/security/prison)
"asQ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{icon_state = "redcorner"; dir = 1},/area/hallway/primary/fore)
"asR" = (/obj/machinery/bot/secbot/beepsky{name = "Officer Beepsky"},/obj/structure/disposalpipe/segment,/turf/simulated/floor,/area/hallway/primary/fore)
"asR" = (/mob/living/bot/secbot/beepsky,/obj/structure/disposalpipe/segment,/turf/simulated/floor,/area/hallway/primary/fore)
"asS" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{icon_state = "redcorner"; dir = 4},/area/hallway/primary/fore)
"asT" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/effect/decal/cleanable/cobweb,/turf/simulated/floor/plating,/area/maintenance/dormitory)
"asU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/dormitory)