diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index 5bb4c93bbc..9213765bbc 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -1,10 +1,6 @@
/atom/movable/proc/get_mob()
return
-/obj/machinery/bot/mulebot/get_mob()
- if(load && istype(load,/mob/living))
- return load
-
/obj/mecha/get_mob()
return occupant
@@ -14,6 +10,11 @@
/mob/get_mob()
return src
+/mob/living/bot/mulebot/get_mob()
+ if(load && istype(load, /mob/living))
+ return list(src, load)
+ return src
+
/proc/mobs_in_view(var/range, var/source)
var/list/mobs = list()
for(var/atom/movable/AM in view(range, source))
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index 55fe373301..d1c0b7b505 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -20,7 +20,7 @@
return // seems legit.
// Things you might plausibly want to follow
- if((ismob(A) && A != src) || istype(A,/obj/machinery/bot) || istype(A,/obj/singularity))
+ if((ismob(A) && A != src) || istype(A,/obj/singularity))
ManualFollow(A)
// Otherwise jump
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index a7b9dc0309..53850a102b 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -278,11 +278,11 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
group = "Miscellaneous"
/datum/supply_packs/mule
- name = "MULEbot Crate"
- contains = list(/obj/machinery/bot/mulebot)
+ name = "Mulebot Crate"
+ contains = list()
cost = 20
- containertype = /obj/structure/largecrate/mule
- containername = "MULEbot Crate"
+ containertype = /obj/structure/largecrate/animal/mulebot
+ containername = "Mulebot Crate"
group = "Operations"
/datum/supply_packs/cargotrain
diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm
deleted file mode 100644
index 312e6dd7d9..0000000000
--- a/code/datums/wires/mulebot.dm
+++ /dev/null
@@ -1,65 +0,0 @@
-/datum/wires/mulebot
- random = 1
- holder_type = /obj/machinery/bot/mulebot
- wire_count = 10
-
-var/const/WIRE_POWER1 = 1 // power connections
-var/const/WIRE_POWER2 = 2
-var/const/WIRE_AVOIDANCE = 4 // mob avoidance
-var/const/WIRE_LOADCHECK = 8 // load checking (non-crate)
-var/const/WIRE_MOTOR1 = 16 // motor wires
-var/const/WIRE_MOTOR2 = 32 //
-var/const/WIRE_REMOTE_RX = 64 // remote recv functions
-var/const/WIRE_REMOTE_TX = 128 // remote trans status
-var/const/WIRE_BEACON_RX = 256 // beacon ping recv
-
-/datum/wires/mulebot/CanUse(var/mob/living/L)
- var/obj/machinery/bot/mulebot/M = holder
- if(M.open)
- return 1
- return 0
-
-// So the wires do not open a new window, handle the interaction ourselves.
-/datum/wires/mulebot/Interact(var/mob/living/user)
- if(CanUse(user))
- var/obj/machinery/bot/mulebot/M = holder
- M.interact(user)
-
-/datum/wires/mulebot/UpdatePulsed(var/index)
- switch(index)
- if(WIRE_POWER1, WIRE_POWER2)
- holder.visible_message("\icon[holder] The charge light flickers.")
- if(WIRE_AVOIDANCE)
- holder.visible_message("\icon[holder] The external warning lights flash briefly.")
- if(WIRE_LOADCHECK)
- holder.visible_message("\icon[holder] The load platform clunks.")
- if(WIRE_MOTOR1, WIRE_MOTOR2)
- holder.visible_message("\icon[holder] The drive motor whines briefly.")
- else
- holder.visible_message("\icon[holder] You hear a radio crackle.")
-
-// HELPER PROCS
-
-/datum/wires/mulebot/proc/Motor1()
- return !(wires_status & WIRE_MOTOR1)
-
-/datum/wires/mulebot/proc/Motor2()
- return !(wires_status & WIRE_MOTOR2)
-
-/datum/wires/mulebot/proc/HasPower()
- return !(wires_status & WIRE_POWER1) && !(wires_status & WIRE_POWER2)
-
-/datum/wires/mulebot/proc/LoadCheck()
- return !(wires_status & WIRE_LOADCHECK)
-
-/datum/wires/mulebot/proc/MobAvoid()
- return !(wires_status & WIRE_AVOIDANCE)
-
-/datum/wires/mulebot/proc/RemoteTX()
- return !(wires_status & WIRE_REMOTE_TX)
-
-/datum/wires/mulebot/proc/RemoteRX()
- return !(wires_status & WIRE_REMOTE_RX)
-
-/datum/wires/mulebot/proc/BeaconRX()
- return !(wires_status & WIRE_BEACON_RX)
diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm
index f644391bf7..2b54b4ef27 100644
--- a/code/game/gamemodes/events.dm
+++ b/code/game/gamemodes/events.dm
@@ -422,11 +422,6 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
M << "
"
M.add_ion_law("THE STATION IS [who2pref] [who2]")
- if(botEmagChance)
- for(var/obj/machinery/bot/bot in machines)
- if(prob(botEmagChance))
- bot.emag_act(1)
-
/*
var/apcnum = 0
diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm
deleted file mode 100644
index 7e03826f05..0000000000
--- a/code/game/machinery/bots/bots.dm
+++ /dev/null
@@ -1,209 +0,0 @@
-// AI (i.e. game AI, not the AI player) controlled bots
-
-/obj/machinery/bot
- icon = 'icons/obj/aibots.dmi'
- layer = MOB_LAYER
- light_range = 3
- use_power = 0
- var/obj/item/weapon/card/id/botcard // the ID card that the bot "holds"
- var/on = 1
- var/health = 0 //do not forget to set health for your bot!
- var/maxhealth = 0
- var/fire_dam_coeff = 1.0
- var/brute_dam_coeff = 1.0
- var/open = 0//Maint panel
- var/locked = 1
- //var/emagged = 0 //Urist: Moving that var to the general /bot tree as it's used by most bots
-
-/obj/machinery/bot/proc/turn_on()
- if(stat) return 0
- on = 1
- set_light(initial(light_range))
- return 1
-
-/obj/machinery/bot/proc/turn_off()
- on = 0
- set_light(0)
-
-/obj/machinery/bot/proc/explode()
- qdel(src)
-
-/obj/machinery/bot/proc/healthcheck()
- if (src.health <= 0)
- src.explode()
-
-/obj/machinery/bot/emag_act(var/remaining_charges, var/user)
- if(locked && !emagged)
- locked = 0
- emagged = 1
- user << "You short out [src]'s maintenance hatch lock."
- log_and_message_admins("emagged [src]'s maintenance hatch lock")
- return 1
-
- if(!locked && open && emagged == 1)
- emagged = 2
- log_and_message_admins("emagged [src]'s inner circuits")
- return 1
-
-/obj/machinery/bot/examine(mob/user)
- ..(user)
- if (src.health < maxhealth)
- if (src.health > maxhealth/3)
- user << "[src]'s parts look loose."
- else
- user << "[src]'s parts look very loose!"
- return
-
-/obj/machinery/bot/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if(istype(W, /obj/item/weapon/screwdriver))
- if(!locked)
- open = !open
- user << "Maintenance panel is now [src.open ? "opened" : "closed"]."
- else if(istype(W, /obj/item/weapon/weldingtool))
- if(health < maxhealth)
- if(open)
- health = min(maxhealth, health+10)
- user.visible_message("[user] repairs [src]!","You repair [src]!")
- else
- user << "Unable to repair with the maintenance panel closed."
- else
- user << "[src] does not need a repair."
- else
- if(hasvar(W,"force") && hasvar(W,"damtype"))
- switch(W.damtype)
- if("fire")
- src.health -= W.force * fire_dam_coeff
- if("brute")
- src.health -= W.force * brute_dam_coeff
- ..()
- healthcheck()
- else
- ..()
-
-/obj/machinery/bot/bullet_act(var/obj/item/projectile/Proj)
- if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN))
- return
- health -= Proj.damage
- ..()
- healthcheck()
-
-/obj/machinery/bot/ex_act(severity)
- switch(severity)
- if(1.0)
- src.explode()
- return
- if(2.0)
- src.health -= rand(5,10)*fire_dam_coeff
- src.health -= rand(10,20)*brute_dam_coeff
- healthcheck()
- return
- if(3.0)
- if (prob(50))
- src.health -= rand(1,5)*fire_dam_coeff
- src.health -= rand(1,5)*brute_dam_coeff
- healthcheck()
- return
- return
-
-/obj/machinery/bot/emp_act(severity)
- var/was_on = on
- stat |= EMPED
- var/obj/effect/overlay/pulse2 = PoolOrNew(/obj/effect/overlay, src.loc )
- pulse2.icon = 'icons/effects/effects.dmi'
- pulse2.icon_state = "empdisable"
- pulse2.name = "emp sparks"
- pulse2.anchored = 1
- pulse2.set_dir(pick(cardinal))
-
- spawn(10)
- qdel(pulse2)
- if (on)
- turn_off()
- spawn(severity*300)
- stat &= ~EMPED
- if (was_on)
- turn_on()
-
-
-/obj/machinery/bot/attack_ai(mob/user as mob)
- src.attack_hand(user)
-
-/obj/machinery/bot/attack_hand(var/mob/living/carbon/human/user)
-
- if(!istype(user))
- return ..()
-
- if(user.species.can_shred(user))
- src.health -= rand(15,30)*brute_dam_coeff
- src.visible_message("[user] has slashed [src]!")
- playsound(src.loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- if(prob(10))
- new /obj/effect/decal/cleanable/blood/oil(src.loc)
- healthcheck()
-
-/******************************************************************/
-// Navigation procs
-// Used for A-star pathfinding
-
-
-// Returns the surrounding cardinal turfs with open links
-// Including through doors openable with the ID
-/turf/proc/CardinalTurfsWithAccess(var/obj/item/weapon/card/id/ID)
- var/L[] = new()
-
- // for(var/turf/simulated/t in oview(src,1))
-
- for(var/d in cardinal)
- var/turf/simulated/T = get_step(src, d)
- if(istype(T) && !T.density)
- if(!LinkBlockedWithAccess(src, T, ID))
- L.Add(T)
- return L
-
-
-// Returns true if a link between A and B is blocked
-// Movement through doors allowed if ID has access
-/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/weapon/card/id/ID)
-
- if(A == null || B == null) return 1
- var/adir = get_dir(A,B)
- var/rdir = get_dir(B,A)
- if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal
- var/iStep = get_step(A,adir&(NORTH|SOUTH))
- if(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID))
- return 0
-
- var/pStep = get_step(A,adir&(EAST|WEST))
- if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID))
- return 0
- return 1
-
- if(DirBlockedWithAccess(A,adir, ID))
- return 1
-
- if(DirBlockedWithAccess(B,rdir, ID))
- return 1
-
- for(var/obj/O in B)
- if(O.density && !istype(O, /obj/machinery/door) && !(O.flags & ON_BORDER))
- return 1
-
- return 0
-
-// Returns true if direction is blocked from loc
-// Checks doors against access with given ID
-/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/weapon/card/id/ID)
- for(var/obj/structure/window/D in loc)
- if(!D.density) continue
- if(D.dir == SOUTHWEST) return 1
- if(D.dir == dir) return 1
-
- for(var/obj/machinery/door/D in loc)
- if(!D.density) continue
- if(istype(D, /obj/machinery/door/window))
- if( dir & D.dir ) return !D.check_access(ID)
-
- //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID)
- //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID)
- else return !D.check_access(ID) // it's a real, air blocking door
- return 0
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
deleted file mode 100644
index 27e6cb1a9d..0000000000
--- a/code/game/machinery/bots/mulebot.dm
+++ /dev/null
@@ -1,887 +0,0 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
-// Mulebot - carries crates around for Quartermaster
-// Navigates via floor navbeacons
-// Remote Controlled from QM's PDA
-
-
-/obj/machinery/bot/mulebot
- name = "Mulebot"
- desc = "A Multiple Utility Load Effector bot."
- icon_state = "mulebot0"
- layer = MOB_LAYER
- density = 1
- anchored = 1
- animate_movement=1
- health = 150 //yeah, it's tougher than ed209 because it is a big metal box with wheels --rastaf0
- maxhealth = 150
- fire_dam_coeff = 0.7
- brute_dam_coeff = 0.5
- var/atom/movable/load = null // the loaded crate (usually)
- var/beacon_freq = 1400
- var/control_freq = BOT_FREQ
-
- suffix = ""
-
- var/turf/target // this is turf to navigate to (location of beacon)
- var/loaddir = 0 // this the direction to unload onto/load from
- var/new_destination = "" // pending new destination (waiting for beacon response)
- var/destination = "" // destination description
- var/home_destination = "" // tag of home beacon
- req_access = list(access_cargo) // added robotics access so assembly line drop-off works properly -veyveyr //I don't think so, Tim. You need to add it to the MULE's hidden robot ID card. -NEO
- var/path[] = new()
-
- var/mode = 0 //0 = idle/ready
- //1 = loading/unloading
- //2 = moving to deliver
- //3 = returning to home
- //4 = blocked
- //5 = computing navigation
- //6 = waiting for nav computation
- //7 = no destination beacon found (or no route)
-
- var/blockcount = 0 //number of times retried a blocked path
- var/reached_target = 1 //true if already reached the target
-
- var/refresh = 1 // true to refresh dialogue
- var/auto_return = 1 // true if auto return to home beacon after unload
- var/auto_pickup = 1 // true if auto-pickup at beacon
-
- var/obj/item/weapon/cell/cell
- // the installed power cell
-
- // constants for internal wiring bitflags
- var/datum/wires/mulebot/wires = null
-
- var/bloodiness = 0 // count of bloodiness
-
-/obj/machinery/bot/mulebot/New()
- ..()
- wires = new(src)
- botcard = new(src)
- botcard.access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
- cell = new(src)
- cell.charge = 2000
- cell.maxcharge = 2000
-
- spawn(5) // must wait for map loading to finish
- if(radio_controller)
- radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
- radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
-
- var/count = 0
- for(var/obj/machinery/bot/mulebot/other in world)
- count++
- if(!suffix)
- suffix = "#[count]"
- name = "Mulebot ([suffix])"
-
-/obj/machinery/bot/mulebot/Destroy()
- unload(0)
- qdel(wires)
- wires = null
- if(radio_controller)
- radio_controller.remove_object(src,beacon_freq)
- radio_controller.remove_object(src,control_freq)
- return ..()
-
-// attack by item
-// emag : lock/unlock,
-// screwdriver: open/close hatch
-// cell: insert it
-// other: chance to knock rider off bot
-/obj/machinery/bot/mulebot/attackby(var/obj/item/I, var/mob/user)
- if(istype(I,/obj/item/weapon/cell) && open && !cell)
- var/obj/item/weapon/cell/C = I
- user.drop_item()
- C.loc = src
- cell = C
- updateDialog()
- else if(istype(I,/obj/item/weapon/screwdriver))
- if(locked)
- user << "The maintenance hatch cannot be opened or closed while the controls are locked."
- return
-
- open = !open
- if(open)
- src.visible_message("[user] opens the maintenance hatch of [src]", "You open [src]'s maintenance hatch.")
- on = 0
- icon_state="mulebot-hatch"
- else
- src.visible_message("[user] closes the maintenance hatch of [src]", "You close [src]'s maintenance hatch.")
- icon_state = "mulebot0"
-
- updateDialog()
- else if (istype(I, /obj/item/weapon/wrench))
- if (src.health < maxhealth)
- src.health = min(maxhealth, src.health+25)
- user.visible_message(
- "\The [user] repairs \the [src]!",
- "You repair \the [src]!"
- )
- else
- user << "[src] does not need a repair!"
- else if(load && ismob(load)) // chance to knock off rider
- if(prob(1+I.force * 2))
- unload(0)
- user.visible_message("[user] knocks [load] off [src] with \the [I]!", "You knock [load] off [src] with \the [I]!")
- else
- user << "You hit [src] with \the [I] but to no effect."
- else
- ..()
- return
-
-/obj/machinery/bot/mulebot/emag_act(var/remaining_charges, var/user)
- locked = !locked
- user << "You [locked ? "lock" : "unlock"] the mulebot's controls!"
- flick("mulebot-emagged", src)
- playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 0)
- return 1
-
-/obj/machinery/bot/mulebot/ex_act(var/severity)
- unload(0)
- switch(severity)
- if(2)
- BITRESET(wires, rand(0,9))
- BITRESET(wires, rand(0,9))
- BITRESET(wires, rand(0,9))
- if(3)
- BITRESET(wires, rand(0,9))
- ..()
- return
-
-/obj/machinery/bot/mulebot/bullet_act()
- if(prob(50) && !isnull(load))
- unload(0)
- if(prob(25))
- src.visible_message("Something shorts out inside [src]!")
- var/index = 1<< (rand(0,9))
- if(wires & index)
- wires &= ~index
- else
- wires |= index
- ..()
-
-
-/obj/machinery/bot/mulebot/attack_ai(var/mob/user)
- user.set_machine(src)
- interact(user, 1)
-
-/obj/machinery/bot/mulebot/attack_hand(var/mob/user)
- . = ..()
- if (.)
- return
- user.set_machine(src)
- interact(user, 0)
-
-/obj/machinery/bot/mulebot/interact(var/mob/user, var/ai=0)
- var/dat
- dat += "Multiple Utility Load Effector Mk. III
"
- dat += "ID: [suffix]
"
- dat += "Power: [on ? "On" : "Off"]
"
-
- if(!open)
-
- dat += "Status: "
- switch(mode)
- if(0)
- dat += "Ready"
- if(1)
- dat += "Loading/Unloading"
- if(2)
- dat += "Navigating to Delivery Location"
- if(3)
- dat += "Navigating to Home"
- if(4)
- dat += "Waiting for clear path"
- if(5,6)
- dat += "Calculating navigation path"
- if(7)
- dat += "Unable to locate destination"
-
-
- dat += "
Current Load: [load ? load.name : "none"]
"
- dat += "Destination: [!destination ? "none" : destination]
"
- dat += "Power level: [cell ? cell.percent() : 0]%
"
-
- if(locked && !ai)
- dat += "
Controls are locked (unlock)"
- else
- dat += "
Controls are unlocked (lock)
"
-
- dat += "Toggle Power
"
- dat += "Stop
"
- dat += "Proceed
"
- dat += "Return to Home
"
- dat += "Set Destination
"
- dat += "Set Bot ID
"
- dat += "Set Home
"
- dat += "Toggle Auto Return Home ([auto_return ? "On":"Off"])
"
- dat += "Toggle Auto Pickup Crate ([auto_pickup ? "On":"Off"])
"
-
- if(load)
- dat += "Unload Now
"
- dat += "
The maintenance hatch is closed.
"
-
- else
- if(!ai)
- dat += "The maintenance hatch is open.
"
- dat += "Power cell: "
- if(cell)
- dat += "Installed
"
- else
- dat += "Removed
"
-
- dat += wires.GetInteractWindow()
- else
- dat += "The bot is in maintenance mode and cannot be controlled.
"
-
- user << browse("Mulebot [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500")
- onclose(user, "mulebot")
- return
-
-/obj/machinery/bot/mulebot/Topic(href, href_list)
- if(..())
- return
- if (usr.stat)
- return
- if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
- usr.set_machine(src)
-
- switch(href_list["op"])
- if("lock", "unlock")
- if(src.allowed(usr))
- locked = !locked
- updateDialog()
- else
- usr << "Access denied."
- return
- if("power")
- if (src.on)
- turn_off()
- else if (cell && !open)
- if (!turn_on())
- usr << "You can't switch on [src]."
- return
- else
- return
- visible_message("[usr] switches [on ? "on" : "off"] [src].")
- updateDialog()
-
-
- if("cellremove")
- if(open && cell && !usr.get_active_hand())
- cell.update_icon()
- usr.put_in_active_hand(cell)
- cell.add_fingerprint(usr)
- cell = null
-
- usr.visible_message("[usr] removes the power cell from [src].", "You remove the power cell from [src].")
- updateDialog()
-
- if("cellinsert")
- if(open && !cell)
- var/obj/item/weapon/cell/C = usr.get_active_hand()
- if(istype(C))
- usr.drop_item()
- cell = C
- C.loc = src
- C.add_fingerprint(usr)
-
- usr.visible_message("[usr] inserts a power cell into [src].", "You insert the power cell into [src].")
- updateDialog()
-
-
- if("stop")
- if(mode >=2)
- mode = 0
- updateDialog()
-
- if("go")
- if(mode == 0)
- start()
- updateDialog()
-
- if("home")
- if(mode == 0 || mode == 2)
- start_home()
- updateDialog()
-
- if("destination")
- refresh=0
- var/new_dest
- var/list/beaconlist = new()
- for(var/obj/machinery/navbeacon/N in navbeacons)
- beaconlist.Add(N.location)
- if(beaconlist.len)
- new_dest = input("Select new destination tag", "Mulebot [suffix ? "([suffix])" : ""]", destination) in beaconlist
- else
- alert("No destination beacons available.")
- refresh=1
- if(new_dest)
- set_destination(new_dest)
-
-
- if("setid")
- refresh=0
- var/new_id = sanitize(input("Enter new bot ID", "Mulebot [suffix ? "([suffix])" : ""]", suffix) as text|null, MAX_NAME_LEN)
- refresh=1
- if(new_id)
- suffix = new_id
- name = "Mulebot ([suffix])"
- updateDialog()
-
- if("sethome")
- refresh=0
- var/new_home = input("Enter new home tag", "Mulebot [suffix ? "([suffix])" : ""]", home_destination) as text|null
- refresh=1
- if(new_home)
- home_destination = new_home
- updateDialog()
-
- if("unload")
- if(load && mode !=1)
- if(loc == target)
- unload(loaddir)
- else
- unload(0)
-
- if("autoret")
- auto_return = !auto_return
-
- if("autopick")
- auto_pickup = !auto_pickup
-
- if("close")
- usr.unset_machine()
- usr << browse(null,"window=mulebot")
-
- updateDialog()
- //src.updateUsrDialog()
- else
- usr << browse(null, "window=mulebot")
- usr.unset_machine()
- return
-
-
-
-// returns true if the bot has power
-/obj/machinery/bot/mulebot/proc/has_power()
- return !open && cell && cell.charge>0 && wires.HasPower()
-
-// mousedrop a crate to load the bot
-// can load anything if emagged
-
-/obj/machinery/bot/mulebot/MouseDrop_T(var/atom/movable/C, mob/user)
-
- if(user.stat)
- return
-
- if (!on || !istype(C)|| C.anchored || get_dist(user, src) > 1 || get_dist(src,C) > 1 )
- return
-
- if(load)
- return
-
- load(C)
-
-
-// called to load a crate
-/obj/machinery/bot/mulebot/proc/load(var/atom/movable/C)
- if(wires.LoadCheck() && !istype(C,/obj/structure/closet/crate))
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
- return // if not emagged, only allow crates to be loaded
-
- //I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool.
- //So this is a simple fix that only allows a selection of item types to be considered. Further narrowing-down is below.
- if(!istype(C,/obj/item) && !istype(C,/obj/machinery) && !istype(C,/obj/structure) && !ismob(C))
- return
- if(!isturf(C.loc)) //To prevent the loading from stuff from someone's inventory, which wouldn't get handled properly.
- return
-
- if(get_dist(C, src) > 1 || load || !on)
- return
- for(var/obj/structure/plasticflaps/P in src.loc)//Takes flaps into account
- if(!CanPass(C,P))
- return
- mode = 1
-
- // if a create, close before loading
- var/obj/structure/closet/crate/crate = C
- if(istype(crate))
- crate.close()
-
- C.loc = src.loc
- sleep(2)
- if(C.loc != src.loc) //To prevent you from going onto more thano ne bot.
- return
- C.loc = src
- load = C
-
- C.pixel_y += 9
- if(C.layer < layer)
- C.layer = layer + 0.1
- overlays += C
-
- if(ismob(C))
- var/mob/M = C
- if(M.client)
- M.client.perspective = EYE_PERSPECTIVE
- M.client.eye = src
-
- mode = 0
- send_status()
-
-// called to unload the bot
-// argument is optional direction to unload
-// if zero, unload at bot's location
-/obj/machinery/bot/mulebot/proc/unload(var/dirn = 0)
- if(!load)
- return
-
- mode = 1
- overlays.Cut()
-
- load.loc = src.loc
- load.pixel_y -= 9
- load.layer = initial(load.layer)
- if(ismob(load))
- var/mob/M = load
- if(M.client)
- M.client.perspective = MOB_PERSPECTIVE
- M.client.eye = src
-
-
- if(dirn)
- var/turf/T = src.loc
- T = get_step(T,dirn)
- if(CanPass(load,T))//Can't get off onto anything that wouldn't let you pass normally
- step(load, dirn)
- else
- load.loc = src.loc//Drops you right there, so you shouldn't be able to get yourself stuck
-
- load = null
-
- // in case non-load items end up in contents, dump every else too
- // this seems to happen sometimes due to race conditions
- // with items dropping as mobs are loaded
-
- for(var/atom/movable/AM in src)
- if(AM == cell || AM == botcard) continue
-
- AM.loc = src.loc
- AM.layer = initial(AM.layer)
- AM.pixel_y = initial(AM.pixel_y)
- if(ismob(AM))
- var/mob/M = AM
- if(M.client)
- M.client.perspective = MOB_PERSPECTIVE
- M.client.eye = src
- mode = 0
-
-
-/obj/machinery/bot/mulebot/process()
- if(!has_power())
- on = 0
- return
- if(on)
- var/speed = (wires.Motor1() ? 1:0) + (wires.Motor2() ? 2:0)
- //world << "speed: [speed]"
- switch(speed)
- if(0)
- // do nothing
- if(1)
- process_bot()
- spawn(2)
- process_bot()
- sleep(2)
- process_bot()
- sleep(2)
- process_bot()
- sleep(2)
- process_bot()
- if(2)
- process_bot()
- spawn(4)
- process_bot()
- if(3)
- process_bot()
-
- if(refresh) updateDialog()
-
-/obj/machinery/bot/mulebot/proc/process_bot()
- //if(mode) world << "Mode: [mode]"
- switch(mode)
- if(0) // idle
- icon_state = "mulebot0"
- return
- if(1) // loading/unloading
- return
- if(2,3,4) // navigating to deliver,home, or blocked
-
- if(loc == target) // reached target
- at_target()
- return
-
- else if(path.len > 0 && target) // valid path
-
- var/turf/next = path[1]
- reached_target = 0
- if(next == loc)
- path -= next
- return
-
-
- if(istype( next, /turf/simulated))
- //world << "at ([x],[y]) moving to ([next.x],[next.y])"
-
-
- if(bloodiness)
- var/obj/effect/decal/cleanable/blood/tracks/B = new(loc)
- var/newdir = get_dir(next, loc)
- if(newdir == dir)
- B.set_dir(newdir)
- else
- newdir = newdir | dir
- if(newdir == 3)
- newdir = 1
- else if(newdir == 12)
- newdir = 4
- B.set_dir(newdir)
- bloodiness--
-
-
-
- var/moved = step_towards(src, next) // attempt to move
- if(cell) cell.use(1)
- if(moved) // successful move
- //world << "Successful move."
- blockcount = 0
- path -= loc
-
-
- if(mode==4)
- spawn(1)
- send_status()
-
- if(destination == home_destination)
- mode = 3
- else
- mode = 2
-
- else // failed to move
-
- //world << "Unable to move."
-
-
-
- blockcount++
- mode = 4
- if(blockcount == 3)
- src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
-
- if(blockcount > 5) // attempt 5 times before recomputing
- // find new path excluding blocked turf
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
-
- spawn(2)
- calc_path(next)
- if(path.len > 0)
- src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
- playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
- mode = 4
- mode =6
- return
- return
- else
- src.visible_message("[src] makes an annoyed buzzing sound", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
- //world << "Bad turf."
- mode = 5
- return
- else
- //world << "No path."
- mode = 5
- return
-
- if(5) // calculate new path
- //world << "Calc new path."
- mode = 6
- spawn(0)
-
- calc_path()
-
- if(path.len > 0)
- blockcount = 0
- mode = 4
- src.visible_message("[src] makes a delighted ping!", "You hear a ping.")
- playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
-
- else
- src.visible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
- playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
-
- mode = 7
- //if(6)
- //world << "Pending path calc."
- //if(7)
- //world << "No dest / no route."
- return
-
-
-// calculates a path to the current destination
-// given an optional turf to avoid
-/obj/machinery/bot/mulebot/proc/calc_path(var/turf/avoid = null)
- src.path = AStar(src.loc, src.target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, id=botcard, exclude=avoid)
- if(!src.path)
- src.path = list()
-
-
-// sets the current destination
-// signals all beacons matching the delivery code
-// beacons will return a signal giving their locations
-/obj/machinery/bot/mulebot/proc/set_destination(var/new_dest)
- spawn(0)
- new_destination = new_dest
- post_signal(beacon_freq, "findbeacon", "delivery")
- updateDialog()
-
-// starts bot moving to current destination
-/obj/machinery/bot/mulebot/proc/start()
- if(destination == home_destination)
- mode = 3
- else
- mode = 2
- icon_state = "mulebot[wires.MobAvoid()]"
-
-// starts bot moving to home
-// sends a beacon query to find
-/obj/machinery/bot/mulebot/proc/start_home()
- spawn(0)
- set_destination(home_destination)
- mode = 4
- icon_state = "mulebot[wires.MobAvoid()]"
-
-// called when bot reaches current target
-/obj/machinery/bot/mulebot/proc/at_target()
- if(!reached_target)
- src.visible_message("[src] makes a chiming sound!", "You hear a chime.")
- playsound(src.loc, 'sound/machines/chime.ogg', 50, 0)
- reached_target = 1
-
- if(load) // if loaded, unload at target
- unload(loaddir)
- else
- // not loaded
- if(auto_pickup) // find a crate
- var/atom/movable/AM
- if(!wires.LoadCheck()) // if emagged, load first unanchored thing we find
- for(var/atom/movable/A in get_step(loc, loaddir))
- if(!A.anchored)
- AM = A
- break
- else // otherwise, look for crates only
- AM = locate(/obj/structure/closet/crate) in get_step(loc,loaddir)
- if(AM)
- load(AM)
- // whatever happened, check to see if we return home
-
- if(auto_return && destination != home_destination)
- // auto return set and not at home already
- start_home()
- mode = 4
- else
- mode = 0 // otherwise go idle
-
- send_status() // report status to anyone listening
-
- return
-
-// called when bot bumps into anything
-/obj/machinery/bot/mulebot/Bump(var/atom/obs)
- if(!wires.MobAvoid()) //usually just bumps, but if avoidance disabled knock over mobs
- var/mob/M = obs
- if(ismob(M))
- if(istype(M,/mob/living/silicon/robot))
- src.visible_message("[src] bumps into [M]!")
- else
- src.visible_message("[src] knocks over [M]!")
- M.stop_pulling()
- M.Stun(8)
- M.Weaken(5)
- M.lying = 1
- ..()
-
-// called from mob/living/carbon/human/Crossed()
-// when mulebot is in the same loc
-/obj/machinery/bot/mulebot/proc/RunOver(var/mob/living/carbon/human/H)
- src.visible_message("[src] drives over [H]!")
- playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
-
- var/damage = rand(5,15)
- H.apply_damage(2*damage, BRUTE, BP_HEAD)
- H.apply_damage(2*damage, BRUTE, BP_TORSO)
- H.apply_damage(0.5*damage, BRUTE, BP_L_LEG)
- H.apply_damage(0.5*damage, BRUTE, BP_R_LEG)
- H.apply_damage(0.5*damage, BRUTE, BP_L_ARM)
- H.apply_damage(0.5*damage, BRUTE, BP_R_ARM)
-
- blood_splatter(src,H,1)
- bloodiness += 4
-
-// player on mulebot attempted to move
-/obj/machinery/bot/mulebot/relaymove(var/mob/user)
- if(user.stat)
- return
- if(load == user)
- unload(0)
- return
-
-// receive a radio signal
-// used for control and beacon reception
-
-/obj/machinery/bot/mulebot/receive_signal(datum/signal/signal)
-
- if(!on)
- return
-
- var/recv = signal.data["command"]
- // process all-bot input
- if(recv=="bot_status" && wires.RemoteRX())
- send_status()
-
-
- recv = signal.data["command [suffix]"]
- if(wires.RemoteRX())
- // process control input
- switch(recv)
- if("stop")
- mode = 0
- return
-
- if("go")
- start()
- return
-
- if("target")
- set_destination(signal.data["destination"] )
- return
-
- if("unload")
- if(loc == target)
- unload(loaddir)
- else
- unload(0)
- return
-
- if("home")
- start_home()
- return
-
- if("bot_status")
- send_status()
- return
-
- if("autoret")
- auto_return = text2num(signal.data["value"])
- return
-
- if("autopick")
- auto_pickup = text2num(signal.data["value"])
- return
-
- // receive response from beacon
- recv = signal.data["beacon"]
- if(wires.BeaconRX())
- if(recv == new_destination) // if the recvd beacon location matches the set destination
- // the we will navigate there
- destination = new_destination
- target = signal.source.loc
- var/direction = signal.data["dir"] // this will be the load/unload dir
- if(direction)
- loaddir = text2num(direction)
- else
- loaddir = 0
- icon_state = "mulebot[wires.MobAvoid()]"
- calc_path()
- updateDialog()
-
-// send a radio signal with a single data key/value pair
-/obj/machinery/bot/mulebot/proc/post_signal(var/freq, var/key, var/value)
- post_signal_multiple(freq, list("[key]" = value) )
-
-// send a radio signal with multiple data key/values
-/obj/machinery/bot/mulebot/proc/post_signal_multiple(var/freq, var/list/keyval)
-
- if(freq == beacon_freq && !wires.BeaconRX())
- return
- if(freq == control_freq && !wires.RemoteTX())
- return
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
-
- if(!frequency) return
-
-
-
- var/datum/signal/signal = new()
- signal.source = src
- signal.transmission_method = 1
- //for(var/key in keyval)
- // signal.data[key] = keyval[key]
- signal.data = keyval
- //world << "sent [key],[keyval[key]] on [freq]"
- if (signal.data["findbeacon"])
- frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
- else if (signal.data["type"] == "mulebot")
- frequency.post_signal(src, signal, filter = RADIO_MULEBOT)
- else
- frequency.post_signal(src, signal)
-
-// signals bot status etc. to controller
-/obj/machinery/bot/mulebot/proc/send_status()
- var/list/kv = list(
- "type" = "mulebot",
- "name" = suffix,
- "loca" = (loc ? loc.loc : "Unknown"), // somehow loc can be null and cause a runtime - Quarxink
- "mode" = mode,
- "powr" = (cell ? cell.percent() : 0),
- "dest" = destination,
- "home" = home_destination,
- "load" = load,
- "retn" = auto_return,
- "pick" = auto_pickup,
- )
- post_signal_multiple(control_freq, kv)
-
-/obj/machinery/bot/mulebot/emp_act(severity)
- if (cell)
- cell.emp_act(severity)
- if(load)
- load.emp_act(severity)
- ..()
-
-
-/obj/machinery/bot/mulebot/explode()
- src.visible_message("[src] blows apart!", 1)
- var/turf/Tsec = get_turf(src)
-
- new /obj/item/device/assembly/prox_sensor(Tsec)
- PoolOrNew(/obj/item/stack/rods, Tsec)
- PoolOrNew(/obj/item/stack/rods, Tsec)
- new /obj/item/stack/cable_coil/cut(Tsec)
- if (cell)
- cell.loc = Tsec
- cell.update_icon()
- cell = null
-
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
-
- new /obj/effect/decal/cleanable/blood/oil(src.loc)
- unload(0)
- qdel(src)
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index f583b620a4..c605ed3644 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -103,13 +103,6 @@
bumpopen(M)
return
- if(istype(AM, /obj/machinery/bot))
- var/obj/machinery/bot/bot = AM
- if(src.check_access(bot.botcard))
- if(density)
- open()
- return
-
if(istype(AM, /mob/living/bot))
var/mob/living/bot/bot = AM
if(src.check_access(bot.botcard))
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 6b423f1309..0d304a1e07 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -420,8 +420,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
cartdata["radio"] = 1
if(istype(cartridge.radio, /obj/item/radio/integrated/signal))
cartdata["radio"] = 2
- if(istype(cartridge.radio, /obj/item/radio/integrated/mule))
- cartdata["radio"] = 3
+ //if(istype(cartridge.radio, /obj/item/radio/integrated/mule))
+ // cartdata["radio"] = 3
if(mode == 2)
cartdata["charges"] = cartridge.charges ? cartridge.charges : 0
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 2c91285e08..24a2db67d7 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -124,10 +124,6 @@
icon_state = "cart-q"
access_quartermaster = 1
-/obj/item/weapon/cartridge/quartermaster/initialize()
- radio = new /obj/item/radio/integrated/mule(src)
- ..()
-
/obj/item/weapon/cartridge/head
name = "\improper Easy-Record DELUXE"
icon_state = "cart-h"
@@ -141,9 +137,6 @@
access_janitor = 1
access_security = 1
-/obj/item/weapon/cartridge/hop/initialize()
- radio = new /obj/item/radio/integrated/mule(src)
-
/obj/item/weapon/cartridge/hos
name = "\improper R.O.B.U.S.T. DELUXE"
icon_state = "cart-hos"
@@ -351,40 +344,26 @@
/* MULEBOT Control (Mode: 48) */
if(mode==48)
- var/muleData[0]
var/mulebotsData[0]
- if(istype(radio,/obj/item/radio/integrated/mule))
- var/obj/item/radio/integrated/mule/QC = radio
- muleData["active"] = QC.active
- if(QC.active && !isnull(QC.botstatus))
- var/area/loca = QC.botstatus["loca"]
- var/loca_name = sanitize(loca.name)
- muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"]))
+ var/count = 0
- else
- muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null)
+ for(var/mob/living/bot/mulebot/M in living_mob_list)
+ if(!M.on)
+ continue
+ ++count
+ var/muleData[0]
+ muleData["name"] = M.suffix
+ muleData["location"] = get_area(M)
+ muleData["mode"] = M.mode
+ muleData["home"] = M.homeName
+ muleData["target"] = M.targetName
+ muleData["ref"] = "\ref[M]"
+ muleData["load"] = M.load ? M.load.name : "Nothing"
+
+ mulebotsData[++mulebotsData.len] = muleData.Copy()
-
- var/mulebotsCount=0
- for(var/obj/machinery/bot/B in QC.botlist)
- mulebotsCount++
- if(B.loc)
- mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
-
- if(!mulebotsData.len)
- mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
-
- muleData["bots"] = mulebotsData
- muleData["count"] = mulebotsCount
-
- else
- muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null)
- muleData["active"] = 0
- mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
- muleData["bots"] = mulebotsData
- muleData["count"] = 0
-
- values["mulebot"] = muleData
+ values["mulebotcount"] = count
+ values["mulebots"] = mulebotsData
@@ -575,5 +554,9 @@
loc:mode = 43
mode = 43
+ if("MULEbot")
+ var/mob/living/bot/mulebot/M = locate(href_list["ref"])
+ if(istype(M))
+ M.obeyCommand(href_list["command"])
return 1
diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm
index 7ad2b00200..5e7d63e1e9 100644
--- a/code/game/objects/items/devices/PDA/radio.dm
+++ b/code/game/objects/items/devices/PDA/radio.dm
@@ -105,107 +105,6 @@
radio_controller.remove_object(src, control_freq)
..()
-/obj/item/radio/integrated/mule
- var/list/botlist = null // list of bots
- var/obj/machinery/bot/mulebot/active // the active bot; if null, show bot list
- var/list/botstatus // the status signal sent by the bot
- var/list/beacons
-
- var/beacon_freq = 1400
- var/control_freq = BOT_FREQ
-
- // create a new QM cartridge, and register to receive bot control & beacon message
- New()
- ..()
- spawn(5)
- if(radio_controller)
- radio_controller.add_object(src, control_freq, filter = RADIO_MULEBOT)
- radio_controller.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
- spawn(10)
- post_signal(beacon_freq, "findbeacon", "delivery", s_filter = RADIO_NAVBEACONS)
-
- // receive radio signals
- // can detect bot status signals
- // and beacon locations
- // create/populate lists as they are recvd
-
- receive_signal(datum/signal/signal)
-// var/obj/item/device/pda/P = src.loc
-
- /*
- world << "recvd:[P] : [signal.source]"
- for(var/d in signal.data)
- world << "- [d] = [signal.data[d]]"
- */
- if(signal.data["type"] == "mulebot")
- if(!botlist)
- botlist = new()
-
- if(!(signal.source in botlist))
- botlist += signal.source
-
- if(active == signal.source)
- var/list/b = signal.data
- botstatus = b.Copy()
-
- else if(signal.data["beacon"])
- if(!beacons)
- beacons = new()
-
- beacons[signal.data["beacon"] ] = signal.source
-
-
-// if(istype(P)) P.updateSelfDialog()
-
- Topic(href, href_list)
- ..()
- var/cmd = "command"
- if(active) cmd = "command [active.suffix]"
-
- switch(href_list["op"])
-
- if("control")
- active = locate(href_list["bot"])
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
-
- if("scanbots") // find all bots
- botlist = null
- post_signal(control_freq, "command", "bot_status", s_filter = RADIO_MULEBOT)
-
- if("botlist")
- active = null
-
-
- if("unload")
- post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
- if("setdest")
- if(beacons)
- var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons
- if(dest)
- post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
-
- if("retoff")
- post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
- if("reton")
- post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
-
- if("pickoff")
- post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
- if("pickon")
- post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
-
- if("stop", "go", "home")
- post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
- post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
-
-
-
/*
* Radio Cartridge, essentially a signaler.
*/
diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm
index 17204e77c8..b9c9a1b797 100644
--- a/code/game/objects/structures/crates_lockers/largecrate.dm
+++ b/code/game/objects/structures/crates_lockers/largecrate.dm
@@ -51,6 +51,10 @@
for(var/i = 1;i<=held_count;i++)
new held_type(src)
+/obj/structure/largecrate/animal/mulebot
+ name = "Mulebot crate"
+ held_type = /mob/living/bot/mulebot
+
/obj/structure/largecrate/animal/corgi
name = "corgi carrier"
held_type = /mob/living/simple_animal/corgi
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index e98d59528f..cc91ee49a2 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -49,6 +49,7 @@ var/list/mechtoys = list(
layer = 4
explosion_resistance = 5
var/list/mobs_can_pass = list(
+ /mob/living/bot,
/mob/living/carbon/slime,
/mob/living/simple_animal/mouse,
/mob/living/silicon/robot/drone
diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm
index 7db20fe1ce..88f04e1924 100644
--- a/code/modules/blob/blob.dm
+++ b/code/modules/blob/blob.dm
@@ -90,10 +90,6 @@
if(V)
V.ex_act(2)
return
- var/obj/machinery/bot/B = locate() in T
- if(B)
- B.ex_act(2)
- return
var/obj/mecha/M = locate() in T
if(M)
M.visible_message("The blob attacks \the [M]!")
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index cf6318638f..f8334dacb0 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -86,12 +86,6 @@
"admin","ponies","heresy","meow","Pun Pun","monkey","Ian","moron","pizza","message","spam",\
"director", "Hello", "Hi!"," ","nuke","crate","dwarf","xeno")
-/datum/event/ionstorm/tick()
- if(botEmagChance)
- for(var/obj/machinery/bot/bot in world)
- if(prob(botEmagChance))
- bot.emag_act(1)
-
/datum/event/ionstorm/end()
spawn(rand(5000,8000))
if(prob(50))
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index 4505c666fd..cd2dbb8642 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -29,6 +29,8 @@
access_scanner.req_access = req_access.Copy()
access_scanner.req_one_access = req_one_access.Copy()
+ turn_on()
+
/mob/living/bot/Life()
..()
if(health <= 0)
@@ -125,3 +127,70 @@
/mob/living/bot/attack_throat()
return
+
+/******************************************************************/
+// Navigation procs
+// Used for A-star pathfinding
+
+
+// Returns the surrounding cardinal turfs with open links
+// Including through doors openable with the ID
+/turf/proc/CardinalTurfsWithAccess(var/obj/item/weapon/card/id/ID)
+ var/L[] = new()
+
+ // for(var/turf/simulated/t in oview(src,1))
+
+ for(var/d in cardinal)
+ var/turf/simulated/T = get_step(src, d)
+ if(istype(T) && !T.density)
+ if(!LinkBlockedWithAccess(src, T, ID))
+ L.Add(T)
+ return L
+
+
+// Returns true if a link between A and B is blocked
+// Movement through doors allowed if ID has access
+/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/weapon/card/id/ID)
+
+ if(A == null || B == null) return 1
+ var/adir = get_dir(A,B)
+ var/rdir = get_dir(B,A)
+ if((adir & (NORTH|SOUTH)) && (adir & (EAST|WEST))) // diagonal
+ var/iStep = get_step(A,adir&(NORTH|SOUTH))
+ if(!LinkBlockedWithAccess(A,iStep, ID) && !LinkBlockedWithAccess(iStep,B,ID))
+ return 0
+
+ var/pStep = get_step(A,adir&(EAST|WEST))
+ if(!LinkBlockedWithAccess(A,pStep,ID) && !LinkBlockedWithAccess(pStep,B,ID))
+ return 0
+ return 1
+
+ if(DirBlockedWithAccess(A,adir, ID))
+ return 1
+
+ if(DirBlockedWithAccess(B,rdir, ID))
+ return 1
+
+ for(var/obj/O in B)
+ if(O.density && !istype(O, /obj/machinery/door) && !(O.flags & ON_BORDER))
+ return 1
+
+ return 0
+
+// Returns true if direction is blocked from loc
+// Checks doors against access with given ID
+/proc/DirBlockedWithAccess(turf/loc,var/dir,var/obj/item/weapon/card/id/ID)
+ for(var/obj/structure/window/D in loc)
+ if(!D.density) continue
+ if(D.dir == SOUTHWEST) return 1
+ if(D.dir == dir) return 1
+
+ for(var/obj/machinery/door/D in loc)
+ if(!D.density) continue
+ if(istype(D, /obj/machinery/door/window))
+ if( dir & D.dir ) return !D.check_access(ID)
+
+ //if((dir & SOUTH) && (D.dir & (EAST|WEST))) return !D.check_access(ID)
+ //if((dir & EAST ) && (D.dir & (NORTH|SOUTH))) return !D.check_access(ID)
+ else return !D.check_access(ID) // it's a real, air blocking door
+ return 0
diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm
new file mode 100644
index 0000000000..29dc665246
--- /dev/null
+++ b/code/modules/mob/living/bot/mulebot.dm
@@ -0,0 +1,431 @@
+#define MULE_IDLE 0
+#define MULE_MOVING 1
+#define MULE_UNLOAD 2
+#define MULE_LOST 3
+#define MULE_CALC_MIN 4
+#define MULE_CALC_MAX 10
+#define MULE_PATH_DONE 11
+// IF YOU CHANGE THOSE, UPDATE THEM IN pda.tmpl TOO
+
+/mob/living/bot/mulebot
+ name = "Mulebot"
+ desc = "A Multiple Utility Load Effector bot."
+ icon_state = "mulebot0"
+ anchored = 1
+ density = 1
+ health = 150
+ maxHealth = 150
+ mob_bump_flag = HEAVY
+
+ botcard_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
+
+ var/busy = 0
+ var/mode = MULE_IDLE
+ var/atom/movable/load
+
+ var/crates_only = 1
+ var/auto_return = 1
+ var/safety = 1
+
+ var/list/path = list()
+ var/frustration = 0
+ var/turf/target
+ var/targetName
+ var/turf/home
+ var/homeName
+ var/turf/obstacle
+
+ var/global/amount = 0
+
+/mob/living/bot/mulebot/New()
+ ..()
+
+ var/turf/T = get_turf(loc)
+ var/obj/machinery/navbeacon/N = locate() in home
+ if(N)
+ home = T
+ homeName = N.location
+ else
+ homeName = "Unset"
+
+ suffix = num2text(++amount) // Starts from 1
+
+ name = "Mulebot #[suffix]"
+
+/mob/living/bot/mulebot/MouseDrop_T(var/atom/movable/C, var/mob/user)
+ if(user.stat)
+ return
+
+ if(!istype(C) || C.anchored || get_dist(user, src) > 1 || get_dist(src, C) > 1 )
+ return
+
+ load(C)
+
+/mob/living/bot/mulebot/attack_hand(var/mob/user)
+ interact(user)
+
+/mob/living/bot/mulebot/proc/interact(var/mob/user)
+ var/dat
+ dat += "Multiple Utility Load Effector Mk. III
"
+ dat += "ID: [suffix]
"
+ dat += "Power: [on ? "On" : "Off"]
"
+
+ if(!open)
+ dat += "Status: "
+ switch(mode)
+ if(MULE_IDLE)
+ dat += "Ready"
+ if(MULE_MOVING, MULE_UNLOAD, MULE_PATH_DONE)
+ dat += "Navigating"
+ if(MULE_UNLOAD)
+ dat += "Unloading"
+ if(MULE_LOST)
+ dat += "Processing commands"
+ if(MULE_CALC_MIN to MULE_CALC_MAX)
+ dat += "Calculating navigation path"
+
+ dat += "
Current Load: [load ? load.name : "none"]
"
+
+ if(locked)
+ dat += "
Controls are locked"
+ else
+ dat += "
Controls are unlocked
"
+
+ if(!locked || issilicon(user))
+ dat += "Toggle power
"
+ dat += "Stop
"
+ dat += "Proceed
"
+ dat += "Return to home
"
+ dat += "Set destination
"
+ dat += "Set home
"
+ dat += "Toggle auto return home ([auto_return ? "On" : "Off"])
"
+ dat += "Toggle non-standard cargo ([crates_only ? "Off" : "On"])
"
+
+ if(load)
+ dat += "Unload now
"
+ dat += "
The maintenance hatch is closed.
"
+
+ else
+ if(!issilicon(user))
+ dat += "The maintenance hatch is open.
"
+
+ dat += "Toggle safety ([safety ? "On" : "Off - DANGER"])
"
+ else
+ dat += "The bot is in maintenance mode and cannot be controlled.
"
+
+ user << browse("Mulebot [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500")
+ onclose(user, "mulebot")
+ return
+
+/mob/living/bot/mulebot/Topic(href, href_list)
+ if(..())
+ return
+ usr.set_machine(src)
+ add_fingerprint(usr)
+ switch(href_list["op"])
+ if("power")
+ if(on)
+ turn_off()
+ else
+ turn_on()
+ visible_message("[usr] switches [on ? "on" : "off"] [src].")
+
+ if("stop")
+ obeyCommand("Stop")
+
+ if("go")
+ obeyCommand("GoTD")
+
+ if("home")
+ obeyCommand("Home")
+
+ if("destination")
+ obeyCommand("SetD")
+
+ if("sethome")
+ var/new_dest
+ var/list/beaconlist = new()
+ for(var/obj/machinery/navbeacon/N in navbeacons)
+ beaconlist.Add(N.location)
+ beaconlist[N.location] = N
+ if(beaconlist.len)
+ new_dest = input("Select new home tag", "Mulebot [suffix ? "([suffix])" : ""]", null) in null|beaconlist
+ else
+ alert("No destination beacons available.")
+ if(new_dest)
+ home = get_turf(beaconlist[new_dest])
+ homeName = new_dest
+
+ if("unload")
+ unload()
+
+ if("autoret")
+ auto_return = !auto_return
+
+ if("cargotypes")
+ crates_only = !crates_only
+
+ if("safety")
+ safety = !safety
+
+ interact(usr)
+
+/mob/living/bot/mulebot/attackby(var/obj/item/O, var/mob/user)
+ ..()
+ update_icons()
+
+/mob/living/bot/mulebot/proc/obeyCommand(var/command)
+ switch(command)
+ if("Home")
+ mode = MULE_IDLE
+ target = home
+ targetName = "Home"
+ mode = MULE_LOST
+ if("SetD")
+ var/new_dest
+ var/list/beaconlist = new()
+ for(var/obj/machinery/navbeacon/N in navbeacons)
+ beaconlist.Add(N.location)
+ beaconlist[N.location] = N
+ if(beaconlist.len)
+ new_dest = input("Select new destination tag", "Mulebot [suffix ? "([suffix])" : ""]") in null|beaconlist
+ else
+ alert("No destination beacons available.")
+ if(new_dest)
+ target = get_turf(beaconlist[new_dest])
+ targetName = new_dest
+ if("GoTD")
+ if(mode == MULE_IDLE)
+ mode = MULE_LOST
+ if("Stop")
+ mode = MULE_IDLE
+
+/mob/living/bot/mulebot/emag_act(var/remaining_charges, var/user)
+ locked = !locked
+ user << "You [locked ? "lock" : "unlock"] the mulebot's controls!"
+ flick("mulebot-emagged", src)
+ playsound(loc, 'sound/effects/sparks1.ogg', 100, 0)
+ return 1
+
+/mob/living/bot/mulebot/update_icons()
+ if(open)
+ icon_state = "mulebot-hatch"
+ return
+ if(mode == MULE_MOVING || mode == MULE_UNLOAD)
+ icon_state = "mulebot1"
+ return
+ icon_state = "mulebot0"
+
+/mob/living/bot/mulebot/Life()
+ ..()
+
+ if(busy)
+ return
+
+ if(!safety && prob(1))
+ flick("mulebot-emagged", src)
+
+ switch(mode)
+ if(MULE_IDLE) // Idle
+ return
+ if(MULE_MOVING) // Moving to target
+ if(!target) // Return home
+ if(auto_return && home)
+ target = home
+ targetName = "Home"
+ mode = MULE_LOST
+ else
+ mode = MULE_IDLE
+ update_icons()
+ return
+ if(loc == target) // Unload or stop
+ custom_emote(2, "makes a chiming sound.")
+ playsound(loc, 'sound/machines/chime.ogg', 50, 0)
+ mode = MULE_UNLOAD
+ update_icons()
+ return
+ if(path.len) // Move
+ var/turf/next = path[1]
+ if(next == loc)
+ path -= next
+ return
+
+ var/moved = step_towards(src, next)
+ if(moved)
+ frustration = 0
+ path -= next
+ else if(frustration < 6)
+ if(frustration == 3)
+ custom_emote(2, "makes an annoyed buzzing sound")
+ playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
+ ++frustration
+ else
+ custom_emote(2, "makes a sighing buzz.")
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ obstacle = next
+
+ mode = MULE_LOST
+ else
+ mode = MULE_LOST
+ update_icons()
+ return
+ if(MULE_UNLOAD)
+ unload(dir)
+
+ if(auto_return && home && (loc != home))
+ target = home
+ targetName = "Home"
+ mode = MULE_LOST
+ else
+ mode = MULE_IDLE
+ update_icons()
+ return
+ if(MULE_LOST) // Lost my way
+ if(target)
+ spawn(0)
+ calc_path(obstacle)
+ mode = MULE_CALC_MIN
+ else
+ mode = MULE_IDLE
+ update_icons()
+ return
+ if(MULE_CALC_MIN to MULE_CALC_MAX) // Calcing path
+ if(path.len)
+ mode = MULE_PATH_DONE
+ update_icons()
+ else
+ ++mode
+ return
+ if(MULE_PATH_DONE) // Done with path
+ obstacle = null
+ if(path.len)
+ frustration = 0
+ mode = MULE_MOVING
+ else
+ if(home)
+ target = home
+ targetName = "Home"
+ mode = MULE_LOST
+ else
+ mode = MULE_IDLE
+ update_icons()
+
+/mob/living/bot/mulebot/Bump(var/mob/living/M)
+ if(!safety && istype(M))
+ visible_message("[src] knocks over [M]!")
+ M.Stun(8)
+ M.Weaken(5)
+ ..()
+
+/mob/living/bot/mulebot/proc/runOver(var/mob/living/carbon/human/H)
+ if(istype(H)) // No safety checks - WILL run over lying humans. Stop ERPing in the maint!
+ visible_message("[src] drives over [H]!")
+ playsound(loc, 'sound/effects/splat.ogg', 50, 1)
+
+ var/damage = rand(5, 7)
+ H.apply_damage(2 * damage, BRUTE, BP_HEAD)
+ H.apply_damage(2 * damage, BRUTE, BP_TORSO)
+ H.apply_damage(0.5 * damage, BRUTE, BP_L_LEG)
+ H.apply_damage(0.5 * damage, BRUTE, BP_R_LEG)
+ H.apply_damage(0.5 * damage, BRUTE, BP_L_ARM)
+ H.apply_damage(0.5 * damage, BRUTE, BP_R_ARM)
+
+ blood_splatter(src, H, 1)
+ ..()
+
+/mob/living/bot/mulebot/relaymove(var/mob/user, var/direction)
+ if(load == user)
+ unload(direction)
+
+/mob/living/bot/mulebot/explode()
+ unload(pick(0, 1, 2, 4, 8))
+
+ visible_message("[src] blows apart!")
+
+ var/turf/Tsec = get_turf(src)
+ new /obj/item/device/assembly/prox_sensor(Tsec)
+ PoolOrNew(/obj/item/stack/rods, Tsec)
+ PoolOrNew(/obj/item/stack/rods, Tsec)
+ new /obj/item/stack/cable_coil/cut(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)
+ ..()
+
+/mob/living/bot/mulebot/proc/calc_path(var/turf/avoid = null)
+ path = AStar(loc, target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 250, id = botcard, exclude = avoid)
+ if(!path)
+ path = list()
+
+/mob/living/bot/mulebot/proc/load(var/atom/movable/C)
+ if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc))
+ return
+
+ for(var/obj/structure/plasticflaps/P in src.loc)//Takes flaps into account
+ if(!CanPass(C,P))
+ return
+
+ if(crates_only && !istype(C,/obj/structure/closet/crate))
+ custom_emote(2, "makes a sighing buzz.")
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ return
+
+ var/obj/structure/closet/crate/crate = C
+ if(istype(crate))
+ crate.close()
+
+ //I'm sure someone will come along and ask why this is here... well people were dragging screen items onto the mule, and that was not cool.
+ //So this is a simple fix that only allows a selection of item types to be considered. Further narrowing-down is below.
+ //if(!istype(C,/obj/item) && !istype(C,/obj/machinery) && !istype(C,/obj/structure) && !ismob(C))
+ // return
+ busy = 1
+
+ C.loc = loc
+ sleep(2)
+ if(C.loc != loc) //To prevent you from going onto more than one bot.
+ return
+ C.loc = src
+ load = C
+
+ C.pixel_y += 9
+ if(C.layer < layer)
+ C.layer = layer + 0.1
+ overlays += C
+
+ busy = 0
+
+/mob/living/bot/mulebot/proc/unload(var/dirn = 0)
+ if(!load || busy)
+ return
+
+ busy = 1
+ overlays.Cut()
+
+ load.loc = loc
+ load.pixel_y -= 9
+ load.layer = initial(load.layer)
+
+ if(dirn)
+ step(load, dirn)
+
+ load = null
+
+ for(var/atom/movable/AM in src)
+ if(AM == botcard || AM == access_scanner)
+ continue
+
+ AM.loc = loc
+ AM.layer = initial(AM.layer)
+ AM.pixel_y = initial(AM.pixel_y)
+ busy = 0
+
+#undef MULE_IDLE
+#undef MULE_MOVING
+#undef MULE_UNLOAD
+#undef MULE_LOST
+#undef MULE_CALC_MIN
+#undef MULE_CALC_MAX
+#undef MULE_PATH_DONE
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index f77be45d56..b4d2289f69 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -235,9 +235,9 @@
// called when something steps onto a human
// this handles mulebots and vehicles
/mob/living/carbon/human/Crossed(var/atom/movable/AM)
- if(istype(AM, /obj/machinery/bot/mulebot))
- var/obj/machinery/bot/mulebot/MB = AM
- MB.RunOver(src)
+ if(istype(AM, /mob/living/bot/mulebot))
+ var/mob/living/bot/mulebot/MB = AM
+ MB.runOver(src)
if(istype(AM, /obj/vehicle))
var/obj/vehicle/V = AM
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index e80c1becff..33fb8acd24 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -50,13 +50,6 @@
stance = HOSTILE_STANCE_ATTACK
T = M
break
-
- if(istype(A, /obj/machinery/bot))
- var/obj/machinery/bot/B = A
- if (B.health > 0)
- stance = HOSTILE_STANCE_ATTACK
- T = B
- break
return T
@@ -101,9 +94,6 @@
var/obj/mecha/M = target_mob
M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return M
- if(istype(target_mob,/obj/machinery/bot))
- var/obj/machinery/bot/B = target_mob
- B.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
/mob/living/simple_animal/hostile/proc/LoseTarget()
stance = HOSTILE_STANCE_IDLE
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index a66f6b772c..06daf72260 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -359,10 +359,6 @@
var/obj/mecha/M = target_mob
if (M.occupant)
return (0)
- if (istype(target_mob,/obj/machinery/bot))
- var/obj/machinery/bot/B = target_mob
- if(B.health > 0)
- return (0)
return 1
/mob/living/simple_animal/say(var/message)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 7a66deb3c4..e3ab63bdfe 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -507,17 +507,6 @@
namecounts[name] = 1
creatures[name] = O
- if(istype(O, /obj/machinery/bot))
- var/name = "BOT: [O.name]"
- if (names.Find(name))
- namecounts[name]++
- name = "[name] ([namecounts[name]])"
- else
- names.Add(name)
- namecounts[name] = 1
- creatures[name] = O
-
-
for(var/mob/M in sortAtom(mob_list))
var/name = M.name
if (names.Find(name))
diff --git a/maps/polaris-1.dmm b/maps/polaris-1.dmm
index 692f067fae..be0624cd23 100644
--- a/maps/polaris-1.dmm
+++ b/maps/polaris-1.dmm
@@ -6544,8 +6544,8 @@
"cvS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/quartermaster/storage)
"cvT" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/quartermaster/storage)
"cvU" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=8"; freq = 1400; location = "QM #3"},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/quartermaster/storage)
-"cvV" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=8"; freq = 1400; location = "QM #2"},/obj/machinery/bot/mulebot{home_destination = "QM #2"; suffix = "#2"},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/quartermaster/storage)
-"cvW" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=8"; freq = 1400; location = "QM #1"},/obj/machinery/bot/mulebot{beacon_freq = 1400; home_destination = "QM #1"; suffix = "#1"},/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/quartermaster/storage)
+"cvV" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=8"; freq = 1400; location = "QM #2"},/mob/living/bot/mulebot,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/quartermaster/storage)
+"cvW" = (/obj/machinery/navbeacon{codes_txt = "delivery;dir=8"; freq = 1400; location = "QM #1"},/mob/living/bot/mulebot,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/quartermaster/storage)
"cvX" = (/obj/machinery/status_display/supply_display,/turf/simulated/wall,/area/quartermaster/qm)
"cvY" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/turf/simulated/floor/tiled,/area/quartermaster/qm)
"cvZ" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/quartermaster/qm)
@@ -9608,7 +9608,7 @@
"dCO" = (/obj/structure/bed/chair/wood{dir = 8},/obj/effect/floor_decal/corner/green{dir = 10},/turf/simulated/floor/tiled,/area/hydroponics/garden)
"dCP" = (/obj/structure/table/woodentable,/obj/effect/floor_decal/corner/green{dir = 10},/turf/simulated/floor/tiled,/area/hydroponics/garden)
"dCQ" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/obj/machinery/door/firedoor/border_only,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/plating,/area/hallway/primary/central_three)
-
+
(1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl
index 37ac74f7e0..756f6edce0 100644
--- a/nano/templates/pda.tmpl
+++ b/nano/templates/pda.tmpl
@@ -128,7 +128,7 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm
{{:helper.link('Supply Records', 'gear', {'choice' : "47"}, null, 'fixedLeftWide')}}
- {{if data.cartridge.radio == 3}} {{:helper.link('Delivery Bot Control', 'gear', {'choice' : "48"}, null, 'fixedLeftWide')}} {{/if}}
+ {{:helper.link('Delivery Bot Control', 'gear', {'choice' : "48"}, null, 'fixedLeftWide')}}
@@ -762,128 +762,38 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm
{{else data.mode == 48}}
- Mule Control
- {{if data.records.mulebot.active == null || data.records.mulebot.active == 0}}
- {{if data.records.mulebot.count == 0}}
- No bots found.
- {{else}}
- Mule List
-
- Select A Mulebot
-
-
- {{for data.records.mulebot.bots}}
-
- {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, null)}} (Location: {{:value.Location}})
-
- {{/for}}
- {{/if}}
-
- {{:helper.link('Scan for Bots','gear', {'radiomenu' : "1", 'op' : "scanbots"}, null, null)}}
- {{else}}
- {{if data.records.mulebot.botstatus.mode == -1}}
- Waiting for response...
- {{else}}
- Status:
-
-
-
- Location:
-
-
- {{:data.records.mulebot.botstatus.loca}}
-
-
-
-
- Mode:
-
-
-
- {{if data.records.mulebot.botstatus.mode ==0}}
- Ready
- {{else data.records.mulebot.botstatus.mode == 1}}
- Loading/Unloading
- {{else data.records.mulebot.botstatus.mode ==2}}
- Navigating to Delivery Location
- {{else data.records.mulebot.botstatus.mode == 3}}
- Navigating to Home
- {{else data.records.mulebot.botstatus.mode ==4}}
- Waiting for Clear Path
- {{else data.records.mulebot.botstatus.mode ==5 || data.records.mulebot.botstatus.mode == 6}}
- Calculating navigation Path
- {{else data.records.mulebot.botstatus.mode ==7}}
- Unable to locate destination
- {{/if}}
-
-
-
-
-
- Current Load:
-
-
-
- {{:helper.link(data.records.mulebot.botstatus.load == null ? 'None (Unload)' : data.records.mulebot.botstatus.load + ' (Unload)', 'gear', {'radiomenu' : "1", 'op' : "unload"},data.records.mulebot.botstatus.load == null ? 'disabled' : null, null)}}
-
-
-
-
-
- Power:
-
-
-
- {{:data.records.mulebot.botstatus.powr}}%
-
-
-
-
-
- Destination:
-
-
- {{:helper.link(data.records.mulebot.botstatus.dest == null || data.records.mulebot.botstatus.dest == "" ? 'None (Set)': data.records.mulebot.botstatus.dest+ ' (Set)', 'gear', {'radiomenu' : "1", 'op' : "setdest"}, null, null)}}
-
-
-
-
- Home:
-
-
- {{if data.records.mulebot.botstatus.home == null}} None {{else}} {{:data.records.mulebot.botstatus.home}} {{/if}}
-
-
-
-
- Auto Return:
-
-
- {{:helper.link(data.records.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : data.records.mulebot.botstatus.retn==1 ? "retoff" : "reton"}, null, null)}}
-
-
-
-
- Auto Pickup:
-
-
- {{:helper.link(data.records.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : data.records.mulebot.botstatus.pick==1 ? "pickoff" : "pickon"}, null, null)}}
-
-
-
-
- Functions:
-
-
- {{:helper.link('Stop', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, null)}}
- {{:helper.link('Proceed', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, null)}}
- {{:helper.link('Return Home', 'gear', {'radiomenu' : "1", 'op' : "home"}, null, null)}}
-
-
-
- {{:helper.link('Return to Bot list', 'gear', {'radiomenu' : "1", 'op' : "botlist"}, null, null)}}
- {{/if}}
- {{/if}}
+ Mule Control
+ {{if data.records.mulebotcount == 0}}
+ No bots found.
+ {{else}}
+ Mule List
+ {{for data.records.mulebots}}
+
+
Mulebot #{{:value.name}}
+
Location: {{:value.location}}
Home: {{:value.home}}
Target: {{:value.target}}
Load: {{:value.load}}
+
+
+
Status:
+
+ {{if value.mode == 0}}
+ Idle
+ {{else value.mode == 1}}
+ Moving
+ {{else value.mode == 2}}
+ Unloading
+ {{else}}
+ Calculating path
+ {{/if}}
+
+
+
+ {{:helper.link('Go home', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "Home"})}}
+ {{:helper.link('Set destination', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "SetD"})}}
+ {{:helper.link('Go', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "GoTD"})}}
+ {{:helper.link('Stop', null, {'cartmenu' : "1", 'choice' : "MULEbot", 'ref' : value.ref, 'command' : "Stop"})}}
+
+ {{/for}}
+ {{/if}}
{{else data.mode == 49}}
diff --git a/polaris.dme b/polaris.dme
index 378700623c..f77cd664f1 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -215,7 +215,6 @@
#include "code\datums\wires\autolathe.dm"
#include "code\datums\wires\camera.dm"
#include "code\datums\wires\explosive.dm"
-#include "code\datums\wires\mulebot.dm"
#include "code\datums\wires\particle_accelerator.dm"
#include "code\datums\wires\radio.dm"
#include "code\datums\wires\robot.dm"
@@ -456,8 +455,6 @@
#include "code\game\machinery\atmoalter\portable_atmospherics.dm"
#include "code\game\machinery\atmoalter\pump.dm"
#include "code\game\machinery\atmoalter\scrubber.dm"
-#include "code\game\machinery\bots\bots.dm"
-#include "code\game\machinery\bots\mulebot.dm"
#include "code\game\machinery\camera\camera.dm"
#include "code\game\machinery\camera\camera_assembly.dm"
#include "code\game\machinery\camera\motion.dm"
@@ -1310,6 +1307,7 @@
#include "code\modules\mob\living\bot\farmbot.dm"
#include "code\modules\mob\living\bot\floorbot.dm"
#include "code\modules\mob\living\bot\medbot.dm"
+#include "code\modules\mob\living\bot\mulebot.dm"
#include "code\modules\mob\living\bot\secbot.dm"
#include "code\modules\mob\living\carbon\breathe.dm"
#include "code\modules\mob\living\carbon\carbon.dm"