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

@@ -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,