From e36853d7c9fc883b267e024094ab1022348bfe7e Mon Sep 17 00:00:00 2001 From: AnturK Date: Thu, 26 Nov 2015 22:04:47 +0100 Subject: [PATCH] Convert bots to simple animals - Updated 7.0 --- code/__DEFINES/is_helpers.dm | 2 + code/__DEFINES/misc.dm | 14 +- code/_onclick/observer.dm | 2 +- code/controllers/subsystem/bots.dm | 22 - code/datums/spells/conjure.dm | 4 +- code/datums/supplypacks.dm | 10 +- code/datums/wires/mulebot.dm | 8 +- code/game/asteroid.dm | 2 +- code/game/gamemodes/sandbox/h_sandbox.dm | 6 +- code/game/machinery/computer/medical.dm | 2 +- code/game/machinery/doors/door.dm | 7 - code/game/machinery/doors/windowdoor.dm | 8 +- code/game/machinery/portable_turret.dm | 2 +- code/game/objects/items/devices/PDA/cart.dm | 10 +- .../crates_lockers/closets/secure/misc.dm | 2 +- code/game/objects/structures/plasticflaps.dm | 4 +- code/modules/crafting/recipes.dm | 10 +- code/modules/events/ion_storm.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 6 +- code/modules/mob/living/carbon/life.dm | 1 - .../mob/living/carbon/monkey/monkey.dm | 2 +- code/modules/mob/living/silicon/ai/ai.dm | 8 +- .../mob/living/simple_animal/bot/bot.dm} | 519 ++++++++++-------- .../mob/living/simple_animal/bot}/cleanbot.dm | 138 ++--- .../living/simple_animal/bot/construction.dm | 462 ++++++++++++++++ .../mob/living/simple_animal/bot}/ed209bot.dm | 396 +++++-------- .../mob/living/simple_animal/bot}/floorbot.dm | 201 ++----- .../mob/living/simple_animal/bot}/medbot.dm | 220 +++----- .../mob/living/simple_animal/bot}/mulebot.dm | 314 +++++------ .../mob/living/simple_animal/bot}/secbot.dm | 237 ++++---- .../living/simple_animal/bot_swarm/swarmer.dm | 2 +- .../simple_animal/friendly/drone/_drone.dm | 2 +- .../living/simple_animal/revenant/revenant.dm | 2 +- .../revenant/revenant_abilities.dm | 4 +- .../mob/living/simple_animal/simple_animal.dm | 24 +- .../reagents/reagent_containers/glass.dm | 2 +- .../research/xenobiology/xenobiology.dm | 7 + tgstation.dme | 16 +- 38 files changed, 1389 insertions(+), 1291 deletions(-) delete mode 100644 code/controllers/subsystem/bots.dm rename code/{game/machinery/bots/bots.dm => modules/mob/living/simple_animal/bot/bot.dm} (62%) rename code/{game/machinery/bots => modules/mob/living/simple_animal/bot}/cleanbot.dm (75%) create mode 100644 code/modules/mob/living/simple_animal/bot/construction.dm rename code/{game/machinery/bots => modules/mob/living/simple_animal/bot}/ed209bot.dm (54%) rename code/{game/machinery/bots => modules/mob/living/simple_animal/bot}/floorbot.dm (67%) rename code/{game/machinery/bots => modules/mob/living/simple_animal/bot}/medbot.dm (72%) rename code/{game/machinery/bots => modules/mob/living/simple_animal/bot}/mulebot.dm (75%) rename code/{game/machinery/bots => modules/mob/living/simple_animal/bot}/secbot.dm (66%) 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 += "" - 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 += "" 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"

Name

Status

Location

Control

[Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model])