diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index a1639cdaf3e..bb94fccc547 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -62,6 +62,8 @@
#define islimb(A) (istype(A, /obj/item/organ/limb))
+#define isbot(A) (istype(A, /mob/living/simple_animal/bot))
+
// ASSEMBLY HELPERS
#define isassembly(O) (istype(O, /obj/item/device/assembly))
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index c28c6670985..9db9065e4c4 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -290,4 +290,16 @@ var/list/bloody_footprints_cache = list()
#define IS_DYNAMIC_LIGHTING(A) ( A.lighting_use_dynamic == DYNAMIC_LIGHTING_IFSTARLIGHT ? config.starlight : A.lighting_use_dynamic )
//subtypesof(), typesof() without the parent path
-#define subtypesof(typepath) ( typesof(typepath) - typepath )
\ No newline at end of file
+#define subtypesof(typepath) ( typesof(typepath) - typepath )
+
+//Bot types
+#define SEC_BOT 1 // Secutritrons (Beepsky) and ED-209s
+#define MULE_BOT 2 // MULEbots
+#define FLOOR_BOT 4 // Floorbots
+#define CLEAN_BOT 8 // Cleanbots
+#define MED_BOT 16 // Medibots
+
+//Sentience types
+#define SENTIENCE_ORGANIC 1
+#define SENTIENCE_ARTIFICIAL 2
+#define SENTIENCE_OTHER 3
\ No newline at end of file
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index d452c21be90..d1fc5d6321f 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/controllers/subsystem/bots.dm b/code/controllers/subsystem/bots.dm
deleted file mode 100644
index 6f71bb62d9b..00000000000
--- a/code/controllers/subsystem/bots.dm
+++ /dev/null
@@ -1,22 +0,0 @@
-var/datum/subsystem/bots/SSbot
-
-/datum/subsystem/bots
- name = "Bots"
- priority = 8
-
- var/list/processing = list()
-
-/datum/subsystem/bots/New()
- NEW_SS_GLOBAL(SSbot)
-
-/datum/subsystem/bots/stat_entry(msg)
- ..("P:[processing.len]")
-
-/datum/subsystem/bots/fire()
- var/seconds = wait * 0.1
- for(var/thing in processing)
- if(thing && !thing:gc_destroyed)
- spawn(-1)
- thing:bot_process(seconds)
- continue
- processing.Remove(thing)
\ No newline at end of file
diff --git a/code/datums/spells/conjure.dm b/code/datums/spells/conjure.dm
index 042243045a6..82320dbc4ca 100644
--- a/code/datums/spells/conjure.dm
+++ b/code/datums/spells/conjure.dm
@@ -3,7 +3,7 @@
desc = "This spell conjures objs of the specified types in range."
var/list/summon_type = list() //determines what exactly will be summoned
- //should be text, like list("/obj/machinery/bot/ed209")
+ //should be text, like list("/mob/living/simple_animal/bot/ed209")
var/summon_lifespan = 0 // 0=permanent, any other time in deciseconds
var/summon_amt = 1 //amount of objects summoned
@@ -50,7 +50,7 @@
name = "Dispense Wizard Justice"
desc = "This spell dispenses wizard justice."
- summon_type = list(/obj/machinery/bot/ed209)
+ summon_type = list(/mob/living/simple_animal/bot/ed209)
summon_amt = 10
range = 3
newVars = list("emagged" = 2, "remote_disabled" = 1,"shoot_sound" = 'sound/weapons/laser.ogg',"projectile" = /obj/item/projectile/beam, "declare_arrests" = 0,"name" = "Wizard's Justicebot")
\ No newline at end of file
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 070261597e1..f469c085965 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -73,10 +73,10 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/emergency/evac
name = "Emergency equipment"
- contains = list(/obj/machinery/bot/floorbot,
- /obj/machinery/bot/floorbot,
- /obj/machinery/bot/medbot,
- /obj/machinery/bot/medbot,
+ contains = list(/mob/living/simple_animal/bot/floorbot,
+ /mob/living/simple_animal/bot/floorbot,
+ /mob/living/simple_animal/bot/medbot,
+ /mob/living/simple_animal/bot/medbot,
/obj/item/weapon/tank/internals/air,
/obj/item/weapon/tank/internals/air,
/obj/item/weapon/tank/internals/air,
@@ -1026,7 +1026,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/misc/mule
name = "MULEbot Crate"
- contains = list(/obj/machinery/bot/mulebot)
+ contains = list(/mob/living/simple_animal/bot/mulebot)
cost = 20
containertype = /obj/structure/largecrate/mule
containername = "\improper MULEbot Crate"
diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm
index 22cae76f697..91efa4e36ba 100644
--- a/code/datums/wires/mulebot.dm
+++ b/code/datums/wires/mulebot.dm
@@ -1,6 +1,6 @@
/datum/wires/mulebot
random = 1
- holder_type = /obj/machinery/bot/mulebot
+ holder_type = /mob/living/simple_animal/bot/mulebot
wire_count = 10
var/const/WIRE_POWER1 = 1 // power connections
@@ -14,7 +14,7 @@ var/const/WIRE_REMOTE_TX = 128 // remote trans status
var/const/WIRE_BEACON_RX = 256 // beacon ping recv
/datum/wires/mulebot/CanUse(mob/living/L)
- var/obj/machinery/bot/mulebot/M = holder
+ var/mob/living/simple_animal/bot/mulebot/M = holder
if(M.open)
return 1
return 0
@@ -22,8 +22,8 @@ var/const/WIRE_BEACON_RX = 256 // beacon ping recv
// So the wires do not open a new window, handle the interaction ourselves.
/datum/wires/mulebot/Interact(mob/living/user)
if(CanUse(user))
- var/obj/machinery/bot/mulebot/M = holder
- M.interact(user)
+ var/mob/living/simple_animal/bot/mulebot/M = holder
+ M.update_controls()
/datum/wires/mulebot/UpdatePulsed(index)
switch(index)
diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm
index 3d8a6667603..16583cbd274 100644
--- a/code/game/asteroid.dm
+++ b/code/game/asteroid.dm
@@ -60,7 +60,7 @@ var/global/max_secret_rooms = 6
if("organharvest")
walltypes = list(/turf/simulated/wall/r_wall=2,/turf/simulated/wall=2,/turf/simulated/mineral/random/high_chance=1)
floortypes = list(/turf/simulated/floor/plasteel,/turf/simulated/floor/engine)
- treasureitems = list(/obj/machinery/bot/medbot/mysterious=1, /obj/item/weapon/circular_saw=1, /obj/structure/closet/critter/cat=2)
+ treasureitems = list(/mob/living/simple_animal/bot/medbot/mysterious=1, /obj/item/weapon/circular_saw=1, /obj/structure/closet/critter/cat=2)
fluffitems = list(/obj/effect/decal/cleanable/blood=5,/obj/item/organ/internal/appendix=2,/obj/structure/closet/crate/freezer=2,
/obj/structure/table/optable=1,/obj/item/weapon/scalpel=1,/obj/item/weapon/storage/firstaid/regular=3,
/obj/item/weapon/tank/internals/anesthetic=1, /obj/item/weapon/surgical_drapes=2, /obj/item/device/mass_spectrometer/adv=1,/obj/item/clothing/glasses/hud/health=1)
diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm
index 14ad0918f91..73ab2b3423c 100644
--- a/code/game/gamemodes/sandbox/h_sandbox.dm
+++ b/code/game/gamemodes/sandbox/h_sandbox.dm
@@ -65,9 +65,9 @@ var/hsboxspawn = 1
"Spawn Water Tank" = "hsbspawn&path=[/obj/structure/reagent_dispensers/watertank]",
"Bots",
- "Spawn Cleanbot" = "hsbspawn&path=[/obj/machinery/bot/cleanbot]",
- "Spawn Floorbot" = "hsbspawn&path=[/obj/machinery/bot/floorbot]",
- "Spawn Medbot" = "hsbspawn&path=[/obj/machinery/bot/medbot]",
+ "Spawn Cleanbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/cleanbot]",
+ "Spawn Floorbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/floorbot]",
+ "Spawn Medbot" = "hsbspawn&path=[/mob/living/simple_animal/bot/medbot]",
"Canisters",
"Spawn O2 Canister" = "hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/oxygen]",
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index 87faab5038f..95c7fb5a85e 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -170,7 +170,7 @@
dat += "Back"
dat += "
Medical Robots:"
var/bdat = null
- for(var/obj/machinery/bot/medbot/M in machines)
+ for(var/mob/living/simple_animal/bot/medbot/M in living_mob_list)
if(M.z != src.z) continue //only find medibots on the same z-level as the computer
var/turf/bl = get_turf(M)
if(bl) //if it can't find a turf for the medibot, then it probably shouldn't be showing up
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 74b817009f0..bf8f66cb6fa 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -52,13 +52,6 @@
bumpopen(M)
return
- if(istype(AM, /obj/machinery/bot))
- var/obj/machinery/bot/bot = AM
- if(src.check_access(bot.botcard) || emergency == 1)
- if(density)
- open()
- return
-
if(istype(AM, /obj/mecha))
var/obj/mecha/mecha = AM
if(density)
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 7d611a644c9..1ca5d29b760 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -40,13 +40,7 @@
if( operating || !src.density )
return
if (!( ismob(AM) ))
- var/obj/machinery/bot/bot = AM
- if(istype(bot))
- if(src.check_access(bot.botcard))
- open_and_close()
- else
- flick("[src.base_state]deny", src)
- else if(istype(AM, /obj/mecha))
+ if(istype(AM, /obj/mecha))
var/obj/mecha/mecha = AM
if(mecha.occupant && src.allowed(mecha.occupant))
open_and_close()
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 31929f6e94f..b1652fda99f 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -448,7 +448,7 @@
if(check_anomalies) //if it's set to check for xenos/simpleanimals
for(var/mob/living/simple_animal/SA in turretview)
- if(!SA.stat && (!SA.has_unlimited_silicon_privilege || !(faction in SA.faction)) ) //don't target dead animals or NT maint drones.
+ if(!SA.stat && (!SA.has_unlimited_silicon_privilege || !(faction in SA.faction))) //don't target dead animals or NT maint drones.
targets += SA
for(var/mob/living/carbon/C in turretview) //loops through all carbon-based lifeforms in view(7)
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 0446dab8815..640da5c5609 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -37,7 +37,7 @@
var/list/stored_data = list()
var/current_channel
- var/obj/machinery/bot/active_bot
+ var/mob/living/simple_animal/bot/active_bot
var/list/botlist = list()
/obj/item/weapon/cartridge/engineering
@@ -549,7 +549,7 @@ Code:
menu += "
Located Cleanbots:
"
ldat = null
- for (var/obj/machinery/bot/cleanbot/B in SSbot.processing)
+ for (var/mob/living/simple_animal/bot/cleanbot/B in living_mob_list)
var/turf/bl = get_turf(B)
if(bl)
@@ -710,7 +710,7 @@ Code:
/obj/item/weapon/cartridge/proc/bot_control()
- var/obj/machinery/bot/Bot
+ var/mob/living/simple_animal/bot/Bot
// if(!SC)
// menu = "Interlink Error - Please reinsert cartridge."
@@ -723,7 +723,7 @@ Code:
//MULEs!
if(active_bot.bot_type == MULE_BOT)
- var/obj/machinery/bot/mulebot/MULE = active_bot
+ var/mob/living/simple_animal/bot/mulebot/MULE = active_bot
var/atom/Load = MULE.load
menu += "
Current Load: [ !Load ? "none" : "[Load.name] (unload)" ]
"
menu += "Destination: [MULE.destination ? MULE.destination : "None"] (set)
"
@@ -750,7 +750,7 @@ Code:
var/turf/current_turf = get_turf(src)
var/zlevel = current_turf.z
var/botcount = 0
- for(Bot in SSbot.processing) //Git da botz
+ for(Bot in living_mob_list) //Git da botz
if(!Bot.on || Bot.z != zlevel || Bot.remote_disabled || !(bot_access_flags & Bot.bot_type)) //Only non-emagged bots on the same Z-level are detected!
continue //Also, the PDA must have access to the bot type.
menu += "[Bot.name] ([Bot.get_mode()])
"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/misc.dm b/code/game/objects/structures/crates_lockers/closets/secure/misc.dm
index 21a126d07db..5ba9f4e5d5b 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/misc.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/misc.dm
@@ -47,7 +47,7 @@
new /obj/item/weapon/storage/firstaid/brute(src)
new /obj/item/weapon/storage/firstaid/regular(src)
new /obj/item/weapon/defibrillator/compact/combat/loaded(src)
- new /obj/machinery/bot/medbot(src)
+ new /mob/living/simple_animal/bot/medbot(src)
/obj/structure/closet/secure_closet/ertEngi
name = "engineer closet"
diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm
index 2a695e236ae..eb15ba1d4c3 100644
--- a/code/game/objects/structures/plasticflaps.dm
+++ b/code/game/objects/structures/plasticflaps.dm
@@ -22,7 +22,9 @@
else if(istype(A, /mob/living)) // You Shall Not Pass!
var/mob/living/M = A
- if(M.buckled && istype(M.buckled, /obj/machinery/bot/mulebot)) // mulebot passenger gets a free pass.
+ if(istype(A,/mob/living/simple_animal/bot/mulebot)) //mulebots can pass
+ return 1
+ if(M.buckled && istype(M.buckled, /mob/living/simple_animal/bot/mulebot)) // mulebot passenger gets a free pass.
return 1
if(!M.lying && !M.ventcrawler && M.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
return 0
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index b52b540cc7b..66809b08614 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -71,7 +71,7 @@
/datum/table_recipe/ed209
name = "ED209"
- result = /obj/machinery/bot/ed209
+ result = /mob/living/simple_animal/bot/ed209
reqs = list(/obj/item/robot_parts/robot_suit = 1,
/obj/item/clothing/head/helmet = 1,
/obj/item/clothing/suit/armor/vest = 1,
@@ -89,7 +89,7 @@
/datum/table_recipe/secbot
name = "Secbot"
- result = /obj/machinery/bot/secbot
+ result = /mob/living/simple_animal/bot/secbot
reqs = list(/obj/item/device/assembly/signaler = 1,
/obj/item/clothing/head/helmet/sec = 1,
/obj/item/weapon/melee/baton = 1,
@@ -101,7 +101,7 @@
/datum/table_recipe/cleanbot
name = "Cleanbot"
- result = /obj/machinery/bot/cleanbot
+ result = /mob/living/simple_animal/bot/cleanbot
reqs = list(/obj/item/weapon/reagent_containers/glass/bucket = 1,
/obj/item/device/assembly/prox_sensor = 1,
/obj/item/robot_parts/r_arm = 1)
@@ -110,7 +110,7 @@
/datum/table_recipe/floorbot
name = "Floorbot"
- result = /obj/machinery/bot/floorbot
+ result = /mob/living/simple_animal/bot/floorbot
reqs = list(/obj/item/weapon/storage/toolbox/mechanical = 1,
/obj/item/stack/tile/plasteel = 1,
/obj/item/device/assembly/prox_sensor = 1,
@@ -120,7 +120,7 @@
/datum/table_recipe/medbot
name = "Medbot"
- result = /obj/machinery/bot/medbot
+ result = /mob/living/simple_animal/bot/medbot
reqs = list(/obj/item/device/healthanalyzer = 1,
/obj/item/weapon/storage/firstaid = 1,
/obj/item/device/assembly/prox_sensor = 1,
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index da1a2c596fd..639bb5cbb1f 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -37,7 +37,7 @@
M << "
"
if(botEmagChance)
- for(var/obj/machinery/bot/bot in machines)
+ for(var/mob/living/simple_animal/bot/bot in living_mob_list)
if(prob(botEmagChance))
bot.Emag()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 549b9f19adc..31dda91368c 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -272,7 +272,7 @@
// called when something steps onto a human
// this could be made more general, but for now just handle mulebot
/mob/living/carbon/human/Crossed(atom/movable/AM)
- var/obj/machinery/bot/mulebot/MB = AM
+ var/mob/living/simple_animal/bot/mulebot/MB = AM
if(istype(MB))
MB.RunOver(src)
@@ -596,7 +596,7 @@
else
return null
-/mob/living/carbon/human/assess_threat(obj/machinery/bot/secbot/judgebot, lasercolor)
+/mob/living/carbon/human/assess_threat(mob/living/simple_animal/bot/secbot/judgebot, lasercolor)
if(judgebot.emagged == 2)
return 10 //Everyone is a criminal!
@@ -858,4 +858,4 @@
return
if(!isturf(M.loc) && M.loc != src)
return
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 27ea1b59382..cf61c41cdab 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -68,7 +68,6 @@
breath_moles = environment.total_moles()*BREATH_PERCENTAGE
breath = loc.remove_air(breath_moles)
-
else //Breathe from loc as obj again
if(istype(loc, /obj/))
var/obj/loc_as_obj = loc
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 68e666e6911..85216f02e9a 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -236,7 +236,7 @@
/mob/living/carbon/monkey/canBeHandcuffed()
return 1
-/mob/living/carbon/monkey/assess_threat(obj/machinery/bot/secbot/judgebot, lasercolor)
+/mob/living/carbon/monkey/assess_threat(mob/living/simple_animal/bot/secbot/judgebot, lasercolor)
if(judgebot.emagged == 2)
return 10 //Everyone is a criminal!
var/threatcount = 0
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 2077fd65399..1bfe79ce37a 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -35,7 +35,7 @@ var/list/ai_list = list()
radiomod = ";" //AIs will, by default, state their laws on the internal radio.
var/obj/item/device/pda/ai/aiPDA = null
var/obj/item/device/multitool/aiMulti = null
- var/obj/machinery/bot/Bot
+ var/mob/living/simple_animal/bot/Bot
var/tracking = 0 //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
@@ -446,14 +446,14 @@ var/list/ai_list = list()
src << "Target is not on or near any active cameras on the station."
return
if(href_list["callbot"]) //Command a bot to move to a selected location.
- Bot = locate(href_list["callbot"]) in SSbot.processing
+ Bot = locate(href_list["callbot"]) in living_mob_list
if(!Bot || Bot.remote_disabled || src.control_disabled)
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
waypoint_mode = 1
src << "Set your waypoint by clicking on a valid location free of obstructions."
return
if(href_list["interface"]) //Remotely connect to a bot!
- Bot = locate(href_list["interface"]) in SSbot.processing
+ Bot = locate(href_list["interface"]) in living_mob_list
if(!Bot || Bot.remote_disabled || src.control_disabled)
return
Bot.attack_ai(src)
@@ -525,7 +525,7 @@ var/list/ai_list = list()
d += "Query network status
"
d += "Name | Status | Location | Control |
"
- for (Bot in SSbot.processing)
+ for (Bot in living_mob_list)
if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
bot_area = get_area(Bot)
d += "| [Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model]) | "
diff --git a/code/game/machinery/bots/bots.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
similarity index 62%
rename from code/game/machinery/bots/bots.dm
rename to code/modules/mob/living/simple_animal/bot/bot.dm
index 55a2444a231..f8b62099442 100644
--- a/code/game/machinery/bots/bots.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -1,17 +1,53 @@
-// AI (i.e. game AI, not the AI player) controlled bots
+#define BOT_STEP_DELAY 4 //Delay between movemements
-/obj/machinery/bot
+#define DEFAULT_SCAN_RANGE 7 //default view range for finding targets.
+
+//Mode defines
+#define BOT_IDLE 0 // idle
+#define BOT_HUNT 1 // found target, hunting
+#define BOT_PREP_ARREST 2 // at target, preparing to arrest
+#define BOT_ARREST 3 // arresting target
+#define BOT_START_PATROL 4 // start patrol
+#define BOT_PATROL 5 // patrolling
+#define BOT_SUMMON 6 // summoned by PDA
+#define BOT_CLEANING 7 // cleaning (cleanbots)
+#define BOT_REPAIRING 8 // repairing hull breaches (floorbots)
+#define BOT_MOVING 9 // for clean/floor/med bots, when moving.
+#define BOT_HEALING 10 // healing people (medbots)
+#define BOT_RESPONDING 11 // responding to a call from the AI
+#define BOT_DELIVER 12 // moving to deliver
+#define BOT_GO_HOME 13 // returning to home
+#define BOT_BLOCKED 14 // blocked
+#define BOT_NAV 15 // computing navigation
+#define BOT_WAIT_FOR_NAV 16 // waiting for nav computation
+#define BOT_NO_ROUTE 17 // no destination beacon found (or no route)
+
+// AI (i.e. game AI, not the AI player) controlled bots
+/mob/living/simple_animal/bot
icon = 'icons/obj/aibots.dmi'
layer = MOB_LAYER
luminosity = 3
- use_power = 0
- var/obj/item/weapon/card/id/botcard // the ID card that the bot "holds"
+ stop_automated_movement = 1
+ wander = 0
+ healable = 0
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ has_unlimited_silicon_privilege = 1
+ sentience_type = SENTIENCE_ARTIFICIAL
+
+ var/obj/machinery/bot_core/bot_core = null
+ var/bot_core_type = /obj/machinery/bot_core
+ var/list/users = list() //for dialog updates
+ var/window_id = "bot_control"
+ var/window_name = "Protobot 1.0" //Popup title
+ var/window_width = 0 //0 for default size
+ var/window_height = 0
+
+ var/list/player_access = list() //Additonal access the bots gets when player controlled
+ var/emagged = 0
var/list/prev_access = list()
var/on = 1
- var/health = 0 //do not forget to set health for your bot!
- var/maxhealth = 0
- var/fire_dam_coeff = 1
- var/brute_dam_coeff = 1
var/open = 0//Maint panel
var/locked = 1
var/hacked = 0 //Used to differentiate between being hacked by silicons and emagged by humans.
@@ -20,18 +56,18 @@
var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset.
var/declare_message = "" //What the bot will display to the HUD user.
var/frustration = 0 //Used by some bots for tracking failures to reach their target.
- var/speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick.
+ var/base_speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick.
var/turf/ai_waypoint //The end point of a bot's path, or the target location.
var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint.
var/pathset = 0
var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore.
- var/mode = 0 //Standardizes the vars that indicate the bot is busy with its function.
+ var/mode = BOT_IDLE //Standardizes the vars that indicate the bot is busy with its function.
var/tries = 0 //Number of times the bot tried and failed to move.
var/remote_disabled = 0 //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras.
var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it.
var/obj/item/device/radio/Radio //The bot's radio, for speaking to people.
- var/radio_frequency //The bot's default radio speaking freqency. Recommended to be on a department frequency.
- //var/emagged = 0 //Urist: Moving that var to the general /bot tree as it's used by most bots
+ var/radio_key = null //which channels can the bot listen to
+ var/radio_channel = "Common" //The bot's default radio channel
var/auto_patrol = 0// set to make bot automatically patrol
var/turf/patrol_target // this is turf to navigate to (location of beacon)
var/turf/summon_target // The turf of a user summoning a bot.
@@ -46,36 +82,8 @@
var/turf/nearest_beacon_loc // the nearest beacon's location
var/beacon_freq = 1445 // navigation beacon frequency
-
var/model = "" //The type of bot it is.
var/bot_type = 0 //The type of bot it is, for radio control.
- #define SEC_BOT 1 // Secutritrons (Beepsky) and ED-209s
- #define MULE_BOT 2 // MULEbots
- #define FLOOR_BOT 4 // Floorbots
- #define CLEAN_BOT 8 // Cleanbots
- #define MED_BOT 16 // Medibots
-
- #define DEFAULT_SCAN_RANGE 7 //default view range for finding targets.
-
- //Mode defines
- #define BOT_IDLE 0 // idle
- #define BOT_HUNT 1 // found target, hunting
- #define BOT_PREP_ARREST 2 // at target, preparing to arrest
- #define BOT_ARREST 3 // arresting target
- #define BOT_START_PATROL 4 // start patrol
- #define BOT_PATROL 5 // patrolling
- #define BOT_SUMMON 6 // summoned by PDA
- #define BOT_CLEANING 7 // cleaning (cleanbots)
- #define BOT_REPAIRING 8 // repairing hull breaches (floorbots)
- #define BOT_MOVING 9 // for clean/floor/med bots, when moving.
- #define BOT_HEALING 10 // healing people (medbots)
- #define BOT_RESPONDING 11 // responding to a call from the AI
- #define BOT_DELIVER 12 // moving to deliver
- #define BOT_GO_HOME 13 // returning to home
- #define BOT_BLOCKED 14 // blocked
- #define BOT_NAV 15 // computing navigation
- #define BOT_WAIT_FOR_NAV 16 // waiting for nav computation
- #define BOT_NO_ROUTE 17 // no destination beacon found (or no route)
var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \
"Beginning Patrol", "Patrolling", "Summoned by PDA", \
"Cleaning", "Repairing", "Proceeding to work site", "Healing", \
@@ -83,48 +91,53 @@
"Waiting for clear path", "Calculating navigation path", "Pinging beacon network", "Unable to reach destination")
//This holds text for what the bot is mode doing, reported on the remote bot control interface.
-/obj/machinery/bot/proc/get_mode()
+/mob/living/simple_animal/bot/proc/get_mode()
if(!mode)
return "Idle"
else
return mode_name[mode]
-/obj/machinery/bot/proc/turn_on()
+/mob/living/simple_animal/bot/proc/turn_on()
if(stat) return 0
on = 1
SetLuminosity(initial(luminosity))
+ update_icon()
return 1
-/obj/machinery/bot/proc/turn_off()
+/mob/living/simple_animal/bot/proc/turn_off()
on = 0
SetLuminosity(0)
bot_reset() //Resets an AI's call, should it exist.
+ update_icon()
-/obj/machinery/bot/New()
+/mob/living/simple_animal/bot/New()
..()
- SSbot.processing += src //Global bot list
- botcard = new /obj/item/weapon/card/id(src)
+ access_card = new /obj/item/weapon/card/id(src)
//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
- botcard.access += access_robotics
+ access_card.access += access_robotics
set_custom_texts()
- Radio = new /obj/item/device/radio(src)
- Radio.listening = 0 //Makes bot radios transmit only so no one hears things while adjacent to one.
+ Radio = new/obj/item/device/radio(src)
+ if(radio_key)
+ Radio.keyslot = new radio_key
+ Radio.canhear_range = 1 // 0 ?
+ Radio.recalculateChannels()
-/obj/machinery/bot/Destroy()
- SSbot.processing -= src
+ bot_core = new bot_core_type(src)
+
+/mob/living/simple_animal/bot/Destroy()
qdel(Radio)
- qdel(botcard)
+ qdel(access_card)
+ qdel(bot_core)
return ..()
+/mob/living/simple_animal/bot/death(gibbed)
+ explode()
+ ..()
-/obj/machinery/bot/proc/explode()
+/mob/living/simple_animal/bot/proc/explode()
qdel(src)
-/obj/machinery/bot/proc/healthcheck()
- if (health <= 0)
- explode()
-
-/obj/machinery/bot/proc/Emag(mob/user) //Master Emag proc. Ensure this is called in your bot before setting unique functions.
+/mob/living/simple_animal/bot/proc/Emag(mob/user) //Master Emag proc. Ensure this is called in your bot before setting unique functions.
if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
locked = 0
emagged = 1
@@ -138,93 +151,30 @@
else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet.
user << "You need to open maintenance panel first!"
-/obj/machinery/bot/examine(mob/user)
+/mob/living/simple_animal/bot/examine(mob/user)
..()
- if (health < maxhealth)
- if (health > maxhealth/3)
+ if (health < maxHealth)
+ if (health > maxHealth/3)
user << "[src]'s parts look loose."
else
user << "[src]'s parts look very loose!"
else
user << "[src] is in pristine condition."
-/obj/machinery/bot/attack_alien(mob/living/carbon/alien/user)
- user.changeNext_move(CLICK_CD_MELEE)
- user.do_attack_animation(src)
- health -= rand(15,30)*brute_dam_coeff
- visible_message("[user] has slashed [src]!")
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- if(prob(10))
+/mob/living/simple_animal/bot/adjustBruteLoss(amount)
+ if(amount>0 && prob(10))
new /obj/effect/decal/cleanable/oil(loc)
- healthcheck()
+ return ..(amount)
-
-/obj/machinery/bot/attack_animal(mob/living/simple_animal/M)
- M.do_attack_animation(src)
- if(M.melee_damage_upper == 0)
- return
- M.changeNext_move(CLICK_CD_MELEE)
- health -= M.melee_damage_upper
- visible_message("[M] has [M.attacktext] [src]!")
- add_logs(M, src, "attacked")
- if(prob(10))
+/mob/living/simple_animal/bot/adjustFireLoss(amount)
+ if(amount>0 && prob(10))
new /obj/effect/decal/cleanable/oil(loc)
- healthcheck()
-
-/obj/machinery/bot/Topic(href, href_list) //Master Topic to handle common functions.
- . = ..()
- if (.)
- return
- if(topic_denied(usr))
- usr << "[src]'s interface is not responding!"
- href_list = list()
- return
-
- usr.set_machine(src)
- add_fingerprint(usr)
- if((href_list["power"]) && (allowed(usr) || !locked))
- if (on)
- turn_off()
- else
- turn_on()
-
- switch(href_list["operation"])
- if("patrol")
- auto_patrol = !auto_patrol
- bot_reset()
- if("remote")
- remote_disabled = !remote_disabled
- if("hack")
- if(emagged != 2)
- emagged = 2
- hacked = 1
- locked = 1
- usr << "[text_hack]"
- bot_reset()
- else if(!hacked)
- usr << "[text_dehack_fail]"
- else
- emagged = 0
- hacked = 0
- usr << "[text_dehack]"
- bot_reset()
- updateUsrDialog()
-
-/obj/machinery/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
- // 0 for access, 1 for denied.
- if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
- if(!hacked) //Manually emagged by a human - access denied to all.
- return 1
- else if(!issilicon(user)) //Bot is hacked, so only silicons are allowed access.
- return 1
- else
- return 0
-
-/obj/machinery/bot/proc/bot_process() //Master process which handles code common across most bots.
+ return ..(amount)
+/mob/living/simple_animal/bot/handle_automated_action() //Master process which handles code common across most bots.
set background = BACKGROUND_ENABLED
- if(!on)
+ if(!on || ckey)
return
switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
@@ -237,17 +187,34 @@
return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early.
-/obj/machinery/bot/attackby(obj/item/weapon/W, mob/user, params)
+/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/M)
+ if(M.a_intent == "help")
+ show_controls(M)
+ else
+ return ..()
+
+/mob/living/simple_animal/bot/attackby(obj/item/weapon/W, mob/user, params)
if(istype(W, /obj/item/weapon/screwdriver))
if(!locked)
open = !open
user << "Maintenance panel is now [open ? "opened" : "closed"]."
else
user << "Maintenance panel is locked."
+ else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
+ if(bot_core.allowed(user) && !open && !emagged)
+ locked = !locked
+ user << "Controls are now [locked ? "locked." : "unlocked."]"
+ else
+ if(emagged)
+ user << "ERROR"
+ if(open)
+ user << "Please close the access panel before locking it."
+ else
+ user << "Access denied."
else
user.changeNext_move(CLICK_CD_MELEE)
if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm")
- if(health >= maxhealth)
+ if(health >= maxHealth)
user << "[src] does not need a repair!"
return
if(!open)
@@ -255,7 +222,7 @@
return
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0, user))
- health = min(maxhealth, health+10)
+ health = min(maxHealth, health+10)
user.visible_message("[user] repairs [src]!","You repair [src].")
else
user << "The welder must be on for this task!"
@@ -263,56 +230,22 @@
if(W.force) //if force is non-zero
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(5, 1, src)
- switch(W.damtype)
- if("fire")
- health -= W.force * fire_dam_coeff
- s.start()
- if("brute")
- health -= W.force * brute_dam_coeff
- s.start()
- ..()
- healthcheck()
+ s.start()
+ ..()
-/obj/machinery/bot/emag_act(mob/user)
+/mob/living/simple_animal/bot/emag_act(mob/user)
if(emagged < 2)
Emag(user)
-/obj/machinery/bot/bullet_act(obj/item/projectile/Proj)
- if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
- health -= Proj.damage
+/mob/living/simple_animal/bot/bullet_act(obj/item/projectile/Proj)
+ if(Proj && (Proj.damage_type == BRUTE || Proj.damage_type == BURN))
if(prob(75) && Proj.damage > 0)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(5, 1, src)
s.start()
- ..()
- healthcheck()
- return 1
- return
+ return ..()
-/obj/machinery/bot/blob_act()
- health -= rand(20,40)*fire_dam_coeff
- healthcheck()
- return
-
-/obj/machinery/bot/ex_act(severity, target)
- switch(severity)
- if(1)
- explode()
- return
- if(2)
- health -= rand(5,10)*fire_dam_coeff
- health -= rand(10,20)*brute_dam_coeff
- healthcheck()
- return
- if(3)
- if (prob(50))
- health -= rand(1,5)*fire_dam_coeff
- health -= rand(1,5)*brute_dam_coeff
- healthcheck()
- return
- return
-
-/obj/machinery/bot/emp_act(severity)
+/mob/living/simple_animal/bot/emp_act(severity)
var/was_on = on
stat |= EMPED
var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( loc )
@@ -331,34 +264,36 @@
if (was_on)
turn_on()
-/obj/machinery/bot/proc/hack(mob/user)
- var/hack
- if(issilicon(user)) //Allows silicons to toggle the emag status of a bot.
- hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
"
- hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
"
- else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control.
- hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]
"
- return hack
-
-/obj/machinery/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally.
+/mob/living/simple_animal/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally.
text_hack = "You hack [name]."
text_dehack = "You reset [name]."
text_dehack_fail = "You fail to reset [name]."
-/obj/machinery/bot/attack_ai(mob/user as mob)
+/mob/living/simple_animal/bot/attack_ai(mob/user as mob)
attack_hand(user)
-/obj/machinery/bot/proc/speak(message, freq) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio.
+/mob/living/simple_animal/bot/proc/speak(message,channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio.
if((!on) || (!message))
return
- if(freq)
- Radio.set_frequency(radio_frequency)
- Radio.talk_into(src, message, radio_frequency)
+ if(channel)
+ if(!Radio.channels[channel]) //Ignore lack of keys
+ Radio.channels[channel] = 1
+ Radio.talk_into(src, message, channel)
+ Radio.channels[channel] = 0
+ else
+ Radio.talk_into(src, message, channel)
else
say(message)
return
- //Generalized behavior code, override where needed!
+/mob/living/simple_animal/bot/say(message)
+ return ..(message, "R")
+
+/mob/living/simple_animal/bot/get_spans()
+ return ..() | SPAN_ROBOT
+
+
+//Generalized behavior code, override where needed!
/*
scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result.
@@ -370,7 +305,7 @@ Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
The proc would return a human next to the bot to be set to the patient var.
Pass the desired type path itself, declaring a temporary var beforehand is not required.
*/
-/obj/machinery/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
+/mob/living/simple_animal/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
var/final_result
for (var/scan in view (scan_range, src) ) //Search for something in range!
if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
@@ -385,11 +320,11 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r
return final_result
//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
-/obj/machinery/bot/proc/process_scan(scan_target)
+/mob/living/simple_animal/bot/proc/process_scan(scan_target)
return scan_target
-/obj/machinery/bot/proc/add_to_ignore(subject)
+/mob/living/simple_animal/bot/proc/add_to_ignore(subject)
if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
ignore_list |= subject
else if (ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
@@ -400,7 +335,7 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r
Movement proc for stepping a bot through a path generated through A-star.
Pass a positive integer as an argument to override a bot's default speed.
*/
-/obj/machinery/bot/proc/bot_move(dest, move_speed)
+/mob/living/simple_animal/bot/proc/bot_move(dest, move_speed)
if(!dest || !path || path.len == 0) //A-star failed or a path/destination was not set.
path = list()
@@ -412,28 +347,26 @@ Pass a positive integer as an argument to override a bot's default speed.
else if (dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop.
path = list()
return 0
- var/success
- var/step_count = move_speed ? move_speed : speed //If a value is passed into move_speed, use that instead of the default speed var.
+ var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var.
+
if(step_count >= 1 && tries < 4)
- for(step_count, step_count >= 1,step_count--)
- success = bot_step(dest)
- if (success)
- tries = 0
- else
- tries++
- break
- sleep(4)
+ for(var/step_number = 0, step_number < step_count,step_number++)
+ spawn(BOT_STEP_DELAY*step_number)
+ bot_step(dest)
else
return 0
return 1
-/obj/machinery/bot/proc/bot_step(dest)
- if(path && path.len > 1)
+/mob/living/simple_animal/bot/proc/bot_step(dest) //Step,increase tries if failed
+ if(!path)
+ return 0
+ if(path.len > 1)
step_towards(src, path[1])
if(get_turf(src) == path[1]) //Successful move
path -= path[1]
else
+ tries++
return 0
else if(path.len == 1)
step_to(src, dest)
@@ -441,11 +374,11 @@ Pass a positive integer as an argument to override a bot's default speed.
return 1
-/obj/machinery/bot/proc/check_bot_access()
+/mob/living/simple_animal/bot/proc/check_bot_access()
if(mode != BOT_SUMMON && mode != BOT_RESPONDING)
- botcard.access = prev_access
+ access_card.access = prev_access
-/obj/machinery/bot/proc/call_bot(caller, turf/waypoint, message=TRUE)
+/mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE)
bot_reset() //Reset a bot before setting it to call mode.
var/area/end_area = get_area(waypoint)
@@ -461,7 +394,7 @@ Pass a positive integer as an argument to override a bot's default speed.
if(path && path.len) //Ensures that a valid path is calculated!
if(!on)
turn_on() //Saves the AI the hassle of having to activate a bot manually.
- botcard = all_access //Give the bot all-access while under the AI's command.
+ access_card = all_access //Give the bot all-access while under the AI's command.
if(message)
calling_ai << "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination."
pathset = 1
@@ -473,7 +406,7 @@ Pass a positive integer as an argument to override a bot's default speed.
calling_ai = null
path = list()
-/obj/machinery/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc.
+/mob/living/simple_animal/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc.
//Handles the bot's movement during a call.
var/success = bot_move(ai_waypoint, 3)
if (!success)
@@ -482,14 +415,14 @@ Pass a positive integer as an argument to override a bot's default speed.
calling_ai = null
bot_reset()
-obj/machinery/bot/proc/bot_reset()
+/mob/living/simple_animal/bot/proc/bot_reset()
if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot.
calling_ai << "Call command to a bot has been reset."
calling_ai = null
path = list()
summon_target = null
pathset = 0
- botcard.access = prev_access
+ access_card.access = prev_access
tries = 0
mode = BOT_IDLE
@@ -501,14 +434,14 @@ obj/machinery/bot/proc/bot_reset()
//Patrol and summon code!
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-/obj/machinery/bot/proc/bot_patrol()
+/mob/living/simple_animal/bot/proc/bot_patrol()
patrol_step()
spawn(5)
if(mode == BOT_PATROL)
patrol_step()
return
-/obj/machinery/bot/proc/start_patrol()
+/mob/living/simple_animal/bot/proc/start_patrol()
if(tries >= 4) //Bot is trapped, so stop trying to patrol.
auto_patrol = 0
@@ -536,7 +469,7 @@ obj/machinery/bot/proc/bot_reset()
// perform a single patrol step
-/obj/machinery/bot/proc/patrol_step()
+/mob/living/simple_animal/bot/proc/patrol_step()
if(loc == patrol_target) // reached target
//Find the next beacon matching the target.
@@ -580,7 +513,7 @@ obj/machinery/bot/proc/bot_reset()
return
// finds the nearest beacon to self
-/obj/machinery/bot/proc/find_patrol_target()
+/mob/living/simple_animal/bot/proc/find_patrol_target()
nearest_beacon = null
new_destination = null
find_nearest_beacon()
@@ -592,7 +525,7 @@ obj/machinery/bot/proc/bot_reset()
mode = BOT_IDLE
speak("Disengaging patrol mode.")
-/obj/machinery/bot/proc/get_next_patrol_target()
+/mob/living/simple_animal/bot/proc/get_next_patrol_target()
// search the beacon list for the next target in the list.
for(var/obj/machinery/navbeacon/NB in navbeacons)
if(NB.location == next_destination) //Does the Beacon location text match the destination?
@@ -601,7 +534,7 @@ obj/machinery/bot/proc/bot_reset()
next_destination = NB.codes["next_patrol"] //Also get the name of the next beacon in line.
return 1
-/obj/machinery/bot/proc/find_nearest_beacon()
+/mob/living/simple_animal/bot/proc/find_nearest_beacon()
for(var/obj/machinery/navbeacon/NB in navbeacons)
var/dist = get_dist(src, NB)
if(nearest_beacon) //Loop though the beacon net to find the true closest beacon.
@@ -619,9 +552,11 @@ obj/machinery/bot/proc/bot_reset()
destination = nearest_beacon
//PDA control. Some bots, especially MULEs, may have more parameters.
-/obj/machinery/bot/proc/bot_control(command, mob/user, turf/user_turf, list/user_access = list())
+/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, turf/user_turf, list/user_access = list())
if(!on || emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
return 1 //ACCESS DENIED
+ if(ckey)
+ bot_control_message(command,user,user_turf,user_access)
// process control input
switch(command)
if("patroloff")
@@ -637,36 +572,54 @@ obj/machinery/bot/proc/bot_reset()
bot_reset()
summon_target = user_turf
if(user_access.len != 0)
- botcard.access = user_access + prev_access //Adds the user's access, if any.
+ access_card.access = user_access + prev_access //Adds the user's access, if any.
mode = BOT_SUMMON
- speak("Responding.", radio_frequency)
+ speak("Responding.", radio_channel)
calc_summon_path()
return
-
-
return
+//
+/mob/living/simple_animal/bot/proc/bot_control_message(command,user,user_turf,user_access)
+ switch(command)
+ if("patroloff")
+ src << "STOP PATROL"
+ if("patrolon")
+ src << "START PATROL"
+ if("summon")
+ var/area/a = get_area(user_turf)
+ src << "PRIORITY ALERT:[user] in [a.name]!"
+ if("stop")
+ src << "STOP!"
-/obj/machinery/bot/proc/bot_summon()
+ if("go")
+ src << "GO!"
+
+ if("home")
+ src << "RETURN HOME!"
+ else
+ src << "Unidentified control sequence recieved:[command]"
+
+/mob/living/simple_animal/bot/proc/bot_summon()
// summoned to PDA
summon_step()
return
// calculates a path to the current destination
// given an optional turf to avoid
-/obj/machinery/bot/proc/calc_path(turf/avoid)
+/mob/living/simple_animal/bot/proc/calc_path(turf/avoid)
check_bot_access()
- path = get_path_to(loc, patrol_target, src, /turf/proc/Distance_cardinal, 0, 120, id=botcard, exclude=avoid)
+ path = get_path_to(loc, patrol_target, src, /turf/proc/Distance_cardinal, 0, 120, id=access_card, exclude=avoid)
-/obj/machinery/bot/proc/calc_summon_path(turf/avoid)
+/mob/living/simple_animal/bot/proc/calc_summon_path(turf/avoid)
check_bot_access()
spawn()
- path = get_path_to(loc, summon_target, src, /turf/proc/Distance_cardinal, 0, 150, id=botcard, exclude=avoid)
+ path = get_path_to(loc, summon_target, src, /turf/proc/Distance_cardinal, 0, 150, id=access_card, exclude=avoid)
if(!path.len || tries >= 5) //Cannot reach target. Give up and announce the issue.
- speak("Summon command failed, destination unreachable.",radio_frequency)
+ speak("Summon command failed, destination unreachable.",radio_channel)
bot_reset()
-/obj/machinery/bot/proc/summon_step()
+/mob/living/simple_animal/bot/proc/summon_step()
if(loc == summon_target) // Arrived to summon location.
bot_reset()
@@ -700,14 +653,108 @@ obj/machinery/bot/proc/bot_reset()
return
-/obj/machinery/bot/Bump(M as mob|obj) //Leave no door unopened!
+/mob/living/simple_animal/bot/Bump(M as mob|obj) //Leave no door unopened!
. = ..()
- if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(botcard)))
+ if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(access_card)))
var/obj/machinery/door/D = M
- if(D.check_access(botcard))
+ if(D.check_access(access_card))
D.open()
frustration = 0
else if((istype(M, /mob/living/)) && (!anchored))
var/mob/living/Mb = M
loc = Mb.loc
frustration = 0
+
+/mob/living/simple_animal/bot/proc/show_controls(mob/M)
+ users |= M
+ var/dat = ""
+ dat = get_controls(M)
+ var/datum/browser/popup = new(M,window_id,window_name,350,600)
+ popup.set_content(dat)
+ popup.open()
+ onclose(M,window_id,ref=src)
+ return
+
+/mob/living/simple_animal/bot/proc/update_controls()
+ for(var/mob/M in users)
+ show_controls(M)
+
+/mob/living/simple_animal/bot/proc/get_controls(mob/M)
+ return "PROTOBOT - NOT FOR USE"
+
+/mob/living/simple_animal/bot/Topic(href, href_list)
+ //No ..() to prevent strip panel showing up - Todo: make that saner
+ if(topic_denied(usr))
+ usr << "[src]'s interface is not responding!"
+ href_list = list()
+ return
+ add_fingerprint(usr)
+ if(href_list["close"])// HUE HUE
+ if(usr in users)
+ users.Remove(usr)
+ return
+ if((href_list["power"]) && (bot_core.allowed(usr) || !locked))
+ if (on)
+ turn_off()
+ else
+ turn_on()
+
+ switch(href_list["operation"])
+ if("patrol")
+ auto_patrol = !auto_patrol
+ bot_reset()
+ if("remote")
+ remote_disabled = !remote_disabled
+ if("hack")
+ if(emagged != 2)
+ emagged = 2
+ hacked = 1
+ locked = 1
+ usr << "[text_hack]"
+ bot_reset()
+ else if(!hacked)
+ usr << "[text_dehack_fail]"
+ else
+ emagged = 0
+ hacked = 0
+ usr << "[text_dehack]"
+ bot_reset()
+ update_controls()
+
+/mob/living/simple_animal/bot/proc/update_icon()
+ icon_state = "[initial(icon_state)][on]"
+
+// Machinery to simplify topic and access calls
+/obj/machinery/bot_core
+ use_power = 0
+ interact_offline = 1 //DEBUG
+ var/mob/living/simple_animal/bot/owner = null
+
+/obj/machinery/bot_core/New(loc)
+ ..()
+ owner = loc
+ if(!istype(owner))
+ qdel(src)
+
+/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
+ // 0 for access, 1 for denied.
+ if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
+ if(hacked) //Manually emagged by a human - access denied to all.
+ return 1
+ else if(!issilicon(user)) //Bot is hacked, so only silicons are allowed access.
+ return 1
+ else
+ return 0
+
+/mob/living/simple_animal/bot/proc/hack(mob/user)
+ var/hack
+ if(issilicon(user)) //Allows silicons to toggle the emag status of a bot.
+ hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
"
+ hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
"
+ else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control.
+ hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]
"
+ return hack
+
+/mob/living/simple_animal/bot/Login()
+ . = ..()
+ access_card.access += player_access
diff --git a/code/game/machinery/bots/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
similarity index 75%
rename from code/game/machinery/bots/cleanbot.dm
rename to code/modules/mob/living/simple_animal/bot/cleanbot.dm
index 87df25eded6..cb99f07ed06 100644
--- a/code/game/machinery/bots/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -1,19 +1,5 @@
-//Cleanbot assembly
-/obj/item/weapon/bucket_sensor
- desc = "It's a bucket. With a sensor attached."
- name = "proxy bucket"
- icon = 'icons/obj/aibots.dmi'
- icon_state = "bucket_proxy"
- force = 3
- throwforce = 5
- throw_speed = 2
- throw_range = 5
- w_class = 3.
- var/created_name = "Cleanbot"
-
-
//Cleanbot
-/obj/machinery/bot/cleanbot
+/mob/living/simple_animal/bot/cleanbot
name = "\improper Cleanbot"
desc = "A little cleaning robot, he looks so excited!"
icon = 'icons/obj/aibots.dmi'
@@ -21,94 +7,60 @@
layer = 5
density = 0
anchored = 0
- //weight = 1.0E7
health = 25
- maxhealth = 25
+ maxHealth = 25
+ radio_channel = "Service" //Service
+ bot_type = CLEAN_BOT
+ model = "Cleanbot"
+ bot_core_type = /obj/machinery/bot_core/cleanbot
+ window_id = "autoclean"
+ window_name = "Automatic Station Cleaner v1.1"
+ pass_flags = PASSMOB
+
var/blood = 1
var/list/target_types = list()
var/obj/effect/decal/cleanable/target
var/max_targets = 50 //Maximum number of targets a cleanbot can ignore.
var/oldloc = null
- req_one_access = list(access_janitor, access_robotics)
-// var/patrol_path[] = null
-// var/beacon_freq = 1445 // navigation beacon frequency
var/closest_dist
var/closest_loc
var/failed_steps
var/next_dest
var/next_dest_loc
- radio_frequency = SERV_FREQ //Service
- bot_type = CLEAN_BOT
- model = "Cleanbot"
-/obj/machinery/bot/cleanbot/New()
+/mob/living/simple_animal/bot/cleanbot/New()
..()
get_targets()
icon_state = "cleanbot[on]"
var/datum/job/janitor/J = new/datum/job/janitor
- botcard.access += J.get_access()
- prev_access = botcard.access
+ access_card.access += J.get_access()
+ prev_access = access_card.access
-/obj/machinery/bot/cleanbot/turn_on()
+/mob/living/simple_animal/bot/cleanbot/turn_on()
..()
icon_state = "cleanbot[on]"
- updateUsrDialog()
+ bot_core.updateUsrDialog()
-/obj/machinery/bot/cleanbot/turn_off()
+/mob/living/simple_animal/bot/cleanbot/turn_off()
..()
icon_state = "cleanbot[on]"
- updateUsrDialog()
+ bot_core.updateUsrDialog()
-/obj/machinery/bot/cleanbot/bot_reset()
+/mob/living/simple_animal/bot/cleanbot/bot_reset()
..()
ignore_list = list() //Allows the bot to clean targets it previously ignored due to being unreachable.
target = null
oldloc = null
-/obj/machinery/bot/cleanbot/set_custom_texts()
+/mob/living/simple_animal/bot/cleanbot/set_custom_texts()
text_hack = "You corrupt [name]'s cleaning software."
text_dehack = "[name]'s software has been reset!"
text_dehack_fail = "[name] does not seem to respond to your repair code!"
-/obj/machinery/bot/cleanbot/attack_hand(mob/user)
- . = ..()
- if (.)
- return
- usr.set_machine(src)
- interact(user)
-
-/obj/machinery/bot/cleanbot/interact(mob/user)
- var/dat
- dat += hack(user)
- dat += text({"
-Cleaner v1.1 controls
-Status: []
-Behaviour controls are [locked ? "locked" : "unlocked"]
-Maintenance panel panel is [open ? "opened" : "closed"]"},
-text("[on ? "On" : "Off"]"))
- if(!locked || issilicon(user))
- dat += text({"
Cleans Blood: []
"}, text("[blood ? "Yes" : "No"]"))
- dat += text({"
Patrol station: []
"}, text("[auto_patrol ? "Yes" : "No"]"))
-
- var/datum/browser/popup = new(user, "autoclean", "Automatic Station Cleaner v1.1")
- popup.set_content(dat)
- popup.open()
- return
-
-/obj/machinery/bot/cleanbot/Topic(href, href_list)
-
- ..()
- switch(href_list["operation"])
- if("blood")
- blood =!blood
- get_targets()
- updateUsrDialog()
- updateUsrDialog()
-
-/obj/machinery/bot/cleanbot/attackby(obj/item/weapon/W, mob/user, params)
+/mob/living/simple_animal/bot/cleanbot/attackby(obj/item/weapon/W, mob/user, params)
if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if(allowed(user) && !open && !emagged)
+ if(bot_core.allowed(user) && !open && !emagged)
locked = !locked
user << "You [ locked ? "lock" : "unlock"] \the [src] behaviour controls."
else
@@ -121,18 +73,18 @@ text("[on ? "On" : "Off"]"))
else
return ..()
-/obj/machinery/bot/cleanbot/Emag(mob/user)
+/mob/living/simple_animal/bot/cleanbot/Emag(mob/user)
..()
if(emagged == 2)
if(user)
user << "[src] buzzes and beeps."
-/obj/machinery/bot/cleanbot/process_scan(obj/effect/decal/cleanable/D)
+/mob/living/simple_animal/bot/cleanbot/process_scan(obj/effect/decal/cleanable/D)
for(var/T in target_types)
if(istype(D, T))
return D
-/obj/machinery/bot/cleanbot/bot_process()
+/mob/living/simple_animal/bot/cleanbot/handle_automated_action()
if (!..())
return
@@ -166,7 +118,7 @@ text("[on ? "On" : "Off"]"))
if(target)
if(!path || path.len == 0) //No path, need a new one
//Try to produce a path to the target, and ignore airlocks to which it has access.
- path = get_path_to(loc, target.loc, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard)
+ path = get_path_to(loc, target.loc, src, /turf/proc/Distance_cardinal, 0, 30, id=access_card)
if (!bot_move(target))
add_to_ignore(target)
target = null
@@ -185,7 +137,7 @@ text("[on ? "On" : "Off"]"))
oldloc = loc
-/obj/machinery/bot/cleanbot/proc/get_targets()
+/mob/living/simple_animal/bot/cleanbot/proc/get_targets()
target_types = new/list()
target_types += /obj/effect/decal/cleanable/oil
@@ -209,7 +161,7 @@ text("[on ? "On" : "Off"]"))
target_types += /obj/effect/decal/cleanable/blood/drip/
target_types += /obj/effect/decal/cleanable/trail_holder
-/obj/machinery/bot/cleanbot/proc/clean(obj/effect/decal/cleanable/target)
+/mob/living/simple_animal/bot/cleanbot/proc/clean(obj/effect/decal/cleanable/target)
anchored = 1
icon_state = "cleanbot-c"
visible_message("[src] begins to clean up [target]")
@@ -222,7 +174,7 @@ text("[on ? "On" : "Off"]"))
mode = BOT_IDLE
icon_state = "cleanbot[on]"
-/obj/machinery/bot/cleanbot/explode()
+/mob/living/simple_animal/bot/cleanbot/explode()
on = 0
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
@@ -246,7 +198,7 @@ text("[on ? "On" : "Off"]"))
return
qdel(W)
var/turf/T = get_turf(loc)
- var/obj/machinery/bot/cleanbot/A = new /obj/machinery/bot/cleanbot(T)
+ var/mob/living/simple_animal/bot/cleanbot/A = new /mob/living/simple_animal/bot/cleanbot(T)
A.name = created_name
user << "You add the robot arm to the bucket and sensor assembly. Beep boop!"
user.unEquip(src, 1)
@@ -259,3 +211,35 @@ text("[on ? "On" : "Off"]"))
if (!in_range(src, usr) && loc != usr)
return
created_name = t
+
+/obj/machinery/bot_core/cleanbot
+ req_one_access = list(access_janitor, access_robotics)
+
+
+/mob/living/simple_animal/bot/cleanbot/get_controls(mob/user)
+ var/dat
+ dat += hack(user)
+ dat += text({"
+Cleaner v1.1 controls
+Status: []
+Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"},
+text("[on ? "On" : "Off"]"))
+ if(!locked || issilicon(user))
+ dat += text({"
Cleans Blood: []
"}, text("[blood ? "Yes" : "No"]"))
+ dat += text({"
Patrol station: []
"}, text("[auto_patrol ? "Yes" : "No"]"))
+ return dat
+
+/mob/living/simple_animal/bot/cleanbot/Topic(href, href_list)
+ ..()
+ switch(href_list["operation"])
+ if("blood")
+ blood =!blood
+ get_targets()
+ update_controls()
+
+/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
+ if(istype(A,/obj/effect/decal/cleanable))
+ clean(A)
+ else
+ ..()
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
new file mode 100644
index 00000000000..c945aff44fc
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -0,0 +1,462 @@
+//Bot Construction
+
+//Cleanbot assembly
+/obj/item/weapon/bucket_sensor
+ desc = "It's a bucket. With a sensor attached."
+ name = "proxy bucket"
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "bucket_proxy"
+ force = 3
+ throwforce = 5
+ throw_speed = 2
+ throw_range = 5
+ w_class = 3.
+ var/created_name = "Cleanbot"
+
+/obj/item/weapon/bucket_sensor/attackby(obj/item/W, mob/user as mob, params)
+ ..()
+ if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
+ if(!user.unEquip(W))
+ return
+ qdel(W)
+ var/turf/T = get_turf(loc)
+ var/mob/living/simple_animal/bot/cleanbot/A = new /mob/living/simple_animal/bot/cleanbot(T)
+ A.name = created_name
+ user << "You add the robot arm to the bucket and sensor assembly. Beep boop!"
+ user.unEquip(src, 1)
+ qdel(src)
+
+ else if (istype(W, /obj/item/weapon/pen))
+ var/t = stripped_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
+
+//Edbot Assembly
+
+/obj/item/weapon/ed209_assembly
+ name = "\improper ED-209 assembly"
+ desc = "Some sort of bizarre assembly."
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "ed209_frame"
+ item_state = "ed209_frame"
+ var/build_step = 0
+ var/created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess
+ var/lasercolor = ""
+
+/obj/item/weapon/ed209_assembly/attackby(obj/item/weapon/W, mob/user, params)
+ ..()
+
+ if(istype(W, /obj/item/weapon/pen))
+ var/t = stripped_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
+ return
+
+ switch(build_step)
+ if(0,1)
+ if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg))
+ if(!user.unEquip(W))
+ return
+ qdel(W)
+ build_step++
+ user << "You add the robot leg to [src]."
+ 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)
+ var/newcolor = ""
+ if(istype(W, /obj/item/clothing/suit/redtag))
+ newcolor = "r"
+ else if(istype(W, /obj/item/clothing/suit/bluetag))
+ newcolor = "b"
+ if(newcolor || istype(W, /obj/item/clothing/suit/armor/vest))
+ if(!user.unEquip(W))
+ return
+ lasercolor = newcolor
+ qdel(W)
+ build_step++
+ user << "You add the armor to [src]."
+ name = "vest/legs/frame assembly"
+ item_state = "[lasercolor]ed209_shell"
+ icon_state = "[lasercolor]ed209_shell"
+
+ if(3)
+ if(istype(W, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/WT = W
+ if(WT.remove_fuel(0,user))
+ build_step++
+ name = "shielded frame assembly"
+ user << "You weld the vest to [src]."
+ if(4)
+ switch(lasercolor)
+ if("b")
+ if(!istype(W, /obj/item/clothing/head/helmet/bluetaghelm))
+ return
+
+ if("r")
+ if(!istype(W, /obj/item/clothing/head/helmet/redtaghelm))
+ return
+
+ if("")
+ if(!istype(W, /obj/item/clothing/head/helmet))
+ return
+
+ if(!user.unEquip(W))
+ return
+ qdel(W)
+ build_step++
+ user << "You add the helmet to [src]."
+ name = "covered and shielded frame assembly"
+ item_state = "[lasercolor]ed209_hat"
+ icon_state = "[lasercolor]ed209_hat"
+
+ if(5)
+ if(isprox(W))
+ if(!user.unEquip(W))
+ return
+ qdel(W)
+ build_step++
+ user << "You add the prox sensor to [src]."
+ name = "covered, shielded and sensored frame assembly"
+ item_state = "[lasercolor]ed209_prox"
+ icon_state = "[lasercolor]ed209_prox"
+
+ if(6)
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = W
+ if (coil.get_amount() < 1)
+ user << "You need one length of cable to wire the ED-209!"
+ return
+ user << "You start to wire [src]..."
+ if (do_after(user, 40, target = src))
+ if (coil.get_amount() >= 1 && build_step == 6)
+ coil.use(1)
+ build_step = 7
+ user << "You wire the ED-209 assembly."
+ name = "wired ED-209 assembly"
+
+ if(7)
+ var/newname = ""
+ switch(lasercolor)
+ if("b")
+ if(!istype(W, /obj/item/weapon/gun/energy/laser/bluetag))
+ return
+ newname = "bluetag ED-209 assembly"
+ if("r")
+ if(!istype(W, /obj/item/weapon/gun/energy/laser/redtag))
+ return
+ newname = "redtag ED-209 assembly"
+ if("")
+ if(!istype(W, /obj/item/weapon/gun/energy/gun/advtaser))
+ return
+ newname = "taser ED-209 assembly"
+ else
+ return
+ if(!user.unEquip(W))
+ return
+ name = newname
+ build_step++
+ user << "You add [W] to [src]."
+ item_state = "[lasercolor]ed209_taser"
+ icon_state = "[lasercolor]ed209_taser"
+ qdel(W)
+
+ if(8)
+ if(istype(W, /obj/item/weapon/screwdriver))
+ playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
+ var/turf/T = get_turf(user)
+ user << "You start attaching the gun to the frame..."
+ sleep(40)
+ if(get_turf(user) == T)
+ build_step++
+ name = "armed [name]"
+ user << "Taser gun attached."
+
+ if(9)
+ if(istype(W, /obj/item/weapon/stock_parts/cell))
+ if(!user.unEquip(W))
+ return
+ build_step++
+ user << "You complete the ED-209."
+ var/turf/T = get_turf(src)
+ new /mob/living/simple_animal/bot/ed209(T,created_name,lasercolor)
+ qdel(W)
+ user.unEquip(src, 1)
+ qdel(src)
+
+//Floorbot assemblies
+/obj/item/weapon/toolbox_tiles
+ desc = "It's a toolbox with tiles sticking out the top"
+ name = "tiles and toolbox"
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "toolbox_tiles"
+ force = 3
+ throwforce = 10
+ throw_speed = 2
+ throw_range = 5
+ w_class = 3
+ var/created_name = "Floorbot"
+
+/obj/item/weapon/toolbox_tiles_sensor
+ desc = "It's a toolbox with tiles sticking out the top and a sensor attached"
+ name = "tiles, toolbox and sensor arrangement"
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "toolbox_tiles_sensor"
+ force = 3
+ throwforce = 10
+ throw_speed = 2
+ throw_range = 5
+ w_class = 3
+ var/created_name = "Floorbot"
+
+/obj/item/weapon/storage/toolbox/mechanical/attackby(obj/item/stack/tile/plasteel/T, mob/user, params)
+ if(!istype(T, /obj/item/stack/tile/plasteel))
+ ..()
+ return
+ if(contents.len >= 1)
+ user << "They won't fit in, as there is already stuff inside!"
+ return
+ if(T.use(10))
+ if(user.s_active)
+ user.s_active.close(user)
+ var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles
+ user.put_in_hands(B)
+ user << "You add the tiles into the empty toolbox. They protrude from the top."
+ user.unEquip(src, 1)
+ qdel(src)
+ else
+ user << "You need 10 floor tiles to start building a floorbot!"
+ return
+
+/obj/item/weapon/toolbox_tiles/attackby(obj/item/W, mob/user, params)
+ ..()
+ if(isprox(W))
+ qdel(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 << "You add the sensor to the toolbox and tiles."
+ user.unEquip(src, 1)
+ qdel(src)
+
+ else if (istype(W, /obj/item/weapon/pen))
+ var/t = stripped_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
+
+/obj/item/weapon/toolbox_tiles_sensor/attackby(obj/item/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
+ qdel(W)
+ var/turf/T = get_turf(user.loc)
+ var/mob/living/simple_animal/bot/floorbot/A = new /mob/living/simple_animal/bot/floorbot(T)
+ A.name = created_name
+ user << "You add the robot arm to the odd looking toolbox assembly. Boop beep!"
+ user.unEquip(src, 1)
+ qdel(src)
+ else if (istype(W, /obj/item/weapon/pen))
+ var/t = stripped_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
+
+//Medbot Assembly
+/obj/item/weapon/firstaid_arm_assembly
+ name = "incomplete medibot 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
+
+ /obj/item/weapon/firstaid_arm_assembly/New()
+ ..()
+ spawn(5)
+ if(skin)
+ overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]")
+
+/obj/item/weapon/storage/firstaid/attackby(obj/item/robot_parts/S, mob/user, params)
+
+ if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
+ ..()
+ return
+
+ //Making a medibot!
+ if(contents.len >= 1)
+ user << "You need to empty [src] out first!"
+ 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"
+ else if(istype(src,/obj/item/weapon/storage/firstaid/brute))
+ A.skin = "brute"
+
+ qdel(S)
+ user.put_in_hands(A)
+ user << "You add the robot arm to the first aid kit."
+ user.unEquip(src, 1)
+ qdel(src)
+
+
+/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/weapon/pen))
+ var/t = stripped_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))
+ if(!user.unEquip(W))
+ return
+ qdel(W)
+ build_step++
+ user << "You add the health sensor to [src]."
+ name = "First aid/robot arm/health analyzer assembly"
+ overlays += image('icons/obj/aibots.dmi', "na_scanner")
+
+ if(1)
+ if(isprox(W))
+ if(!user.unEquip(W))
+ return
+ qdel(W)
+ build_step++
+ user << "You complete the Medibot. Beep boop!"
+ var/turf/T = get_turf(src)
+ var/mob/living/simple_animal/bot/medbot/S = new /mob/living/simple_animal/bot/medbot(T)
+ S.skin = skin
+ S.name = created_name
+ user.unEquip(src, 1)
+ qdel(src)
+
+//Secbot Assembly
+/obj/item/weapon/secbot_assembly
+ name = "incomplete securitron assembly"
+ desc = "Some sort of bizarre assembly made from a proximity sensor, helmet, and signaler."
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "helmet_signaler"
+ item_state = "helmet"
+ var/build_step = 0
+ var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
+
+/obj/item/clothing/head/helmet/attackby(obj/item/device/assembly/signaler/S, mob/user, params)
+ ..()
+ if(!issignaler(S))
+ ..()
+ return
+
+ if(type != /obj/item/clothing/head/helmet/sec) //Eh, but we don't want people making secbots out of space helmets.
+ return
+
+ if(F) //Has a flashlight. Player must remove it, else it will be lost forever.
+ user << "The mounted flashlight is in the way, remove it first!"
+ return
+
+ if(S.secured)
+ qdel(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.unEquip(src, 1)
+ qdel(src)
+ else
+ return
+
+/obj/item/weapon/secbot_assembly/attackby(obj/item/I, mob/user, params)
+ ..()
+ if(istype(I, /obj/item/weapon/weldingtool))
+ if(!build_step)
+ var/obj/item/weapon/weldingtool/WT = I
+ if(WT.remove_fuel(0, user))
+ build_step++
+ overlays += "hs_hole"
+ user << "You weld a hole in [src]!"
+ else if(build_step == 1)
+ var/obj/item/weapon/weldingtool/WT = I
+ if(WT.remove_fuel(0, user))
+ build_step--
+ overlays -= "hs_hole"
+ user << "You weld the hole in [src] shut!"
+
+ else if(isprox(I) && (build_step == 1))
+ if(!user.unEquip(I))
+ return
+ build_step++
+ user << "You add the prox sensor to [src]!"
+ overlays += "hs_eye"
+ name = "helmet/signaler/prox sensor assembly"
+ qdel(I)
+
+ else if(((istype(I, /obj/item/robot_parts/l_arm)) || (istype(I, /obj/item/robot_parts/r_arm))) && (build_step == 2))
+ if(!user.unEquip(I))
+ return
+ build_step++
+ user << "You add the robot arm to [src]!"
+ name = "helmet/signaler/prox sensor/robot arm assembly"
+ overlays += "hs_arm"
+ qdel(I)
+
+ else if((istype(I, /obj/item/weapon/melee/baton)) && (build_step >= 3))
+ if(!user.unEquip(I))
+ return
+ build_step++
+ user << "You complete the Securitron! Beep boop."
+ var/mob/living/simple_animal/bot/secbot/S = new /mob/living/simple_animal/bot/secbot
+ S.loc = get_turf(src)
+ S.name = created_name
+ qdel(I)
+ qdel(src)
+
+ else if(istype(I, /obj/item/weapon/pen))
+ var/t = stripped_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 if(istype(I, /obj/item/weapon/screwdriver))
+ if(!build_step)
+ new /obj/item/device/assembly/signaler(get_turf(src))
+ new /obj/item/clothing/head/helmet/sec(get_turf(src))
+ user << "You disconnect the signaler from the helmet."
+ qdel(src)
+
+ else if(build_step == 2)
+ overlays -= "hs_eye"
+ new /obj/item/device/assembly/prox_sensor(get_turf(src))
+ user << "You detach the proximity sensor from [src]."
+ build_step--
+
+ else if(build_step == 3)
+ overlays -= "hs_arm"
+ new /obj/item/robot_parts/l_arm(get_turf(src))
+ user << "You remove the robot arm from [src]."
+ build_step--
\ No newline at end of file
diff --git a/code/game/machinery/bots/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
similarity index 54%
rename from code/game/machinery/bots/ed209bot.dm
rename to code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 5073441a097..9fbf47d1509 100644
--- a/code/game/machinery/bots/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -1,4 +1,4 @@
-/obj/machinery/bot/ed209
+/mob/living/simple_animal/bot/ed209
name = "\improper ED-209 Security Robot"
desc = "A security robot. He looks less than thrilled."
icon = 'icons/obj/aibots.dmi'
@@ -6,26 +6,32 @@
layer = 5
density = 1
anchored = 0
-// weight = 1.0E7
- req_access = list(access_security)
health = 100
- maxhealth = 100
- fire_dam_coeff = 0.7
- brute_dam_coeff = 0.5
+ maxHealth = 100
+ damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+
+ environment_smash = 2 //Walls can't stop THE LAW
+ mob_size = MOB_SIZE_LARGE
+
+ radio_key = /obj/item/device/encryptionkey/headset_sec
+ radio_channel = "Security"
+ bot_type = SEC_BOT
+ model = "ED-209"
+ bot_core = /obj/machinery/bot_core/secbot
+ window_id = "autoed209"
+ window_name = "Automatic Security Unit v2.6"
var/lastfired = 0
var/shot_delay = 3 //.3 seconds between shots
var/lasercolor = ""
var/disabled = 0//A holder for if it needs to be disabled, if true it will not seach for targets, shoot at targets, or move, currently only used for lasertag
- //var/lasers = 0
var/mob/living/carbon/target
var/oldtarget_name
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
-//var/emagged = 0 //Emagged Secbots view everyone as a criminal
var/declare_arrests = 1 //When making an arrest, should it notify everyone wearing sechuds?
var/idcheck = 1 //If true, arrest people with no IDs
var/weaponscheck = 1 //If true, arrest people for weapons if they don't have access
@@ -33,23 +39,9 @@
var/arrest_type = 0 //If true, don't handcuff
var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type
var/shoot_sound = 'sound/weapons/Taser.ogg'
- radio_frequency = SEC_FREQ
- bot_type = SEC_BOT
- model = "ED-209"
-/obj/item/weapon/ed209_assembly
- name = "\improper ED-209 assembly"
- desc = "Some sort of bizarre assembly."
- icon = 'icons/obj/aibots.dmi'
- icon_state = "ed209_frame"
- item_state = "ed209_frame"
- var/build_step = 0
- var/created_name = "ED-209 Security Robot" //To preserve the name if it's a unique securitron I guess
- var/lasercolor = ""
-
-
-/obj/machinery/bot/ed209/New(loc,created_name,created_lasercolor)
+/mob/living/simple_animal/bot/ed209/New(loc,created_name,created_lasercolor)
..()
if(created_name)
name = created_name
@@ -59,32 +51,34 @@
set_weapon() //giving it the right projectile and firing sound.
spawn(3)
var/datum/job/detective/J = new/datum/job/detective
- botcard.access += J.get_access()
- prev_access = botcard.access
+ access_card.access += J.get_access()
+ prev_access = access_card.access
if(lasercolor)
shot_delay = 6//Longer shot delay because JESUS CHRIST
check_records = 0//Don't actively target people set to arrest
arrest_type = 1//Don't even try to cuff
- req_access = list(access_maint_tunnels, access_theatre)
+ bot_core.req_access = list(access_maint_tunnels, access_theatre)
arrest_type = 1
if((lasercolor == "b") && (name == "\improper ED-209 Security Robot"))//Picks a name if there isn't already a custome one
name = pick("BLUE BALLER","SANIC","BLUE KILLDEATH MURDERBOT")
if((lasercolor == "r") && (name == "\improper ED-209 Security Robot"))
name = pick("RED RAMPAGE","RED ROVER","RED KILLDEATH MURDERBOT")
-/obj/machinery/bot/ed209/turn_on()
+ //SECHUD
+ var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
+ secsensor.add_hud_to(src)
+
+/mob/living/simple_animal/bot/ed209/turn_on()
. = ..()
icon_state = "[lasercolor]ed209[on]"
mode = BOT_IDLE
- updateUsrDialog()
-/obj/machinery/bot/ed209/turn_off()
+/mob/living/simple_animal/bot/ed209/turn_off()
..()
icon_state = "[lasercolor]ed209[on]"
- updateUsrDialog()
-/obj/machinery/bot/ed209/bot_reset()
+/mob/living/simple_animal/bot/ed209/bot_reset()
..()
target = null
oldtarget_name = null
@@ -93,15 +87,12 @@
last_found = world.time
set_weapon()
-/obj/machinery/bot/ed209/set_custom_texts()
+/mob/living/simple_animal/bot/ed209/set_custom_texts()
text_hack = "You disable [name]'s combat inhibitor."
text_dehack = "You restore [name]'s combat inhibitor."
text_dehack_fail = "[name] ignores your attempts to restrict him!"
-/obj/machinery/bot/ed209/attack_hand(mob/user)
- . = ..()
- if (.)
- return
+/mob/living/simple_animal/bot/ed209/get_controls(mob/user)
var/dat
dat += hack(user)
dat += text({"
@@ -129,12 +120,10 @@ Auto Patrol[]"},
"[arrest_type ? "Detain" : "Arrest"]",
"[declare_arrests ? "Yes" : "No"]",
"[auto_patrol ? "On" : "Off"]" )
- var/datum/browser/popup = new(user, "autoed209", "Automatic Security Unit v2.6")
- popup.set_content(dat)
- popup.open()
- return
-/obj/machinery/bot/ed209/Topic(href, href_list)
+ return dat
+
+/mob/living/simple_animal/bot/ed209/Topic(href, href_list)
if(lasercolor && (istype(usr,/mob/living/carbon/human)))
var/mob/living/carbon/human/H = usr
if((lasercolor == "b") && (istype(H.wear_suit, /obj/item/clothing/suit/redtag)))//Opposing team cannot operate it
@@ -148,44 +137,32 @@ Auto Patrol[]"},
idcheck = !idcheck
if("weaponscheck")
weaponscheck = !weaponscheck
- updateUsrDialog()
+ update_controls()
if ("ignorerec")
check_records = !check_records
- updateUsrDialog()
+ update_controls()
if ("switchmode")
arrest_type = !arrest_type
- updateUsrDialog()
+ update_controls()
if("declarearrests")
declare_arrests = !declare_arrests
- updateUsrDialog()
+ update_controls()
-/obj/machinery/bot/ed209/attackby(obj/item/weapon/W, mob/user, params)
- if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if (allowed(user) && !open && !emagged)
- locked = !locked
- user << "Controls are now [locked ? "locked" : "unlocked"]."
- else
- if(emagged)
- user << "ERROR"
- if(open)
- user << "Please close the access panel before locking it."
- else
- user << "Access denied."
- else
- ..()
- if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
- return
- if (!istype(W, /obj/item/weapon/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
- if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina.
- threatlevel = user.assess_threat(src)
- threatlevel += 6
- if(threatlevel >= 4)
- target = user
- if(lasercolor)//To make up for the fact that lasertag bots don't hunt
- shootAt(user)
- mode = BOT_HUNT
+/mob/living/simple_animal/bot/ed209/attackby(obj/item/weapon/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
+ return
+ if (!istype(W, /obj/item/weapon/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
+ if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina.
+ threatlevel = user.assess_threat(src)
+ threatlevel += 6
+ if(threatlevel >= 4)
+ target = user
+ if(lasercolor)//To make up for the fact that lasertag bots don't hunt
+ shootAt(user)
+ mode = BOT_HUNT
-/obj/machinery/bot/ed209/Emag(mob/user)
+/mob/living/simple_animal/bot/ed209/Emag(mob/user)
..()
if(emagged == 2)
if(user)
@@ -196,7 +173,7 @@ Auto Patrol[]"},
icon_state = "[lasercolor]ed209[on]"
set_weapon()
-/obj/machinery/bot/ed209/bullet_act(obj/item/projectile/Proj)
+/mob/living/simple_animal/bot/ed209/bullet_act(obj/item/projectile/Proj)
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if (!Proj.nodamage && Proj.damage < src.health)
@@ -207,7 +184,7 @@ Auto Patrol[]"},
mode = BOT_HUNT
..()
-/obj/machinery/bot/ed209/bot_process()
+/mob/living/simple_animal/bot/ed209/handle_automated_action()
if (!..())
return
@@ -250,29 +227,11 @@ Auto Patrol[]"},
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
- playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
- icon_state = "[lasercolor]ed209-c"
- spawn(2)
- icon_state = "[lasercolor]ed209[on]"
- var/mob/living/carbon/M = target
- if(istype(M, /mob/living/carbon/human))
- M.stuttering = 5
- M.Stun(5)
- M.Weaken(5)
- else
- M.Weaken(5)
- M.stuttering = 5
- M.Stun(5)
-
- if(declare_arrests)
- var/area/location = get_area(src)
- speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_frequency)
- target.visible_message("[src] has stunned [target]!",\
- "[src] has stunned you!")
+ stun_attack(target)
mode = BOT_PREP_ARREST
anchored = 1
- target_lastloc = M.loc
+ target_lastloc = target.loc
return
else // not next to perp
@@ -295,18 +254,7 @@ Auto Patrol[]"},
if(iscarbon(target) && target.canBeHandcuffed())
if(!arrest_type)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
- mode = BOT_ARREST
- playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
- target.visible_message("[src] is trying to put zipties on [target]!",\
- "[src] is trying to put zipties on you!")
-
- spawn(60)
- if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
- return
- if(!target.handcuffed)
- target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(target)
- target.update_inv_handcuffed(0) //update the handcuffs overlay
- back_to_idle()
+ cuff(target)
else
back_to_idle()
return
@@ -344,25 +292,25 @@ Auto Patrol[]"},
return
-/obj/machinery/bot/ed209/proc/back_to_idle()
+/mob/living/simple_animal/bot/ed209/proc/back_to_idle()
anchored = 0
mode = BOT_IDLE
target = null
last_found = world.time
frustration = 0
spawn(0)
- bot_process() //ensure bot quickly responds
+ handle_automated_action() //ensure bot quickly responds
-/obj/machinery/bot/ed209/proc/back_to_hunt()
+/mob/living/simple_animal/bot/ed209/proc/back_to_hunt()
anchored = 0
frustration = 0
mode = BOT_HUNT
spawn(0)
- bot_process() //ensure bot quickly responds
+ handle_automated_action() //ensure bot quickly responds
// look for a criminal in view of the bot
-/obj/machinery/bot/ed209/proc/look_for_perp()
+/mob/living/simple_animal/bot/ed209/proc/look_for_perp()
if(disabled)
return
anchored = 0
@@ -387,17 +335,17 @@ Auto Patrol[]"},
visible_message("[src] points at [C.name]!")
mode = BOT_HUNT
spawn(0)
- bot_process() // ensure bot quickly responds to a perp
+ handle_automated_action() // ensure bot quickly responds to a perp
break
else
continue
-/obj/machinery/bot/ed209/proc/check_for_weapons(var/obj/item/slot_item)
+/mob/living/simple_animal/bot/ed209/proc/check_for_weapons(var/obj/item/slot_item)
if(slot_item && slot_item.needs_permit)
return 1
return 0
-/obj/machinery/bot/ed209/explode()
+/mob/living/simple_animal/bot/ed209/explode()
walk_to(src,0)
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
@@ -443,7 +391,7 @@ Auto Patrol[]"},
new /obj/effect/decal/cleanable/oil(loc)
..()
-/obj/machinery/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound
+/mob/living/simple_animal/bot/ed209/proc/set_weapon() //used to update the projectile type and firing sound
shoot_sound = 'sound/weapons/laser.ogg'
if(emagged == 2)
if(lasercolor)
@@ -459,7 +407,7 @@ Auto Patrol[]"},
else if(lasercolor == "r")
projectile = /obj/item/projectile/beam/lasertag/redtag
-/obj/machinery/bot/ed209/proc/shootAt(mob/target)
+/mob/living/simple_animal/bot/ed209/proc/shootAt(mob/target)
if(lastfired && world.time - lastfired < shot_delay)
return
lastfired = world.time
@@ -472,8 +420,6 @@ Auto Patrol[]"},
if (!( istype(T, /turf) ))
return
- //if(lastfired && world.time - lastfired < 100)
-
if(!projectile)
return
@@ -486,14 +432,14 @@ Auto Patrol[]"},
A.xo = U.x - T.x
A.fire()
-/obj/machinery/bot/ed209/attack_alien(mob/living/carbon/alien/user)
+/mob/living/simple_animal/bot/ed209/attack_alien(mob/living/carbon/alien/user)
..()
if (!isalien(target))
target = user
mode = BOT_HUNT
-/obj/machinery/bot/ed209/emp_act(severity)
+/mob/living/simple_animal/bot/ed209/emp_act(severity)
if(severity==2 && prob(70))
..(severity-1)
@@ -532,156 +478,7 @@ Auto Patrol[]"},
mode = BOT_HUNT
-
-/obj/item/weapon/ed209_assembly/attackby(obj/item/weapon/W, mob/user, params)
- ..()
-
- if(istype(W, /obj/item/weapon/pen))
- var/t = stripped_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
- return
-
- switch(build_step)
- if(0,1)
- if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg))
- if(!user.unEquip(W))
- return
- qdel(W)
- build_step++
- user << "You add the robot leg to [src]."
- 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)
- var/newcolor = ""
- if(istype(W, /obj/item/clothing/suit/redtag))
- newcolor = "r"
- else if(istype(W, /obj/item/clothing/suit/bluetag))
- newcolor = "b"
- if(newcolor || istype(W, /obj/item/clothing/suit/armor/vest))
- if(!user.unEquip(W))
- return
- lasercolor = newcolor
- qdel(W)
- build_step++
- user << "You add the armor to [src]."
- name = "vest/legs/frame assembly"
- item_state = "[lasercolor]ed209_shell"
- icon_state = "[lasercolor]ed209_shell"
-
- if(3)
- if(istype(W, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/WT = W
- if(WT.remove_fuel(0,user))
- build_step++
- name = "shielded frame assembly"
- user << "You weld the vest to [src]."
- if(4)
- switch(lasercolor)
- if("b")
- if(!istype(W, /obj/item/clothing/head/helmet/bluetaghelm))
- return
-
- if("r")
- if(!istype(W, /obj/item/clothing/head/helmet/redtaghelm))
- return
-
- if("")
- if(!istype(W, /obj/item/clothing/head/helmet))
- return
-
- if(!user.unEquip(W))
- return
- qdel(W)
- build_step++
- user << "You add the helmet to [src]."
- name = "covered and shielded frame assembly"
- item_state = "[lasercolor]ed209_hat"
- icon_state = "[lasercolor]ed209_hat"
-
- if(5)
- if(isprox(W))
- if(!user.unEquip(W))
- return
- qdel(W)
- build_step++
- user << "You add the prox sensor to [src]."
- name = "covered, shielded and sensored frame assembly"
- item_state = "[lasercolor]ed209_prox"
- icon_state = "[lasercolor]ed209_prox"
-
- if(6)
- if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/coil = W
- if (coil.get_amount() < 1)
- user << "You need one length of cable to wire the ED-209!"
- return
- user << "You start to wire [src]..."
- if (do_after(user, 40, target = src))
- if (coil.get_amount() >= 1 && build_step == 6)
- coil.use(1)
- build_step = 7
- user << "You wire the ED-209 assembly."
- name = "wired ED-209 assembly"
-
- if(7)
- var/newname = ""
- switch(lasercolor)
- if("b")
- if(!istype(W, /obj/item/weapon/gun/energy/laser/bluetag))
- return
- newname = "bluetag ED-209 assembly"
- if("r")
- if(!istype(W, /obj/item/weapon/gun/energy/laser/redtag))
- return
- newname = "redtag ED-209 assembly"
- if("")
- if(!istype(W, /obj/item/weapon/gun/energy/gun/advtaser))
- return
- newname = "taser ED-209 assembly"
- else
- return
- if(!user.unEquip(W))
- return
- name = newname
- build_step++
- user << "You add [W] to [src]."
- item_state = "[lasercolor]ed209_taser"
- icon_state = "[lasercolor]ed209_taser"
- qdel(W)
-
- if(8)
- if(istype(W, /obj/item/weapon/screwdriver))
- playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
- var/turf/T = get_turf(user)
- user << "You start attaching the gun to the frame..."
- sleep(40)
- if(get_turf(user) == T)
- build_step++
- name = "armed [name]"
- user << "Taser gun attached."
-
- if(9)
- if(istype(W, /obj/item/weapon/stock_parts/cell))
- if(!user.unEquip(W))
- return
- build_step++
- user << "You complete the ED-209."
- var/turf/T = get_turf(src)
- new /obj/machinery/bot/ed209(T,created_name,lasercolor)
- qdel(W)
- user.unEquip(src, 1)
- qdel(src)
-
-
-/obj/machinery/bot/ed209/bullet_act(obj/item/projectile/Proj)
+/mob/living/simple_animal/bot/ed209/bullet_act(obj/item/projectile/Proj)
if(!disabled)
var/lasertag_check = 0
if((lasercolor == "b"))
@@ -703,11 +500,64 @@ Auto Patrol[]"},
else
..(Proj)
-/obj/machinery/bot/ed209/bluetag/New()//If desired, you spawn red and bluetag bots easily
- new /obj/machinery/bot/ed209(get_turf(src),null,"b")
+/mob/living/simple_animal/bot/ed209/bluetag/New()//If desired, you spawn red and bluetag bots easily
+ new /mob/living/simple_animal/bot/ed209(get_turf(src),null,"b")
qdel(src)
-/obj/machinery/bot/ed209/redtag/New()
- new /obj/machinery/bot/ed209(get_turf(src),null,"r")
+/mob/living/simple_animal/bot/ed209/redtag/New()
+ new /mob/living/simple_animal/bot/ed209(get_turf(src),null,"r")
qdel(src)
+
+/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A)
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ if(!C.stunned || arrest_type)
+ stun_attack(A)
+ else if(C.canBeHandcuffed() && !C.handcuffed)
+ cuff(A)
+ else
+ ..()
+
+/mob/living/simple_animal/bot/ed209/RangedAttack(atom/A)
+ if(ismob(A))
+ shootAt(A)
+ else
+ ..()
+
+/mob/living/simple_animal/bot/ed209/proc/stun_attack(mob/living/carbon/C)
+ playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
+ icon_state = "[lasercolor]ed209-c"
+ spawn(2)
+ icon_state = "[lasercolor]ed209[on]"
+ var/threat = 5
+ if(istype(C, /mob/living/carbon/human))
+ C.stuttering = 5
+ C.Stun(5)
+ C.Weaken(5)
+ var/mob/living/carbon/human/H = C
+ threat = H.assess_threat(src)
+ else
+ C.Weaken(5)
+ C.stuttering = 5
+ C.Stun(5)
+
+ if(declare_arrests)
+ var/area/location = get_area(src)
+ speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
+ C.visible_message("[src] has stunned [C]!",\
+ "[src] has stunned you!")
+
+/mob/living/simple_animal/bot/ed209/proc/cuff(mob/living/carbon/C)
+ mode = BOT_ARREST
+ playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
+ C.visible_message("[src] is trying to put zipties on [C]!",\
+ "[src] is trying to put zipties on you!")
+
+ spawn(60)
+ if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
+ return
+ if(!C.handcuffed)
+ C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
+ C.update_inv_handcuffed(0) //update the handcuffs overlay
+ back_to_idle()
diff --git a/code/game/machinery/bots/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
similarity index 67%
rename from code/game/machinery/bots/floorbot.dm
rename to code/modules/mob/living/simple_animal/bot/floorbot.dm
index 50a429270f5..25d8436e2e3 100644
--- a/code/game/machinery/bots/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -1,30 +1,5 @@
-//Floorbot assemblies
-/obj/item/weapon/toolbox_tiles
- desc = "It's a toolbox with tiles sticking out the top"
- name = "tiles and toolbox"
- icon = 'icons/obj/aibots.dmi'
- icon_state = "toolbox_tiles"
- force = 3
- throwforce = 10
- throw_speed = 2
- throw_range = 5
- w_class = 3
- var/created_name = "Floorbot"
-
-/obj/item/weapon/toolbox_tiles_sensor
- desc = "It's a toolbox with tiles sticking out the top and a sensor attached"
- name = "tiles, toolbox and sensor arrangement"
- icon = 'icons/obj/aibots.dmi'
- icon_state = "toolbox_tiles_sensor"
- force = 3
- throwforce = 10
- throw_speed = 2
- throw_range = 5
- w_class = 3
- var/created_name = "Floorbot"
-
//Floorbot
-/obj/machinery/bot/floorbot
+/mob/living/simple_animal/bot/floorbot
name = "\improper Floorbot"
desc = "A little floor repairing robot, he looks so excited!"
icon = 'icons/obj/aibots.dmi'
@@ -33,8 +8,17 @@
density = 0
anchored = 0
health = 25
- maxhealth = 25
- //weight = 1.0E7
+ maxHealth = 25
+
+ radio_channel = "Engineering"
+ bot_type = FLOOR_BOT
+ model = "Floorbot"
+ bot_core = /obj/machinery/bot_core/floorbot
+ window_id = "autofloor"
+ window_name = "Automatic Station Floor Repairer v1.1"
+
+ var/process_type //Determines what to do when process_scan() recieves a target. See process_scan() for details.
+ var/targetdirection
var/amount = 10
var/replacetiles = 0
var/eattiles = 0
@@ -46,12 +30,7 @@
var/max_targets = 50
var/turf/target
var/oldloc = null
- req_one_access = list(access_construction, access_robotics)
- var/targetdirection
- radio_frequency = ENG_FREQ //Engineering channel
- bot_type = FLOOR_BOT
- model = "Floorbot"
- var/process_type //Determines what to do when process_scan() recieves a target. See process_scan() for details.
+
#define HULL_BREACH 1
#define BRIDGE_MODE 2
#define FIX_TILE 3
@@ -59,24 +38,22 @@
#define REPLACE_TILE 5
#define TILE_EMAG 6
-/obj/machinery/bot/floorbot/New()
+/mob/living/simple_animal/bot/floorbot/New()
..()
- updateicon()
+ update_icon()
var/datum/job/engineer/J = new/datum/job/engineer
- botcard.access += J.get_access()
- prev_access = botcard.access
+ access_card.access += J.get_access()
+ prev_access = access_card.access
-/obj/machinery/bot/floorbot/turn_on()
+/mob/living/simple_animal/bot/floorbot/turn_on()
. = ..()
- updateicon()
- updateUsrDialog()
+ update_icon()
-/obj/machinery/bot/floorbot/turn_off()
+/mob/living/simple_animal/bot/floorbot/turn_off()
..()
- updateicon()
- updateUsrDialog()
+ update_icon()
-/obj/machinery/bot/floorbot/bot_reset()
+/mob/living/simple_animal/bot/floorbot/bot_reset()
..()
target = null
oldloc = null
@@ -85,19 +62,12 @@
anchored = 0
update_icon()
-/obj/machinery/bot/floorbot/set_custom_texts()
+/mob/living/simple_animal/bot/floorbot/set_custom_texts()
text_hack = "You corrupt [name]'s construction protocols."
text_dehack = "You detect errors in [name] and reset his programming."
text_dehack_fail = "[name] is not responding to reset commands!"
-/obj/machinery/bot/floorbot/attack_hand(mob/user)
- . = ..()
- if (.)
- return
- usr.set_machine(src)
- interact(user)
-
-/obj/machinery/bot/floorbot/interact(mob/user)
+/mob/living/simple_animal/bot/floorbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += "Floor Repairer Controls v1.1
"
@@ -121,13 +91,10 @@
bmode = "disabled"
dat += "Bridge Mode : [bmode]
"
- var/datum/browser/popup = new(user, "autofloor", "Automatic Station Floor Repairer v1.1")
- popup.set_content(dat)
- popup.open()
- return
+ return dat
-/obj/machinery/bot/floorbot/attackby(obj/item/W , mob/user, params)
+/mob/living/simple_animal/bot/floorbot/attackby(obj/item/W , mob/user, params)
if(istype(W, /obj/item/stack/tile/plasteel))
var/obj/item/stack/tile/plasteel/T = W
if(amount >= 50)
@@ -138,31 +105,19 @@
if (loaded > 0)
user << "You load [loaded] tiles into the floorbot. He now contains [amount] tiles."
nagged = 0
- updateicon()
+ update_icon()
else
user << "You need at least one floor tile to put into [src]!"
- else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if(allowed(user) && !open && !emagged)
- locked = !locked
- user << "You [locked ? "lock" : "unlock"] \the [src] behaviour controls."
- else
- if(emagged)
- user << "ERROR"
- if(open)
- user << "Please close the access panel before locking it."
- else
- user << "Access denied."
- updateUsrDialog()
else
..()
-/obj/machinery/bot/floorbot/Emag(mob/user)
+/mob/living/simple_animal/bot/floorbot/Emag(mob/user)
..()
if(emagged == 2)
if(user)
user << "[src] buzzes and beeps."
-/obj/machinery/bot/floorbot/Topic(href, href_list)
+/mob/living/simple_animal/bot/floorbot/Topic(href, href_list)
..()
switch(href_list["operation"])
if("replace")
@@ -193,9 +148,9 @@
targetdirection = 8
if("disable")
targetdirection = null
- updateUsrDialog()
+ update_controls()
-/obj/machinery/bot/floorbot/bot_process()
+/mob/living/simple_animal/bot/floorbot/handle_automated_action()
if (!..())
return
@@ -260,9 +215,9 @@
if(path.len == 0)
if(!istype(target, /turf/))
var/turf/TL = get_turf(target)
- path = get_path_to(loc, TL, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard, simulated_only = 0)
+ path = get_path_to(loc, TL, src, /turf/proc/Distance_cardinal, 0, 30, id=access_card,simulated_only = 0)
else
- path = get_path_to(loc, target, src, /turf/proc/Distance_cardinal, 0, 30, id=botcard, simulated_only = 0)
+ path = get_path_to(loc, target, src, /turf/proc/Distance_cardinal, 0, 30, id=access_card,simulated_only = 0)
if(!bot_move(target))
add_to_ignore(target)
@@ -300,12 +255,12 @@
oldloc = loc
-/obj/machinery/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us!
+/mob/living/simple_animal/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us!
if(!nagged)
- speak("Requesting refill at [get_area(src)]!", radio_frequency)
+ speak("Requesting refill at [get_area(src)]!", radio_channel)
nagged = 1
-/obj/machinery/bot/floorbot/proc/is_hull_breach(turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas.
+/mob/living/simple_animal/bot/floorbot/proc/is_hull_breach(turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas.
var/area/t_area = get_area(t)
if (t_area && (t_area.name == "Space" || findtext(t_area.name, "huttle")))
return 0
@@ -313,7 +268,7 @@
return 1
//Floorbots, having several functions, need sort out special conditions here.
-obj/machinery/bot/floorbot/process_scan(scan_target)
+/mob/living/simple_animal/bot/floorbot/process_scan(scan_target)
var/result
var/turf/simulated/floor/F
switch(process_type)
@@ -341,7 +296,7 @@ obj/machinery/bot/floorbot/process_scan(scan_target)
result = scan_target
return result
-/obj/machinery/bot/floorbot/proc/repair(turf/target_turf)
+/mob/living/simple_animal/bot/floorbot/proc/repair(turf/target_turf)
if(istype(target_turf, /turf/space/))
//Must be a hull breach or in bridge mode to continue.
@@ -367,7 +322,7 @@ obj/machinery/bot/floorbot/process_scan(scan_target)
target_turf.ChangeTurf(/turf/simulated/floor/plating)
mode = BOT_IDLE
amount -= 1
- updateicon()
+ update_icon()
anchored = 0
target = null
else
@@ -381,11 +336,11 @@ obj/machinery/bot/floorbot/process_scan(scan_target)
F.ChangeTurf(/turf/simulated/floor/plasteel)
mode = BOT_IDLE
amount -= 1
- updateicon()
+ update_icon()
anchored = 0
target = null
-/obj/machinery/bot/floorbot/proc/eattile(obj/item/stack/tile/plasteel/T)
+/mob/living/simple_animal/bot/floorbot/proc/eattile(obj/item/stack/tile/plasteel/T)
if(!istype(T, /obj/item/stack/tile/plasteel))
return
visible_message("[src] begins to collect tiles.")
@@ -402,11 +357,11 @@ obj/machinery/bot/floorbot/process_scan(scan_target)
else
amount += T.amount
qdel(T)
- updateicon()
+ update_icon()
target = null
mode = BOT_IDLE
-/obj/machinery/bot/floorbot/proc/maketile(obj/item/stack/sheet/metal/M)
+/mob/living/simple_animal/bot/floorbot/proc/maketile(obj/item/stack/sheet/metal/M)
if(!istype(M, /obj/item/stack/sheet/metal))
return
visible_message("[src] begins to create tiles.")
@@ -426,13 +381,13 @@ obj/machinery/bot/floorbot/process_scan(scan_target)
target = null
mode = BOT_IDLE
-/obj/machinery/bot/floorbot/proc/updateicon()
+/mob/living/simple_animal/bot/floorbot/update_icon()
if(amount > 0)
icon_state = "floorbot[on]"
else
icon_state = "floorbot[on]e"
-/obj/machinery/bot/floorbot/explode()
+/mob/living/simple_animal/bot/floorbot/explode()
on = 0
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
@@ -460,61 +415,15 @@ obj/machinery/bot/floorbot/process_scan(scan_target)
s.start()
..()
+/obj/machinery/bot_core/floorbot
+ req_one_access = list(access_construction, access_robotics)
-/obj/item/weapon/storage/toolbox/mechanical/attackby(obj/item/stack/tile/plasteel/T, mob/user, params)
- if(!istype(T, /obj/item/stack/tile/plasteel))
- ..()
- return
- if(contents.len >= 1)
- user << "They won't fit in, as there is already stuff inside!"
- return
- if(T.use(10))
- if(user.s_active)
- user.s_active.close(user)
- var/obj/item/weapon/toolbox_tiles/B = new /obj/item/weapon/toolbox_tiles
- user.put_in_hands(B)
- user << "You add the tiles into the empty toolbox. They protrude from the top."
- user.unEquip(src, 1)
- qdel(src)
+/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A)
+ if(isturf(A))
+ repair(A)
+ else if(istype(A,/obj/item/stack/tile/plasteel))
+ eattile(A)
+ else if(istype(A,/obj/item/stack/sheet/metal))
+ maketile(A)
else
- user << "You need 10 floor tiles to start building a floorbot!"
- return
-
-/obj/item/weapon/toolbox_tiles/attackby(obj/item/W, mob/user, params)
- ..()
- if(isprox(W))
- qdel(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 << "You add the sensor to the toolbox and tiles."
- user.unEquip(src, 1)
- qdel(src)
-
- else if (istype(W, /obj/item/weapon/pen))
- var/t = stripped_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
-
-/obj/item/weapon/toolbox_tiles_sensor/attackby(obj/item/W, mob/user, params)
- ..()
- if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
- qdel(W)
- var/turf/T = get_turf(user.loc)
- var/obj/machinery/bot/floorbot/A = new /obj/machinery/bot/floorbot(T)
- A.name = created_name
- user << "You add the robot arm to the odd looking toolbox assembly. Boop beep!"
- user.unEquip(src, 1)
- qdel(src)
- else if (istype(W, /obj/item/weapon/pen))
- var/t = stripped_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
+ ..()
diff --git a/code/game/machinery/bots/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
similarity index 72%
rename from code/game/machinery/bots/medbot.dm
rename to code/modules/mob/living/simple_animal/bot/medbot.dm
index e2aa7e2f5e1..098cc64efe6 100644
--- a/code/game/machinery/bots/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -3,7 +3,7 @@
//MEDBOT ASSEMBLY
-/obj/machinery/bot/medbot
+/mob/living/simple_animal/bot/medbot
name = "\improper Medibot"
desc = "A little medical robot. He looks somewhat underwhelmed."
icon = 'icons/obj/aibots.dmi'
@@ -12,11 +12,18 @@
density = 0
anchored = 0
health = 20
- maxhealth = 20
- req_one_access =list(access_medical, access_robotics)
- var/stunned = 0 //It can be stunned by tasers. Delicate circuits.
-// var/emagged = 0
- var/list/botcard_access = list(access_medical)
+ maxHealth = 20
+ pass_flags = PASSMOB
+
+ radio_key = /obj/item/device/encryptionkey/headset_med
+ radio_channel = "Medical"
+
+ bot_type = MED_BOT
+ model = "Medibot"
+ bot_core_type = /obj/machinery/bot_core/medbot
+ window_id = "automed"
+ window_name = "Automatic Medical Unit v1.1"
+
var/obj/item/weapon/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
var/mob/living/carbon/patient = null
@@ -30,7 +37,6 @@
var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
- radio_frequency = MED_FREQ //Medical frequency
//Setting which reagents to use to treat what by default. By id.
var/treatment_brute = "bicaridine"
var/treatment_oxy = "dexalin"
@@ -39,10 +45,8 @@
var/treatment_virus = "spaceacillin"
var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
var/shut_up = 0 //self explanatory :)
- bot_type = MED_BOT
- model = "Medibot"
-/obj/machinery/bot/medbot/mysterious
+/mob/living/simple_animal/bot/medbot/mysterious
name = "\improper Mysterious Medibot"
desc = "International Medibot of mystery."
skin = "bezerk"
@@ -51,7 +55,7 @@
treatment_fire = "tricordrazine"
treatment_tox = "tricordrazine"
-/obj/machinery/bot/medbot/derelict
+/mob/living/simple_animal/bot/medbot/derelict
name = "\improper Old Medibot"
desc = "Looks like it hasn't been modified since the late 2080s."
skin = "bezerk"
@@ -62,23 +66,7 @@
treatment_fire = "sodium_thiopental"
treatment_tox = "sodium_thiopental"
-/obj/item/weapon/firstaid_arm_assembly
- name = "incomplete medibot 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
-
- /obj/item/weapon/firstaid_arm_assembly/New()
- ..()
- spawn(5)
- if(skin)
- overlays += image('icons/obj/aibots.dmi', "kit_skin_[skin]")
-
-/obj/machinery/bot/medbot/proc/updateicon()
+/mob/living/simple_animal/bot/medbot/update_icon()
if(!on)
icon_state = "medibot0"
return
@@ -90,57 +78,47 @@
else
icon_state = "medibot1"
-/obj/machinery/bot/medbot/New()
+/mob/living/simple_animal/bot/medbot/New()
..()
- updateicon()
+ update_icon()
spawn(4)
if(skin)
overlays += image('icons/obj/aibots.dmi', "medskin_[skin]")
var/datum/job/doctor/J = new/datum/job/doctor
- botcard.access += J.get_access()
- prev_access = botcard.access
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+ var/datum/atom_hud/medsensor = huds[DATA_HUD_MEDICAL_ADVANCED]
+ medsensor.add_hud_to(src)
-/obj/machinery/bot/medbot/turn_on()
- . = ..()
- updateicon()
- updateUsrDialog()
-
-/obj/machinery/bot/medbot/turn_off()
- ..()
- updateUsrDialog()
-
-/obj/machinery/bot/medbot/bot_reset()
+/mob/living/simple_animal/bot/medbot/bot_reset()
..()
patient = null
oldpatient = null
oldloc = null
last_found = world.time
declare_cooldown = 0
- updateicon()
+ update_icon()
-/obj/machinery/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
+/mob/living/simple_animal/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
path = list()
patient = null
mode = BOT_IDLE
last_found = world.time
- updateicon()
+ update_icon()
-/obj/machinery/bot/medbot/set_custom_texts()
+/mob/living/simple_animal/bot/medbot/set_custom_texts()
text_hack = "You corrupt [name]'s reagent processor circuits."
text_dehack = "You reset [name]'s reagent processor circuits."
text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
-/obj/machinery/bot/medbot/attack_paw(mob/user)
+/mob/living/simple_animal/bot/medbot/attack_paw(mob/user)
return attack_hand(user)
-/obj/machinery/bot/medbot/attack_hand(mob/user)
- . = ..()
- if (.)
- return
+/mob/living/simple_animal/bot/medbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += "Medical Unit Controls v1.1
"
@@ -175,13 +153,10 @@
dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"]
"
dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
"
dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"]
"
+
+ return dat
- var/datum/browser/popup = new(user, "automed", "Automatic Medical Unit v1.1")
- popup.set_content(dat)
- popup.open()
- return
-
-/obj/machinery/bot/medbot/Topic(href, href_list)
+/mob/living/simple_animal/bot/medbot/Topic(href, href_list)
..()
if(href_list["adj_threshold"])
@@ -216,29 +191,16 @@
else if (href_list["stationary"])
stationary_mode = !stationary_mode
path = list()
- updateicon()
+ update_icon()
else if (href_list["virus"])
treat_virus = !treat_virus
- updateUsrDialog()
+ update_controls()
return
-/obj/machinery/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
- if (istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if (allowed(user) && !open && !emagged)
- locked = !locked
- user << "Controls are now [locked ? "locked." : "unlocked."]"
- updateUsrDialog()
- else
- if(emagged)
- user << "ERROR"
- if(open)
- user << "Please close the access panel before locking it!"
- else
- user << "Access denied."
-
- else if (istype(W, /obj/item/weapon/reagent_containers/glass))
+/mob/living/simple_animal/bot/medbot/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
+ if (istype(W, /obj/item/weapon/reagent_containers/glass))
if(locked)
user << "You cannot insert a beaker because the panel is locked!"
return
@@ -251,7 +213,7 @@
W.loc = src
reagent_glass = W
user << "You insert [W]."
- updateUsrDialog()
+ show_controls(user)
return
else
@@ -260,7 +222,7 @@
if (health < current_health) //if medbot took some damage
step_to(src, (get_step_away(src,user)))
-/obj/machinery/bot/medbot/Emag(mob/user)
+/mob/living/simple_animal/bot/medbot/Emag(mob/user)
..()
if(emagged == 2)
declare_crit = 0
@@ -272,7 +234,7 @@
if(user)
oldpatient = user
-/obj/machinery/bot/medbot/process_scan(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/medbot/process_scan(mob/living/carbon/human/H)
if (H.stat == 2)
return
@@ -289,7 +251,7 @@
else
return
-/obj/machinery/bot/medbot/bot_process()
+/mob/living/simple_animal/bot/medbot/handle_automated_action()
if (!..())
return
@@ -305,7 +267,7 @@
mode = BOT_IDLE
if(stunned <= 0)
- updateicon()
+ update_icon()
stunned = 0
return
@@ -324,7 +286,7 @@
if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
if(mode != BOT_HEALING)
mode = BOT_HEALING
- updateicon()
+ update_icon()
frustration = 0
medicate_patient(patient)
return
@@ -340,7 +302,7 @@
return
if(patient && path.len == 0 && (get_dist(src,patient) > 1))
- path = get_path_to(loc, get_turf(patient), src, /turf/proc/Distance_cardinal, 0, 30,id=botcard)
+ path = get_path_to(loc, get_turf(patient), src, /turf/proc/Distance_cardinal, 0, 30,id=access_card)
mode = BOT_MOVING
if(!path.len) //Do not chase a patient we cannot reach.
soft_reset()
@@ -363,7 +325,7 @@
return
-/obj/machinery/bot/medbot/proc/assess_patient(mob/living/carbon/C)
+/mob/living/simple_animal/bot/medbot/proc/assess_patient(mob/living/carbon/C)
//Time to see if they need medical help!
if(C.stat == 2)
return 0 //welp too late for them!
@@ -410,7 +372,18 @@
return 0
-/obj/machinery/bot/medbot/proc/medicate_patient(mob/living/carbon/C)
+/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A)
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ patient = C
+ mode = BOT_HEALING
+ update_icon()
+ medicate_patient(C)
+ update_icon()
+ else
+ ..()
+
+/mob/living/simple_animal/bot/medbot/proc/medicate_patient(mob/living/carbon/C)
if(!on)
return
@@ -477,7 +450,7 @@
C.visible_message("[src] is trying to inject [patient]!", \
"[src] is trying to inject you!")
- spawn(30)
+ spawn(30)//replace with do mob
if ((get_dist(src, patient) <= 1) && (on) && assess_patient(patient))
if(reagent_id == "internal_beaker")
if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
@@ -490,19 +463,19 @@
"[src] injects you with its syringe!")
else
visible_message("[src] retracts its syringe.")
-
+ update_icon()
soft_reset()
return
reagent_id = null
return
-/obj/machinery/bot/medbot/bullet_act(obj/item/projectile/Proj)
+/mob/living/simple_animal/bot/medbot/bullet_act(obj/item/projectile/Proj)
if(Proj.flag == "taser")
stunned = min(stunned+10,20)
..()
-/obj/machinery/bot/medbot/explode()
+/mob/living/simple_animal/bot/medbot/explode()
on = 0
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
@@ -525,79 +498,14 @@
s.start()
..()
-/obj/machinery/bot/medbot/proc/declare(crit_patient)
+/mob/living/simple_animal/bot/medbot/proc/declare(crit_patient)
if(declare_cooldown)
return
var/area/location = get_area(src)
- speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_frequency)
+ speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_channel)
declare_cooldown = 1
spawn(200) //Twenty seconds
declare_cooldown = 0
-/*
- * Medbot Assembly -- Can be made out of all three medkits.
- */
-
-/obj/item/weapon/storage/firstaid/attackby(obj/item/robot_parts/S, mob/user, params)
-
- if ((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
- ..()
- return
-
- //Making a medibot!
- if(contents.len >= 1)
- user << "You need to empty [src] out first!"
- 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"
- else if(istype(src,/obj/item/weapon/storage/firstaid/brute))
- A.skin = "brute"
-
- qdel(S)
- user.put_in_hands(A)
- user << "You add the robot arm to the first aid kit."
- user.unEquip(src, 1)
- qdel(src)
-
-
-/obj/item/weapon/firstaid_arm_assembly/attackby(obj/item/weapon/W, mob/user, params)
- ..()
- if(istype(W, /obj/item/weapon/pen))
- var/t = stripped_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))
- if(!user.unEquip(W))
- return
- qdel(W)
- build_step++
- user << "You add the health sensor to [src]."
- name = "First aid/robot arm/health analyzer assembly"
- overlays += image('icons/obj/aibots.dmi', "na_scanner")
-
- if(1)
- if(isprox(W))
- if(!user.unEquip(W))
- return
- qdel(W)
- build_step++
- user << "You complete the Medibot. Beep boop!"
- var/turf/T = get_turf(src)
- var/obj/machinery/bot/medbot/S = new /obj/machinery/bot/medbot(T)
- S.skin = skin
- S.name = created_name
- user.unEquip(src, 1)
- qdel(src)
-
+/obj/machinery/bot_core/medbot
+ req_one_access =list(access_medical, access_robotics)
diff --git a/code/game/machinery/bots/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
similarity index 75%
rename from code/game/machinery/bots/mulebot.dm
rename to code/modules/mob/living/simple_animal/bot/mulebot.dm
index 9b96447552b..cedd06e6f3e 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -6,12 +6,11 @@
var/global/mulebot_count = 0
-
#define SIGH 0
#define ANNOYED 1
#define DELIGHT 2
-/obj/machinery/bot/mulebot
+/mob/living/simple_animal/bot/mulebot
name = "\improper MULEbot"
desc = "A Multiple Utility Load Effector bot."
icon_state = "mulebot0"
@@ -20,25 +19,28 @@ var/global/mulebot_count = 0
anchored = 1
animate_movement=1
health = 150
- maxhealth = 150
- fire_dam_coeff = 0.7
- brute_dam_coeff = 0.5
- var/atom/movable/load = null
+ maxHealth = 150
+ damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ a_intent = "harm" //No swapping
+ buckle_lying = 0
+ mob_size = MOB_SIZE_LARGE
+
bot_type = MULE_BOT
model = "MULE"
- can_buckle = 1
- buckle_lying = 0
+ bot_core_type = /obj/machinery/bot_core/mulebot
+ window_id = "mulebot"
+ window_name = "M.U.L.E. Mk. V"
+ window_width = 350
+ window_height = 600
suffix = ""
+ var/atom/movable/load = null
+ var/mob/living/passenger = null
var/turf/target // this is turf to navigate to (location of beacon)
var/loaddir = 0 // this the direction to unload onto/load from
var/home_destination = "" // tag of home beacon
- req_access = list(access_cargo)
-
- mode = BOT_IDLE
-
- 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
@@ -50,24 +52,14 @@ var/global/mulebot_count = 0
var/datum/wires/mulebot/wires = null
// the installed power cell
- // constants for internal wiring bitflags
- /*
-
- var/wires = 1023 // all flags on
-
- var/list/wire_text // list of wire colours
- var/list/wire_order // order of wire indices
- */
-
-
var/bloodiness = 0 // count of bloodiness
-/obj/machinery/bot/mulebot/New()
+/mob/living/simple_animal/bot/mulebot/New()
..()
wires = new(src)
var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
- botcard.access = J.get_access()
- prev_access = botcard.access
+ access_card.access = J.get_access()
+ prev_access = access_card.access
cell = new(src)
cell.charge = 2000
cell.maxcharge = 2000
@@ -78,13 +70,13 @@ var/global/mulebot_count = 0
suffix = "#[mulebot_count]"
name = "\improper Mulebot ([suffix])"
-/obj/machinery/bot/mulebot/Destroy()
+/mob/living/simple_animal/bot/mulebot/Destroy()
unload(0)
qdel(wires)
wires = null
return ..()
-/obj/machinery/bot/mulebot/bot_reset()
+mob/living/simple_animal/bot/mulebot/bot_reset()
..()
reached_target = 0
@@ -93,18 +85,14 @@ var/global/mulebot_count = 0
// screwdriver: open/close hatch
// cell: insert it
// other: chance to knock rider off bot
-/obj/machinery/bot/mulebot/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/weapon/card/id) || istype(I, /obj/item/device/pda))
- if(toggle_lock(user))
- user << "Controls [(locked ? "locked" : "unlocked")]."
-
- else if(istype(I,/obj/item/weapon/stock_parts/cell) && open && !cell)
+/mob/living/simple_animal/bot/mulebot/attackby(obj/item/I, mob/user, params)
+ if(istype(I,/obj/item/weapon/stock_parts/cell) && open && !cell)
if(!user.drop_item())
return
var/obj/item/weapon/stock_parts/cell/C = I
C.loc = src
cell = C
- updateDialog()
+ update_controls()
else if(istype(I,/obj/item/weapon/screwdriver))
if(locked)
user << "The maintenance hatch cannot be opened or closed while the controls are locked!"
@@ -119,36 +107,44 @@ var/global/mulebot_count = 0
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 (health < maxhealth)
- health = min(maxhealth, health+25)
- user.visible_message(
- "[user] repairs [src]!",
- "You repair [src]."
- )
- else
- user << "[src] does not need a repair!"
+ update_controls()
else if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters))
if(open)
attack_hand(usr)
- 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
+ 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!"
..()
return
-/obj/machinery/bot/mulebot/emag_act(mob/user)
+/mob/living/simple_animal/bot/mulebot/emag_act(mob/user)
locked = !locked
user << "You [locked ? "lock" : "unlock"] the mulebot's controls!"
flick("mulebot-emagged", src)
playsound(loc, 'sound/effects/sparks1.ogg', 100, 0)
-/obj/machinery/bot/mulebot/ex_act(severity)
+/mob/living/simple_animal/bot/mulebot/update_icon()
+ //UNFINISHED
+ switch(mode)
+ if(BOT_IDLE)
+ icon_state = "mulebot0"
+ if(open)
+ icon_state="mulebot-hatch"
+ else
+ icon_state = "mulebot0"
+ overlays.Cut()
+ if(load && !ismob(load))//buckling handles the mob offsets
+ load.pixel_y = initial(load.pixel_y) + 9
+ if(load.layer < layer)
+ load.layer = layer + 0.1
+ overlays += load
+ return
+
+/mob/living/simple_animal/bot/mulebot/ex_act(severity)
unload(0)
switch(severity)
if(1)
@@ -160,7 +156,7 @@ var/global/mulebot_count = 0
wires.RandomCut()
return
-/obj/machinery/bot/mulebot/bullet_act(obj/item/projectile/Proj)
+/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
if(..())
if(prob(50) && !isnull(load))
unload(0)
@@ -169,18 +165,11 @@ var/global/mulebot_count = 0
wires.RandomCut()
-/obj/machinery/bot/mulebot/attack_ai(mob/user)
- user.set_machine(src)
- interact(user, 1)
+/mob/living/simple_animal/bot/mulebot/attack_ai(mob/user)
+ show_controls(user)
-/obj/machinery/bot/mulebot/attack_hand(mob/user)
- . = ..()
- if (.)
- return
- user.set_machine(src)
- interact(user, 0)
-
-/obj/machinery/bot/mulebot/interact(mob/user, ai=0)
+/mob/living/simple_animal/bot/mulebot/get_controls(mob/user)
+ var/ai = issilicon(user)
var/dat
dat += "Multiple Utility Load Effector Mk. V
"
dat += "ID: [suffix]
"
@@ -244,31 +233,24 @@ var/global/mulebot_count = 0
else
dat += "The bot is in maintenance mode and cannot be controlled.
"
- //user << browse("M.U.L.E. Mk. III [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500")
- //onclose(user, "mulebot")
- var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. V [suffix ? "([suffix])" : ""]", 350, 600)
- popup.set_content(dat)
- popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
- popup.open()
- return
+ return dat
// returns the wire panel text
-/obj/machinery/bot/mulebot/proc/wires()
+/mob/living/simple_animal/bot/mulebot/proc/wires()
return wires.GetInteractWindow()
-/obj/machinery/bot/mulebot/Topic(href, href_list)
+/mob/living/simple_animal/bot/mulebot/Topic(href, href_list)
if(..())
return
if (usr.stat)
return
if ((in_range(src, usr) && istype(loc, /turf)) || (istype(usr, /mob/living/silicon)))
- usr.set_machine(src)
-
switch(href_list["op"])
if("lock", "unlock")
- toggle_lock(usr)
+ locked = !locked
+ update_controls()
if("power")
if (on)
@@ -280,7 +262,7 @@ var/global/mulebot_count = 0
else
return
visible_message("[usr] switches [on ? "on" : "off"] [src].")
- updateDialog()
+ update_controls()
if("cellremove")
@@ -291,7 +273,7 @@ var/global/mulebot_count = 0
cell = null
usr.visible_message("[usr] removes the power cell from [src].", "You remove the power cell from [src].")
- updateDialog()
+ update_controls()
if("cellinsert")
if(open && !cell)
@@ -304,19 +286,13 @@ var/global/mulebot_count = 0
C.add_fingerprint(usr)
usr.visible_message("[usr] inserts a power cell into [src].", "You insert the power cell into [src].")
- updateDialog()
+ update_controls()
else
bot_control(href_list["op"], usr)
-
-
- updateDialog()
- //updateUsrDialog()
- else
- usr << browse(null, "window=mulebot")
- usr.unset_machine()
+ update_controls()
return
-/obj/machinery/bot/mulebot/bot_control(command, mob/user, pda= 0)
+/mob/living/simple_animal/bot/mulebot/bot_control(command, mob/user, pda= 0)
if(pda && !wires.RemoteRX()) //MULE wireless is controlled by wires.
return
@@ -324,22 +300,22 @@ var/global/mulebot_count = 0
if("autorefresh")
refresh = !refresh
- updateDialog()
+ update_controls()
if("stop")
if(mode >= BOT_DELIVER)
bot_reset()
- updateDialog()
+ update_controls()
if("go")
if(mode == BOT_IDLE)
start()
- updateDialog()
+ update_controls()
if("home")
if(mode == BOT_IDLE || mode == BOT_DELIVER)
start_home()
- updateDialog()
+ update_controls()
if("destination")
refresh=0
@@ -356,7 +332,7 @@ var/global/mulebot_count = 0
if(new_id)
suffix = new_id
name = "\improper Mulebot ([suffix])"
- updateDialog()
+ update_controls()
if("sethome")
refresh=0
@@ -364,7 +340,7 @@ var/global/mulebot_count = 0
refresh=1
if(new_home)
home_destination = new_home
- updateDialog()
+ update_controls()
if("unload")
if(load && mode != BOT_HUNT)
@@ -389,19 +365,10 @@ var/global/mulebot_count = 0
// returns true if the bot has power
-/obj/machinery/bot/mulebot/proc/has_power()
+/mob/living/simple_animal/bot/mulebot/proc/has_power()
return !open && cell && cell.charge > 0 && wires.HasPower()
-/obj/machinery/bot/mulebot/proc/toggle_lock(mob/user)
- if(allowed(user))
- locked = !locked
- updateDialog()
- return 1
- else
- user << "Access denied."
- return 0
-
-/obj/machinery/bot/mulebot/proc/buzz(type)
+/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
switch(type)
if(SIGH)
audible_message("[src] makes a sighing buzz.", "You hear an electronic buzzing sound.")
@@ -416,7 +383,7 @@ var/global/mulebot_count = 0
// mousedrop a crate to load the bot
// can load anything if emagged
-/obj/machinery/bot/mulebot/MouseDrop_T(atom/movable/AM, mob/user)
+/mob/living/simple_animal/bot/mulebot/MouseDrop_T(atom/movable/AM, mob/user)
if(user.incapacitated() || user.lying)
return
@@ -427,7 +394,7 @@ var/global/mulebot_count = 0
load(AM)
// called to load a crate
-/obj/machinery/bot/mulebot/proc/load(atom/movable/AM)
+/mob/living/simple_animal/bot/mulebot/proc/load(atom/movable/AM)
if(load || AM.anchored)
return
@@ -452,32 +419,26 @@ var/global/mulebot_count = 0
return
if(isliving(AM))
- if(!buckle_mob(AM))
+ if(!load_mob(AM))
return
else
AM.loc = src
- AM.pixel_y += 9
- if(AM.layer < layer)
- AM.layer = layer + 0.1
- overlays += AM
- load= AM
+ load = AM
mode = BOT_IDLE
+ update_icon()
-/obj/machinery/bot/mulebot/buckle_mob(mob/living/M, force = 0)
+/mob/living/simple_animal/bot/mulebot/proc/load_mob(mob/living/M)
if(M.buckled)
return 0
- var/turf/T = get_turf(src)
- if(M.loc != T)
- density = 0
- var/can_step = step_towards(M, T)
- density = 1
- if(!can_step)
- return 0
- return ..()
+ passenger = M
+ load = M
+ can_buckle = 1
+ buckle_mob(M)
+ can_buckle = 0
+ return 1
-
-/obj/machinery/bot/mulebot/post_buckle_mob(mob/living/M)
+/mob/living/simple_animal/bot/mulebot/post_buckle_mob(mob/living/M)
if(M == buckled_mob) //post buckling
M.pixel_y = initial(M.pixel_y) + 9
if(M.layer < layer)
@@ -488,11 +449,10 @@ var/global/mulebot_count = 0
M.layer = initial(M.layer)
M.pixel_y = initial(M.pixel_y)
-
// called to unload the bot
// argument is optional direction to unload
// if zero, unload at bot's location
-/obj/machinery/bot/mulebot/proc/unload(dirn)
+/mob/living/simple_animal/bot/mulebot/proc/unload(dirn)
if(!load)
return
@@ -500,24 +460,22 @@ var/global/mulebot_count = 0
overlays.Cut()
- if(buckled_mob)
- unbuckle_mob()
- return
+ unbuckle_mob()
- load.loc = loc
- load.pixel_y = initial(load.pixel_y)
- load.layer = initial(load.layer)
- if(dirn)
- var/turf/T = loc
- var/turf/newT = get_step(T,dirn)
- if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally
- step(load, dirn)
-
- load = null
+ if(load)
+ load.loc = loc
+ load.pixel_y = initial(load.pixel_y)
+ load.layer = initial(load.layer)
+ if(dirn)
+ var/turf/T = loc
+ var/turf/newT = get_step(T,dirn)
+ if(load.CanPass(load,newT)) //Can't get off onto anything that wouldn't let you pass normally
+ step(load, dirn)
+ load = null
-/obj/machinery/bot/mulebot/call_bot()
+/mob/living/simple_animal/bot/mulebot/call_bot()
..()
var/area/dest_area
if (path && path.len)
@@ -527,7 +485,7 @@ var/global/mulebot_count = 0
pathset = 1 //Indicates the AI's custom path is initialized.
start()
-/obj/machinery/bot/mulebot/bot_process()
+/mob/living/simple_animal/bot/mulebot/handle_automated_action()
if(!has_power())
on = 0
return
@@ -548,13 +506,15 @@ var/global/mulebot_count = 0
if(num_steps)
process_bot()
num_steps--
- for(var/i=num_steps,i>0,i--)
- sleep(2)
- process_bot()
+ if(mode != BOT_IDLE)
+ spawn(0)
+ for(var/i=num_steps,i>0,i--)
+ sleep(2)
+ process_bot()
- if(refresh) updateDialog()
+ if(refresh) update_controls()
-/obj/machinery/bot/mulebot/proc/process_bot()
+/mob/living/simple_animal/bot/mulebot/proc/process_bot()
if(!on)
return
@@ -598,16 +558,14 @@ var/global/mulebot_count = 0
bloodiness--
-
+ var/oldloc = loc
var/moved = step_towards(src, next) // attempt to move
if(cell) cell.use(1)
- if(moved) // successful move
+ if(moved && oldloc!=loc) // successful move
//world << "Successful move."
blockcount = 0
path -= loc
-
-
if(destination == home_destination)
mode = BOT_GO_HOME
else
@@ -616,9 +574,6 @@ var/global/mulebot_count = 0
else // failed to move
//world << "Unable to move."
-
-
-
blockcount++
mode = BOT_BLOCKED
if(blockcount == 3)
@@ -650,7 +605,6 @@ var/global/mulebot_count = 0
//world << "Calc new path."
mode = BOT_WAIT_FOR_NAV
spawn(0)
-
calc_path()
if(path.len > 0)
@@ -663,23 +617,22 @@ var/global/mulebot_count = 0
mode = BOT_NO_ROUTE
-
// calculates a path to the current destination
// given an optional turf to avoid
-/obj/machinery/bot/mulebot/calc_path(turf/avoid = null)
- path = get_path_to(loc, target, src, /turf/proc/Distance_cardinal, 0, 250, id=botcard, exclude=avoid)
+/mob/living/simple_animal/bot/mulebot/calc_path(turf/avoid = null)
+ path = get_path_to(loc, target, src, /turf/proc/Distance_cardinal, 0, 250, id=access_card, exclude=avoid)
// 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(new_dest)
+/mob/living/simple_animal/bot/mulebot/proc/set_destination(new_dest)
new_destination = new_dest
get_nav()
- updateDialog()
+ update_controls()
// starts bot moving to current destination
-/obj/machinery/bot/mulebot/proc/start()
+/mob/living/simple_animal/bot/mulebot/proc/start()
if(!on)
return
if(destination == home_destination)
@@ -691,7 +644,7 @@ var/global/mulebot_count = 0
// starts bot moving to home
// sends a beacon query to find
-/obj/machinery/bot/mulebot/proc/start_home()
+/mob/living/simple_animal/bot/mulebot/proc/start_home()
if(!on)
return
spawn(0)
@@ -700,9 +653,9 @@ var/global/mulebot_count = 0
icon_state = "mulebot[(wires.MobAvoid() != 0)]"
// called when bot reaches current target
-/obj/machinery/bot/mulebot/proc/at_target()
+/mob/living/simple_animal/bot/mulebot/proc/at_target()
if(!reached_target)
- radio_frequency = SUPP_FREQ //Supply channel
+ radio_channel = "Supply" //Supply channel
audible_message("[src] makes a chiming sound!", "You hear a chime.")
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
reached_target = 1
@@ -713,11 +666,11 @@ var/global/mulebot_count = 0
calling_ai << "\icon[src] [src] wirelessly plays a chiming sound!"
playsound(calling_ai, 'sound/machines/chime.ogg',40, 0)
calling_ai = null
- radio_frequency = AIPRIV_FREQ //Report on AI Private instead if the AI is controlling us.
+ radio_channel = "AI Private" //Report on AI Private instead if the AI is controlling us.
if(load) // if loaded, unload at target
if(report_delivery)
- speak("Destination [destination] reached. Unloading [load].",radio_frequency)
+ speak("Destination [destination] reached. Unloading [load].",radio_channel)
unload(loaddir)
else
// not loaded
@@ -733,10 +686,10 @@ var/global/mulebot_count = 0
if(AM && AM.Adjacent(src))
load(AM)
if(report_delivery)
- speak("Now loading [load] at [get_area(src)].", radio_frequency)
+ speak("Now loading [load] at [get_area(src)].", radio_channel)
// whatever happened, check to see if we return home
- if(auto_return && destination != home_destination)
+ if(auto_return && home_destination && destination != home_destination)
// auto return set and not at home already
start_home()
mode = BOT_BLOCKED
@@ -746,7 +699,7 @@ var/global/mulebot_count = 0
return
// called when bot bumps into anything
-/obj/machinery/bot/mulebot/Bump(atom/obs)
+/mob/living/simple_animal/bot/mulebot/Bump(atom/obs)
if(!wires.MobAvoid()) //usually just bumps, but if avoidance disabled knock over mobs
var/mob/M = obs
if(ismob(M))
@@ -759,13 +712,9 @@ var/global/mulebot_count = 0
M.Weaken(5)
return ..()
-/obj/machinery/bot/mulebot/alter_health()
- return get_turf(src)
-
-
// called from mob/living/carbon/human/Crossed()
// when mulebot is in the same loc
-/obj/machinery/bot/mulebot/proc/RunOver(mob/living/carbon/human/H)
+/mob/living/simple_animal/bot/mulebot/proc/RunOver(mob/living/carbon/human/H)
H.visible_message("[src] drives over [H]!", \
"[src] drives over you!")
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
@@ -784,7 +733,7 @@ var/global/mulebot_count = 0
bloodiness += 4
// player on mulebot attempted to move
-/obj/machinery/bot/mulebot/relaymove(mob/user)
+/mob/living/simple_animal/bot/mulebot/relaymove(mob/user)
if(user.incapacitated())
return
if(load == user)
@@ -792,7 +741,7 @@ var/global/mulebot_count = 0
//Update navigation data. Called when commanded to deliver, return home, or a route update is needed...
-/obj/machinery/bot/mulebot/proc/get_nav()
+/mob/living/simple_animal/bot/mulebot/proc/get_nav()
//Formerly the beacon reception proc, except that it is no longer a potential lag bomb called TEN TIMES A SECOND OR MORE in some cases!
if(!on || !wires.BeaconRX())
return
@@ -810,9 +759,9 @@ var/global/mulebot_count = 0
icon_state = "mulebot[(wires.MobAvoid() != null)]"
if(destination) // No need to calculate a path if you do not have a destination set!
calc_path()
- updateDialog()
+ update_controls()
-/obj/machinery/bot/mulebot/emp_act(severity)
+/mob/living/simple_animal/bot/mulebot/emp_act(severity)
if (cell)
cell.emp_act(severity)
if(load)
@@ -820,7 +769,7 @@ var/global/mulebot_count = 0
..()
-/obj/machinery/bot/mulebot/explode()
+/mob/living/simple_animal/bot/mulebot/explode()
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
@@ -840,6 +789,15 @@ var/global/mulebot_count = 0
new /obj/effect/decal/cleanable/oil(loc)
..()
+/mob/living/simple_animal/bot/mulebot/remove_air(amount) //To prevent riders suffocating
+ if(loc)
+ return loc.remove_air(amount)
+ else
+ return null
+
#undef SIGH
#undef ANNOYED
#undef DELIGHT
+
+/obj/machinery/bot_core/mulebot
+ req_access = list(access_cargo)
diff --git a/code/game/machinery/bots/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
similarity index 66%
rename from code/game/machinery/bots/secbot.dm
rename to code/modules/mob/living/simple_animal/bot/secbot.dm
index 2fdb4c03990..d49073e4bcf 100644
--- a/code/game/machinery/bots/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -1,76 +1,68 @@
-/obj/machinery/bot/secbot
+/mob/living/simple_animal/bot/secbot
name = "\improper Securitron"
desc = "A little security robot. He looks less than thrilled."
icon = 'icons/obj/aibots.dmi'
icon_state = "secbot0"
layer = 5
- density = 0
+ density = 1
anchored = 0
health = 25
- maxhealth = 25
- fire_dam_coeff = 0.7
- brute_dam_coeff = 0.5
-// weight = 1.0E7
- req_access = list(access_security)
+ maxHealth = 25
+ damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+
+ radio_key = /obj/item/device/encryptionkey/headset_sec
+ radio_channel = "Security" //Security channel
+ bot_type = SEC_BOT
+ model = "Securitron"
+ bot_core_type = /obj/machinery/bot_core/secbot
+ window_id = "autosec"
+ window_name = "Automatic Security Unit v1.6"
+
var/mob/living/carbon/target
var/oldtarget_name
var/threatlevel = 0
var/target_lastloc //Loc of target when arrested.
var/last_found //There's a delay
-// var/emagged = 0 //Emagged Secbots view everyone as a criminal
var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
var/idcheck = 0 //If true, arrest people with no IDs
var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
var/check_records = 1 //Does it check security records?
var/arrest_type = 0 //If true, don't handcuff
- radio_frequency = SEC_FREQ //Security channel
- bot_type = SEC_BOT
- model = "Securitron"
-/obj/machinery/bot/secbot/beepsky
+/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
idcheck = 0
weaponscheck = 0
auto_patrol = 1
-/obj/machinery/bot/secbot/pingsky
+/mob/living/simple_animal/bot/secbot/pingsky
name = "Officer Pingsky"
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
- radio_frequency = AIPRIV_FREQ
+ radio_channel = "AI Private"
-/obj/item/weapon/secbot_assembly
- name = "incomplete securitron assembly"
- desc = "Some sort of bizarre assembly made from a proximity sensor, helmet, and signaler."
- icon = 'icons/obj/aibots.dmi'
- icon_state = "helmet_signaler"
- item_state = "helmet"
- var/build_step = 0
- var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
-
-
-
-/obj/machinery/bot/secbot/New()
+/mob/living/simple_animal/bot/secbot/New()
..()
icon_state = "secbot[on]"
spawn(3)
var/datum/job/detective/J = new/datum/job/detective
- botcard.access += J.get_access()
- prev_access = botcard.access
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+ //SECHUD
+ var/datum/atom_hud/secsensor = huds[DATA_HUD_SECURITY_ADVANCED]
+ secsensor.add_hud_to(src)
-/obj/machinery/bot/secbot/turn_on()
+/mob/living/simple_animal/bot/secbot/turn_on()
..()
icon_state = "secbot[on]"
- updateUsrDialog()
-/obj/machinery/bot/secbot/turn_off()
+/mob/living/simple_animal/bot/secbot/turn_off()
..()
icon_state = "secbot[on]"
- updateUsrDialog()
-/obj/machinery/bot/secbot/bot_reset()
+/mob/living/simple_animal/bot/secbot/bot_reset()
..()
target = null
oldtarget_name = null
@@ -78,20 +70,13 @@
walk_to(src,0)
last_found = world.time
-/obj/machinery/bot/secbot/set_custom_texts()
+/mob/living/simple_animal/bot/secbot/set_custom_texts()
text_hack = "You overload [name]'s target identification system."
text_dehack = "You reboot [name] and restore the target identification."
text_dehack_fail = "[name] refuses to accept your authority!"
-/obj/machinery/bot/secbot/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- usr.set_machine(src)
- interact(user)
-
-/obj/machinery/bot/secbot/interact(mob/user)
+/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
var/dat
dat += hack(user)
dat += text({"
@@ -117,58 +102,42 @@ Auto Patrol: []"},
"[arrest_type ? "Detain" : "Arrest"]",
"[declare_arrests ? "Yes" : "No"]",
"[auto_patrol ? "On" : "Off"]" )
+
+ return dat
- var/datum/browser/popup = new(user, "autosec", "Automatic Security Unit v1.6")
- popup.set_content(dat)
- popup.open()
- return
-
-/obj/machinery/bot/secbot/Topic(href, href_list)
+/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
..()
switch(href_list["operation"])
if("idcheck")
idcheck = !idcheck
- updateUsrDialog()
+ update_controls()
if("weaponscheck")
weaponscheck = !weaponscheck
- updateUsrDialog()
+ update_controls()
if("ignorerec")
check_records = !check_records
- updateUsrDialog()
+ update_controls()
if("switchmode")
arrest_type = !arrest_type
- updateUsrDialog()
+ update_controls()
if("declarearrests")
declare_arrests = !declare_arrests
- updateUsrDialog()
+ update_controls()
+/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
+ return
+ if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
+ threatlevel = user.assess_threat(src)
+ threatlevel += 6
+ if(threatlevel >= 4)
+ target = user
+ mode = BOT_HUNT
-/obj/machinery/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
- if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda))
- if(allowed(user) && !open && !emagged)
- locked = !locked
- user << "Controls are now [locked ? "locked." : "unlocked."]"
- else
- if(emagged)
- user << "ERROR"
- if(open)
- user << "Please close the access panel before locking it."
- else
- user << "Access denied."
- else
- ..()
- if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != "harm") // Any intent but harm will heal, so we shouldn't get angry.
- return
- if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
- threatlevel = user.assess_threat(src)
- threatlevel += 6
- if(threatlevel >= 4)
- target = user
- mode = BOT_HUNT
-
-/obj/machinery/bot/secbot/Emag(mob/user)
+/mob/living/simple_animal/bot/secbot/Emag(mob/user)
..()
if(emagged == 2)
@@ -179,7 +148,7 @@ Auto Patrol: []"},
declare_arrests = 0
icon_state = "secbot[on]"
-/obj/machinery/bot/secbot/bullet_act(obj/item/projectile/Proj)
+/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if (!Proj.nodamage && Proj.damage < src.health)
@@ -190,7 +159,55 @@ Auto Patrol: []"},
mode = BOT_HUNT
..()
-/obj/machinery/bot/secbot/bot_process()
+
+/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ if(!C.stunned || arrest_type)
+ stun_attack(A)
+ else if(C.canBeHandcuffed() && !C.handcuffed)
+ cuff(A)
+ else
+ ..()
+
+/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
+ mode = BOT_ARREST
+ playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
+ C.visible_message("[src] is trying to put zipties on [C]!",\
+ "[src] is trying to put zipties on you!")
+ spawn(60)
+ if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
+ return
+ if(!C.handcuffed)
+ C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
+ C.update_inv_handcuffed(0) //update the handcuffs overlay
+ playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
+ back_to_idle()
+
+/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
+ playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
+ icon_state = "secbot-c"
+ spawn(2)
+ icon_state = "secbot[on]"
+ var/threat = 5
+ if(istype(C, /mob/living/carbon/human))
+ C.stuttering = 5
+ C.Stun(5)
+ C.Weaken(5)
+ var/mob/living/carbon/human/H = C
+ threat = H.assess_threat(src)
+ else
+ C.Weaken(5)
+ C.stuttering = 5
+ C.Stun(5)
+
+ if(declare_arrests)
+ var/area/location = get_area(src)
+ speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
+ C.visible_message("[src] has stunned [C]!",\
+ "[src] has stunned you!")
+
+/mob/living/simple_animal/bot/secbot/handle_automated_action()
if (!..())
return
@@ -213,29 +230,11 @@ Auto Patrol: []"},
if(target) // make sure target exists
if(Adjacent(target) && isturf(target.loc)) // if right next to perp
- playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
- icon_state = "secbot-c"
- spawn(2)
- icon_state = "secbot[on]"
- var/mob/living/carbon/M = target
- if(istype(M, /mob/living/carbon/human))
- M.stuttering = 5
- M.Stun(5)
- M.Weaken(5)
- else
- M.Weaken(5)
- M.stuttering = 5
- M.Stun(5)
-
- if(declare_arrests)
- var/area/location = get_area(src)
- speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_frequency)
- target.visible_message("[src] has stunned [target]!",\
- "[src] has stunned you!")
+ stun_attack(target)
mode = BOT_PREP_ARREST
anchored = 1
- target_lastloc = M.loc
+ target_lastloc = target.loc
return
else // not next to perp
@@ -258,18 +257,7 @@ Auto Patrol: []"},
if(iscarbon(target) && target.canBeHandcuffed())
if(!arrest_type)
if(!target.handcuffed) //he's not cuffed? Try to cuff him!
- mode = BOT_ARREST
- playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
- target.visible_message("[src] is trying to put zipties on [target]!",\
- "[src] is trying to put zipties on you!")
- spawn(60)
- if( !Adjacent(target) || !isturf(target.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
- return
- if(!target.handcuffed)
- target.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(target)
- target.update_inv_handcuffed(0) //update the handcuffs overlay
- playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
- back_to_idle()
+ cuff(target)
else
back_to_idle()
return
@@ -307,24 +295,24 @@ Auto Patrol: []"},
return
-/obj/machinery/bot/secbot/proc/back_to_idle()
+/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
anchored = 0
mode = BOT_IDLE
target = null
last_found = world.time
frustration = 0
spawn(0)
- bot_process() //ensure bot quickly responds
+ handle_automated_action() //ensure bot quickly responds
-/obj/machinery/bot/secbot/proc/back_to_hunt()
+/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
anchored = 0
frustration = 0
mode = BOT_HUNT
spawn(0)
- bot_process() //ensure bot quickly responds
+ handle_automated_action() //ensure bot quickly responds
// look for a criminal in view of the bot
-/obj/machinery/bot/secbot/proc/look_for_perp()
+/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
anchored = 0
for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
if((C.stat) || (C.handcuffed))
@@ -346,16 +334,16 @@ Auto Patrol: []"},
visible_message("[src] points at [C.name]!")
mode = BOT_HUNT
spawn(0)
- bot_process() // ensure bot quickly responds to a perp
+ handle_automated_action() // ensure bot quickly responds to a perp
break
else
continue
-/obj/machinery/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
+/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
if(slot_item && slot_item.needs_permit)
return 1
return 0
-/obj/machinery/bot/secbot/explode()
+/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
visible_message("[src] blows apart!")
@@ -378,13 +366,13 @@ Auto Patrol: []"},
new /obj/effect/decal/cleanable/oil(loc)
..()
-/obj/machinery/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
+/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
..()
if(!isalien(target))
target = user
mode = BOT_HUNT
-/obj/machinery/bot/secbot/Crossed(atom/movable/AM)
+/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
if(ismob(AM) && target)
var/mob/living/carbon/C = AM
if(!istype(C) || !C || in_range(src, target))
@@ -464,7 +452,7 @@ Auto Patrol: []"},
return
build_step++
user << "You complete the Securitron! Beep boop."
- var/obj/machinery/bot/secbot/S = new /obj/machinery/bot/secbot(get_turf(src))
+ var/mob/living/simple_animal/bot/secbot/S = new/mob/living/simple_animal/bot/secbot(get_turf(src))
S.name = created_name
qdel(I)
qdel(src)
@@ -494,4 +482,7 @@ Auto Patrol: []"},
overlays -= "hs_arm"
new /obj/item/robot_parts/l_arm(get_turf(src))
user << "You remove the robot arm from [src]."
- build_step--
\ No newline at end of file
+ build_step--
+
+/obj/machinery/bot_core/secbot
+ req_access = list(access_security)
diff --git a/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm b/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm
index 70f84ceea60..378bea51011 100644
--- a/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm
+++ b/code/modules/mob/living/simple_animal/bot_swarm/swarmer.dm
@@ -50,7 +50,7 @@
melee_damage_lower = 15
melee_damage_upper = 15
melee_damage_type = STAMINA
- ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1)
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
languages = SWARMER
environment_smash = 0
attacktext = "shocks"
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index bf08c51dce2..18e07e4b2a9 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -38,7 +38,7 @@
languages = DRONE
mob_size = MOB_SIZE_SMALL
has_unlimited_silicon_privilege = 1
- ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) // 0 to receive that damage type, 1 to ignore
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
staticOverlays = list()
var/staticChoice = "static"
var/list/staticChoices = list("static", "blank", "letter")
diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/modules/mob/living/simple_animal/revenant/revenant.dm
index 7e52f96962c..1ac81e4e6b4 100644
--- a/code/modules/mob/living/simple_animal/revenant/revenant.dm
+++ b/code/modules/mob/living/simple_animal/revenant/revenant.dm
@@ -27,7 +27,7 @@
response_disarm = "swings at"
response_harm = "punches through"
unsuitable_atmos_damage = 0
- ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 1, CLONE = 1, STAMINA = 1, OXY = 1) //I don't know how you'd apply those, but revenants no-sell them anyway.
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway.
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
diff --git a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm b/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm
index e29d3962b71..c3a219eb6ce 100644
--- a/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm
+++ b/code/modules/mob/living/simple_animal/revenant/revenant_abilities.dm
@@ -181,7 +181,7 @@
if(attempt_cast(user))
for(var/turf/T in targets)
spawn(0)
- for(var/obj/machinery/bot/bot in T.contents)
+ for(var/mob/living/simple_animal/bot/bot in T.contents)
if(!bot.emagged)
PoolOrNew(/obj/effect/overlay/temp/revenant, bot.loc)
bot.locked = 0
@@ -194,7 +194,7 @@
PoolOrNew(/obj/effect/overlay/temp/revenant, human.loc)
human.emp_act(1)
for(var/obj/thing in T.contents)
- if(istype(thing, /obj/machinery/dominator) || istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes) || istype(thing, /obj/machinery/bot)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
+ if(istype(thing, /obj/machinery/dominator) || istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
continue
if(prob(20))
if(prob(50))
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 5e6c14e5df5..e53304b5381 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -45,7 +45,7 @@
var/melee_damage_upper = 0
var/armour_penetration = 0 //How much armour they ignore, as a flat reduction from the targets armour value
var/melee_damage_type = BRUTE //Damage type of a simple mob's melee attack, should it do damage.
- var/list/ignored_damage_types = list(BRUTE = 0, BURN = 0, TOX = 0, CLONE = 0, STAMINA = 1, OXY = 0) //Set 0 to receive that damage type, 1 to ignore
+ var/list/damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) // 1 for full damage , 0 for none , -1 for 1:1 heal from that source
var/attacktext = "attacks"
var/attack_sound = null
var/friendly = "nuzzles" //If the mob does no damage with it's attack
@@ -67,6 +67,8 @@
var/mob/living/simple_animal/hostile/spawner/nest
+ var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions
+
/mob/living/simple_animal/New()
..()
verbs -= /mob/verb/observe
@@ -271,20 +273,20 @@
return 0
/mob/living/simple_animal/adjustBruteLoss(amount)
- if(!ignored_damage_types[BRUTE])
- ..()
+ if(damage_coeff[BRUTE])
+ ..(amount*damage_coeff[BRUTE])
/mob/living/simple_animal/adjustFireLoss(amount)
- if(!ignored_damage_types[BURN])
- adjustBruteLoss(amount)
+ if(damage_coeff[BURN])
+ adjustBruteLoss(amount*damage_coeff[BURN])
/mob/living/simple_animal/adjustToxLoss(amount)
- if(!ignored_damage_types[TOX])
- ..(amount)
+ if(damage_coeff[TOX])
+ ..(amount*damage_coeff[TOX])
/mob/living/simple_animal/adjustCloneLoss(amount)
- if(!ignored_damage_types[CLONE])
- ..(amount)
+ if(damage_coeff[CLONE])
+ ..(amount*damage_coeff[CLONE])
/mob/living/simple_animal/adjustStaminaLoss(amount)
return
@@ -356,7 +358,7 @@
return 1
/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE)
- if(damage <= force_threshold || ignored_damage_types[damagetype])
+ if(damage <= force_threshold || !damage_coeff[damagetype])
visible_message("[src] looks unharmed.")
else
adjustBruteLoss(damage)
@@ -506,4 +508,4 @@
if(nest)
nest.spawned_mobs -= src
nest = null
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 7987ef2716e..e9275ebd71c 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -22,7 +22,7 @@
/obj/item/weapon/storage,
/obj/machinery/atmospherics/components/unary/cryo_cell,
/obj/item/weapon/grenade/chem_grenade,
- /obj/machinery/bot/medbot,
+ /mob/living/simple_animal/bot/medbot,
/obj/machinery/computer/pandemic,
/obj/structure/safe,
/obj/machinery/disposal,
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 6bbcfa5f086..ad6483d7408 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -162,6 +162,7 @@
origin_tech = "biotech=5"
var/list/not_interested = list()
var/being_used = 0
+ var/sentience_type = SENTIENCE_ORGANIC
/obj/item/slimepotion/sentience/afterattack(mob/living/M, mob/user)
if(being_used || !ismob(M))
@@ -172,6 +173,12 @@
if(M.stat)
user << "[M] is dead!"
return..()
+ var/mob/living/simple_animal/SM = M
+ if(SM.sentience_type != sentience_type)
+ user << "The potion won't work on [M]."
+ return ..()
+
+
user << "You offer the sentience potion to [M]..."
being_used = 1
diff --git a/tgstation.dme b/tgstation.dme
index dcd7fa82404..1b3e0accfb8 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -142,7 +142,6 @@
#include "code\controllers\subsystems.dm"
#include "code\controllers\verbs.dm"
#include "code\controllers\subsystem\air.dm"
-#include "code\controllers\subsystem\bots.dm"
#include "code\controllers\subsystem\diseases.dm"
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\garbage.dm"
@@ -461,13 +460,6 @@
#include "code\game\machinery\atmoalter\pump.dm"
#include "code\game\machinery\atmoalter\scrubber.dm"
#include "code\game\machinery\atmoalter\zvent.dm"
-#include "code\game\machinery\bots\bots.dm"
-#include "code\game\machinery\bots\cleanbot.dm"
-#include "code\game\machinery\bots\ed209bot.dm"
-#include "code\game\machinery\bots\floorbot.dm"
-#include "code\game\machinery\bots\medbot.dm"
-#include "code\game\machinery\bots\mulebot.dm"
-#include "code\game\machinery\bots\secbot.dm"
#include "code\game\machinery\camera\camera.dm"
#include "code\game\machinery\camera\camera_assembly.dm"
#include "code\game\machinery\camera\motion.dm"
@@ -1283,6 +1275,14 @@
#include "code\modules\mob\living\simple_animal\shade.dm"
#include "code\modules\mob\living\simple_animal\simple_animal.dm"
#include "code\modules\mob\living\simple_animal\spawner.dm"
+#include "code\modules\mob\living\simple_animal\bot\bot.dm"
+#include "code\modules\mob\living\simple_animal\bot\cleanbot.dm"
+#include "code\modules\mob\living\simple_animal\bot\construction.dm"
+#include "code\modules\mob\living\simple_animal\bot\ed209bot.dm"
+#include "code\modules\mob\living\simple_animal\bot\floorbot.dm"
+#include "code\modules\mob\living\simple_animal\bot\medbot.dm"
+#include "code\modules\mob\living\simple_animal\bot\mulebot.dm"
+#include "code\modules\mob\living\simple_animal\bot\secbot.dm"
#include "code\modules\mob\living\simple_animal\bot_swarm\swarmer.dm"
#include "code\modules\mob\living\simple_animal\bot_swarm\swarmer_event.dm"
#include "code\modules\mob\living\simple_animal\friendly\butterfly.dm"