mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-01-06 07:23:16 +00:00
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:
123
code/modules/mob/living/bot/bot.dm
Normal file
123
code/modules/mob/living/bot/bot.dm
Normal 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)
|
||||
306
code/modules/mob/living/bot/cleanbot.dm
Normal file
306
code/modules/mob/living/bot/cleanbot.dm
Normal 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
|
||||
192
code/modules/mob/living/bot/ed209bot.dm
Normal file
192
code/modules/mob/living/bot/ed209bot.dm
Normal 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)
|
||||
359
code/modules/mob/living/bot/farmbot.dm
Normal file
359
code/modules/mob/living/bot/farmbot.dm
Normal 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
|
||||
365
code/modules/mob/living/bot/floorbot.dm
Normal file
365
code/modules/mob/living/bot/floorbot.dm
Normal 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
|
||||
365
code/modules/mob/living/bot/medbot.dm
Normal file
365
code/modules/mob/living/bot/medbot.dm
Normal 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)
|
||||
579
code/modules/mob/living/bot/secbot.dm
Normal file
579
code/modules/mob/living/bot/secbot.dm
Normal 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
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user