From 1d008754da0d4e26bd500c81103ba52bfc7f69e6 Mon Sep 17 00:00:00 2001 From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> Date: Sat, 17 Sep 2022 12:46:25 +0100 Subject: [PATCH] [READY] Bot Refactor (#18930) * [WIP] Bot Refactor * No more spawns, sleeps, and working EDs * Mules * GC fixing * h --- .../mob/living/simple_animal/bot/bot.dm | 257 ++++++++---------- .../mob/living/simple_animal/bot/cleanbot.dm | 28 +- .../living/simple_animal/bot/construction.dm | 2 +- .../mob/living/simple_animal/bot/ed209bot.dm | 56 ++-- .../mob/living/simple_animal/bot/floorbot.dm | 142 +++++----- .../mob/living/simple_animal/bot/griefsky.dm | 11 +- .../mob/living/simple_animal/bot/honkbot.dm | 5 +- .../mob/living/simple_animal/bot/medbot.dm | 47 ++-- .../mob/living/simple_animal/bot/mulebot.dm | 200 ++++++-------- .../mob/living/simple_animal/bot/secbot.dm | 17 +- .../mob/living/simple_animal/bot/syndicate.dm | 2 +- code/modules/pda/PDA.dm | 4 +- code/modules/pda/cart.dm | 24 -- code/modules/pda/cart_apps.dm | 197 ++++++-------- code/modules/pda/pda_tgui.dm | 2 - code/modules/pda/radio.dm | 145 ---------- paradise.dme | 1 - tgui/packages/tgui/interfaces/pda/pda_mule.js | 48 ++-- .../tgui/interfaces/pda/pda_secbot.js | 28 +- tgui/packages/tgui/public/tgui.bundle.js | 2 +- 20 files changed, 475 insertions(+), 743 deletions(-) delete mode 100644 code/modules/pda/radio.dm diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 084fc3e45b1..387fd5deb44 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -23,8 +23,6 @@ bubble_icon = "machine" faction = list("neutral", "silicon") - 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 @@ -93,6 +91,9 @@ var/path_image_color = "#FFFFFF" var/reset_access_timer_id + /// List of access values you can have to access the bot. Consider this as req_one_access + var/list/req_access = list() + hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)//Diagnostic HUD views /obj/item/radio/headset/bot @@ -159,11 +160,6 @@ add_language("Trinary", 1) default_language = GLOB.all_languages["Galactic Common"] - bot_core = new bot_core_type(src) - - if(SSradio && bot_filter) - SSradio.add_object(bot_core, control_freq, bot_filter) - prepare_huds() for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) @@ -194,12 +190,11 @@ GLOB.bots_list -= src QDEL_NULL(Radio) QDEL_NULL(access_card) + if(reset_access_timer_id) deltimer(reset_access_timer_id) reset_access_timer_id = null - if(SSradio && bot_filter) - SSradio.remove_object(bot_core, control_freq) - QDEL_NULL(bot_core) + return ..() /mob/living/simple_animal/bot/death(gibbed) @@ -319,7 +314,7 @@ else to_chat(user, "The maintenance panel is locked.") else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda)) - if(bot_core.allowed(user) && !open && !emagged) + if(allowed(user) && !open && !emagged) locked = !locked to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]") else @@ -405,14 +400,18 @@ if(paicard) paicard.emp_act(severity) - src.visible_message("[paicard] is flies out of [bot_name]!","You are forcefully ejected from [bot_name]!") - ejectpai(0) + visible_message("[paicard] is flies out of [bot_name]!") + ejectpai() + if(on) turn_off() - spawn(severity*300) - stat &= ~EMPED - if(was_on) - turn_on() + addtimer(CALLBACK(src, .proc/un_emp, was_on), severity * 300) + + +/mob/living/simple_animal/bot/proc/un_emp(was_on) + stat &= ~EMPED + if(was_on) + turn_on() /mob/living/simple_animal/bot/rename_character(oldname, newname) if(!..(oldname, newname)) @@ -478,43 +477,50 @@ 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. */ /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. set_path(null) - return 0 + return FALSE + dest = get_turf(dest) //We must always compare turfs, so get the turf of the dest var if dest was originally something else. var/turf/last_node = get_turf(path[path.len]) //This is the turf at the end of the path, it should be equal to dest. if(get_turf(src) == dest) //We have arrived, no need to move again. - return 1 + return TRUE + else if(dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop. set_path(null) - return 0 + return FALSE + 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 < BOT_STEP_MAX_RETRIES) - for(var/step_number = 0, step_number < step_count,step_number++) - spawn(BOT_STEP_DELAY*step_number) - bot_step(dest) + for(var/step_number in 1 to step_count) + // Hopefully this wont fill the buckets too much + addtimer(CALLBACK(src, .proc/bot_step), BOT_STEP_DELAY * (step_number - 1)) else - return 0 - return 1 + return FALSE + return TRUE -/mob/living/simple_animal/bot/proc/bot_step(dest) //Step,increase tries if failed - if(!path) - return 0 - if(path.len > 1) +/mob/living/simple_animal/bot/proc/bot_step() //Step,increase tries if failed + if(!length(path)) + return FALSE + + // Only one destination + if(length(path) == 1) + step_to(src, path[1]) + set_path(null) + + else + // Move us slowly Move(path[1], get_dir(src, path[1]), BOT_STEP_DELAY) if(get_turf(src) == path[1]) //Successful move increment_path() tries = 0 else tries++ - return 0 - else if(path.len == 1) - step_to(src, dest) - set_path(null) - return 1 + return FALSE + + return TRUE /mob/living/simple_animal/bot/proc/check_bot_access() @@ -584,10 +590,11 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/bot_patrol() patrol_step() - spawn(5) - if(mode == BOT_PATROL) - patrol_step() - return + addtimer(CALLBACK(src, .proc/do_patrol), 5) + +/mob/living/simple_animal/bot/proc/do_patrol() + if(mode == BOT_PATROL) + patrol_step() /mob/living/simple_animal/bot/proc/start_patrol() @@ -602,18 +609,20 @@ Pass a positive integer as an argument to override a bot's default speed. mode = BOT_IDLE return - if(patrol_target) // has patrol target - spawn(0) - calc_path() // Find a route to it - if(path.len == 0) - patrol_target = null - return - mode = BOT_PATROL - else // no patrol target, so need a new one + + if(patrol_target) // has patrol target + INVOKE_ASYNC(src, .proc/target_patrol) + else // no patrol target, so need a new one speak("Engaging patrol mode.") find_patrol_target() tries++ - return + +/mob/living/simple_animal/bot/proc/target_patrol() + calc_path() // Find a route to it + if(!length(path)) + patrol_target = null + return + mode = BOT_PATROL // perform a single patrol step @@ -637,18 +646,19 @@ Pass a positive integer as an argument to override a bot's default speed. var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times - spawn(2) - calc_path() - if(path.len == 0) - find_patrol_target() - tries = 0 + addtimer(CALLBACK(src, .proc/patrol_step_not_moved), 2) else // no path, so calculate new one mode = BOT_START_PATROL +/mob/living/simple_animal/bot/proc/patrol_step_not_moved() + calc_path() + if(!length(path)) + find_patrol_target() + tries = 0 + // finds the nearest beacon to self /mob/living/simple_animal/bot/proc/find_patrol_target() - send_status() nearest_beacon = null new_destination = null find_nearest_beacon() @@ -659,7 +669,6 @@ Pass a positive integer as an argument to override a bot's default speed. auto_patrol = FALSE mode = BOT_IDLE speak("Disengaging patrol mode.") - send_status() /mob/living/simple_animal/bot/proc/get_next_patrol_target() // search the beacon list for the next target in the list. @@ -702,83 +711,41 @@ Pass a positive integer as an argument to override a bot's default speed. else to_chat(src, "Unidentified control sequence recieved: [command]") -/obj/machinery/bot_core/receive_signal(datum/signal/signal) - owner.receive_signal(signal) - -/mob/living/simple_animal/bot/proc/receive_signal(datum/signal/signal) +/mob/living/simple_animal/bot/proc/handle_command(mob/user, command, list/params) + // We aint even on, why bother if(!on) - return 1 //ACCESS DENIED - - var/recv = signal.data["command"] - var/user = signal.data["user"] - - // process all-bot input - if(recv == "bot_status" && (!signal.data["active"] || signal.data["active"] == src)) - send_status() - return 1 + return FALSE // check to see if we are the commanded bot - if(signal.data["active"] == src) - if(emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. - return 1 - if(client) - bot_control_message(recv, user, signal.data["target"] ? signal.data["target"] : "Unknown") - // process control input - switch(recv) - if("stop") - bot_reset() //HOLD IT!! - auto_patrol = FALSE + if(emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands. + return FALSE - if("go") - auto_patrol = TRUE + if(client) + bot_control_message(command, user, params["target"] ? params["target"] : "Unknown") - if("summon") - bot_reset() - var/list/user_access = signal.data["useraccess"] - summon_target = signal.data["target"] //Location of the user - if(user_access.len != 0) - access_card.access = user_access + prev_access //Adds the user's access, if any. - mode = BOT_SUMMON - calc_summon_path() - speak("Responding.", radio_channel) + // process control input + switch(command) + if("stop") + bot_reset() //HOLD IT!! + auto_patrol = FALSE - else - return 0 - return 1 + if("go") + auto_patrol = TRUE -// send a radio signal with a single data key/value pair -/mob/living/simple_animal/bot/proc/post_signal(freq, key, value) - post_signal_multiple(freq, list("[key]" = value) ) + if("summon") + bot_reset() + var/list/user_access = params["useraccess"] + summon_target = params["target"] // Location of the user -// send a radio signal with multiple data key/values -/mob/living/simple_animal/bot/proc/post_signal_multiple(freq, list/keyval) - if(!is_station_level(z)) //Bot control will only work on station. - return - var/datum/radio_frequency/frequency = SSradio.return_frequency(freq) - if(!frequency) - return + if(length(user_access)) + access_card.access = user_access + prev_access //Adds the user's access, if any. - var/datum/signal/signal = new() - signal.source = bot_core - signal.transmission_method = 1 - signal.data = keyval - spawn() - if(signal.data["type"] == bot_type) - frequency.post_signal(bot_core, signal, filter = bot_filter) - else - frequency.post_signal(bot_core, signal) + mode = BOT_SUMMON + calc_summon_path() + speak("Responding.", radio_channel) + + return TRUE -// signals bot status etc. to controller -/mob/living/simple_animal/bot/proc/send_status() - if(remote_disabled || emagged == 2) - return - var/list/kv = list( - "type" = bot_type, - "name" = name, - "loca" = get_area(src), // area - "mode" = mode - ) - post_signal_multiple(control_freq, kv) /mob/living/simple_animal/bot/proc/bot_summon() // summoned to PDA summon_step() @@ -790,12 +757,12 @@ Pass a positive integer as an argument to override a bot's default speed. set_path(get_path_to(src, patrol_target, /turf/proc/Distance_cardinal, 0, 120, id=access_card, exclude=avoid)) /mob/living/simple_animal/bot/proc/calc_summon_path(turf/avoid) + set waitfor = FALSE check_bot_access() - spawn() - set_path(get_path_to(src, summon_target, /turf/proc/Distance_cardinal, 0, 150, id=access_card, exclude=avoid)) - if(!path.len) //Cannot reach target. Give up and announce the issue. - speak("Summon command failed, destination unreachable.",radio_channel) - bot_reset() + set_path(get_path_to(src, summon_target, /turf/proc/Distance_cardinal, 0, 150, id=access_card, exclude=avoid)) + if(!path.len) //Cannot reach target. Give up and announce the issue. + speak("Summon command failed, destination unreachable.",radio_channel) + bot_reset() /mob/living/simple_animal/bot/proc/summon_step() @@ -814,13 +781,17 @@ Pass a positive integer as an argument to override a bot's default speed. var/moved = bot_move(summon_target, 3) // Move attempt if(!moved) - spawn(2) - calc_summon_path() - tries = 0 + addtimer(CALLBACK(src, .proc/try_calc_path), 2) + else // no path, so calculate new one calc_summon_path() +/mob/living/simple_animal/bot/proc/try_calc_path() + calc_summon_path() + tries = 0 + + /mob/living/simple_animal/bot/proc/openedDoor(obj/machinery/door/D) frustration = 0 @@ -844,6 +815,14 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/get_controls(mob/M) return "PROTOBOT - NOT FOR USE" +/mob/living/simple_animal/bot/proc/allowed(mob/M) + var/acc = M.get_access() //see mob.dm + + if(acc == IGNORE_ACCESS || M.can_admin_interact()) + return TRUE //Mob ignores access + + return has_access(list(), req_access, acc) + /mob/living/simple_animal/bot/Topic(href, href_list) if(href_list["close"])// HUE HUE if(usr in users) @@ -855,7 +834,7 @@ Pass a positive integer as an argument to override a bot's default speed. return 1 add_fingerprint(usr) - if((href_list["power"]) && (bot_core.allowed(usr) || !locked || usr.can_admin_interact())) + if((href_list["power"]) && (allowed(usr) || !locked || usr.can_admin_interact())) if(on) turn_off() else @@ -902,17 +881,6 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/update_icon_state() icon_state = "[initial(icon_state)][on]" -// Machinery to simplify topic and access calls -/obj/machinery/bot_core - use_power = NO_POWER_USE - 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. if(user.can_admin_interact()) return FALSE @@ -975,7 +943,7 @@ Pass a positive integer as an argument to override a bot's default speed. faction = initial(faction) /mob/living/simple_animal/bot/proc/ejectpairemote(mob/user) - if(bot_core.allowed(user) && paicard) + if(allowed(user) && paicard) speak("Ejecting personality chip.", radio_channel) ejectpai(user) @@ -1035,8 +1003,7 @@ Pass a positive integer as an argument to override a bot's default speed. switch(message_mode) if("intercom") for(var/obj/item/radio/intercom/I in view(1, src)) - spawn(0) - I.talk_into(src, message, null, verb, speaking) + I.talk_into(src, message, null, verb, speaking) used_radios += I if("headset") Radio.talk_into(src, message, null, verb, speaking) diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 52ce08554cc..658911475ff 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -13,7 +13,7 @@ bot_type = CLEAN_BOT model = "Cleanbot" bot_purpose = "seek out messes and clean them" - bot_core_type = /obj/machinery/bot_core/cleanbot + req_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS) window_id = "autoclean" window_name = "Automatic Station Cleaner v1.1" pass_flags = PASSMOB @@ -61,7 +61,7 @@ /mob/living/simple_animal/bot/cleanbot/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda)) - if(bot_core.allowed(user) && !open && !emagged) + if(allowed(user) && !open && !emagged) locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] \the [src] behaviour controls.") else @@ -131,7 +131,7 @@ return if(target && loc == target.loc) - clean(target) + start_clean(target) path = list() target = null @@ -163,17 +163,19 @@ target_types += /obj/effect/decal/cleanable/dirt target_types += /obj/effect/decal/cleanable/trail_holder -/mob/living/simple_animal/bot/cleanbot/proc/clean(obj/effect/decal/cleanable/target) +/mob/living/simple_animal/bot/cleanbot/proc/start_clean(obj/effect/decal/cleanable/target) anchored = TRUE icon_state = "cleanbot-c" visible_message("[src] begins to clean up [target]") mode = BOT_CLEANING - spawn(50) - if(mode == BOT_CLEANING) - QDEL_NULL(target) - anchored = FALSE - mode = BOT_IDLE - icon_state = "cleanbot[on]" + addtimer(CALLBACK(src, .proc/do_clean, target), 5 SECONDS) + +/mob/living/simple_animal/bot/cleanbot/proc/do_clean(obj/effect/decal/cleanable/target) + if(mode == BOT_CLEANING) + QDEL_NULL(target) + anchored = FALSE + mode = BOT_IDLE + icon_state = "cleanbot[on]" /mob/living/simple_animal/bot/cleanbot/explode() on = FALSE @@ -186,10 +188,6 @@ do_sparks(3, 1, src) ..() -/obj/machinery/bot_core/cleanbot - req_one_access = list(ACCESS_JANITOR, ACCESS_ROBOTICS) - - /mob/living/simple_animal/bot/cleanbot/show_controls(mob/M) ui_interact(M) @@ -245,6 +243,6 @@ /mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A) if(istype(A,/obj/effect/decal/cleanable)) - clean(A) + start_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 index b02fd890803..deb73af8ade 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -405,7 +405,7 @@ if(!syndicate_aligned) var/mob/living/simple_animal/bot/medbot/S = new /mob/living/simple_animal/bot/medbot(T, skin) S.name = created_name - S.bot_core.req_one_access = req_one_access + S.req_access = req_one_access S.treatment_oxy = treatment_oxy S.treatment_brute = treatment_brute S.treatment_fire = treatment_fire diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 7c5185c3a3e..004cfb25080 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -19,7 +19,7 @@ bot_filter = RADIO_SECBOT model = "ED-209" bot_purpose = "seek out criminals, handcuff them, and report their location to security" - bot_core_type = /obj/machinery/bot_core/secbot + req_access = list(ACCESS_SECURITY) window_id = "autoed209" window_name = "Automatic Security Unit v2.6" path_image_color = "#FF0000" @@ -62,7 +62,7 @@ check_records = FALSE //Don't actively target people set to arrest arrest_type = TRUE //Don't even try to cuff declare_arrests = FALSE // Don't spam sec - bot_core.req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE, ACCESS_ROBOTICS) + req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE, ACCESS_ROBOTICS) if(created_name == initial(name) || !created_name) if(lasercolor == "b") @@ -296,7 +296,7 @@ if(iscarbon(target) && target.canBeHandcuffed()) if(!arrest_type) if(!target.handcuffed) //he's not cuffed? Try to cuff him! - cuff(target) + start_cuffing(target) else back_to_idle() return @@ -340,15 +340,13 @@ target = null last_found = world.time frustration = 0 - spawn(0) - handle_automated_action() //ensure bot quickly responds + INVOKE_ASYNC(src, .proc/handle_automated_action) /mob/living/simple_animal/bot/ed209/proc/back_to_hunt() anchored = FALSE frustration = 0 mode = BOT_HUNT - spawn(0) - handle_automated_action() //ensure bot quickly responds + INVOKE_ASYNC(src, .proc/handle_automated_action) // look for a criminal in view of the bot @@ -376,8 +374,7 @@ playsound(loc, pick('sound/voice/ed209_20sec.ogg', 'sound/voice/edplaceholder.ogg'), 50, 0) visible_message("[src] points at [C.name]!") mode = BOT_HUNT - spawn(0) - handle_automated_action() // ensure bot quickly responds to a perp + INVOKE_ASYNC(src, .proc/handle_automated_action) break else continue @@ -488,8 +485,7 @@ pulse2.name = "emp sparks" pulse2.anchored = TRUE pulse2.dir = pick(GLOB.cardinal) - spawn(10) - qdel(pulse2) + QDEL_IN(pulse2, 1 SECONDS) var/list/mob/living/carbon/targets = new for(var/mob/living/carbon/C in view(12,src)) if(C.stat==2) @@ -522,23 +518,29 @@ if((lasercolor == "b")) if(istype(Proj, /obj/item/projectile/beam/lasertag/redtag)) lasertag_check++ + else if((lasercolor == "r")) if(istype(Proj, /obj/item/projectile/beam/lasertag/bluetag)) lasertag_check++ + if(lasertag_check) icon_state = "[lasercolor]ed2090" disabled = TRUE walk_to(src, 0) target = null - spawn(100) - disabled = FALSE - icon_state = "[lasercolor]ed2091" - return 1 + addtimer(CALLBACK(src, .proc/unset_disabled), 10 SECONDS) + return TRUE + else ..(Proj) + else ..(Proj) +/mob/living/simple_animal/bot/ed209/proc/unset_disabled() + disabled = FALSE + icon_state = "[lasercolor]ed2091" + /mob/living/simple_animal/bot/ed209/bluetag lasercolor = "b" @@ -553,7 +555,7 @@ if(!C.IsStunned() || arrest_type && !baton_delayed) stun_attack(A) else if(C.canBeHandcuffed() && !C.handcuffed) - cuff(A) + start_cuffing(A) else ..() @@ -573,8 +575,7 @@ /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]" + addtimer(VARSET_CALLBACK(src, icon_state, "[lasercolor]ed209[on]"), 2) var/threat = C.assess_threat(src) C.SetStuttering(10 SECONDS) C.adjustStaminaLoss(60) @@ -588,18 +589,21 @@ C.visible_message("[src] has stunned [C]!",\ "[src] has stunned you!") -/mob/living/simple_animal/bot/ed209/proc/cuff(mob/living/carbon/C) +/mob/living/simple_animal/bot/ed209/proc/start_cuffing(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/restraints/handcuffs/cable/zipties/used(C) - C.update_handcuffed() - back_to_idle() + addtimer(CALLBACK(src, .proc/cuff_target, C), 6 SECONDS) + +/mob/living/simple_animal/bot/ed209/proc/cuff_target(mob/living/carbon/C) + 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/restraints/handcuffs/cable/zipties/used(C) + C.update_handcuffed() + back_to_idle() #undef BATON_COOLDOWN diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index c941e18e3a5..5efa0941498 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -14,7 +14,7 @@ bot_filter = RADIO_FLOORBOT model = "Floorbot" bot_purpose = "seek out damaged or missing floor tiles, and repair or replace them as necessary" - bot_core_type = /obj/machinery/bot_core/floorbot + req_access = list(ACCESS_CONSTRUCTION, ACCESS_ROBOTICS) window_id = "autofloor" window_name = "Automatic Station Floor Repairer v1.1" path_image_color = "#FFA500" @@ -233,9 +233,9 @@ if(loc == target || loc == target.loc) if(istype(target, /obj/item/stack/tile/plasteel)) - eattile(target) + start_eattile(target) else if(istype(target, /obj/item/stack/sheet/metal)) - maketile(target) + start_maketile(target) else if(istype(target, /turf/) && emagged < 2) repair(target) else if(emagged == 2 && istype(target,/turf/simulated/floor)) @@ -247,20 +247,23 @@ else F.ReplaceWithLattice() audible_message("[src] makes an excited booping sound.") - spawn(50) - amount ++ - anchored = FALSE - mode = BOT_IDLE - target = null + addtimer(CALLBACK(src, .proc/inc_amount_callback), 5 SECONDS) + path = list() return oldloc = loc +/mob/living/simple_animal/bot/floorbot/proc/inc_amount_callback() + amount ++ + anchored = FALSE + mode = BOT_IDLE + target = null + /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_channel) - nagged = 1 + nagged = TRUE /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) @@ -299,90 +302,106 @@ return result /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. if(!is_hull_breach(target_turf) && !targetdirection) target = null return + else if(!istype(target_turf, /turf/simulated/floor)) return + if(amount <= 0) mode = BOT_IDLE target = null return + anchored = TRUE + if(istype(target_turf, /turf/space/)) //If we are fixing an area not part of pure space, it is visible_message("[targetdirection ? "[src] begins installing a bridge plating." : "[src] begins to repair the hole."] ") mode = BOT_REPAIRING update_icon(UPDATE_ICON_STATE) - spawn(50) - if(mode == BOT_REPAIRING) - if(autotile) //Build the floor and include a tile. - target_turf.ChangeTurf(/turf/simulated/floor/plasteel) - else //Build a hull plating without a floor tile. - target_turf.ChangeTurf(/turf/simulated/floor/plating) - mode = BOT_IDLE - amount -= 1 - update_icon(UPDATE_ICON_STATE) - anchored = FALSE - target = null + addtimer(CALLBACK(src, .proc/make_bridge_plating, target_turf), 5 SECONDS) + else var/turf/simulated/floor/F = target_turf mode = BOT_REPAIRING update_icon(UPDATE_ICON_STATE) visible_message("[src] begins repairing the floor.") - spawn(50) - if(mode == BOT_REPAIRING) - F.broken = FALSE - F.burnt = FALSE - F.ChangeTurf(/turf/simulated/floor/plasteel) - mode = BOT_IDLE - amount -= 1 - update_icon(UPDATE_ICON_STATE) - anchored = FALSE - target = null + addtimer(CALLBACK(src, .proc/make_bridge_plating, F), 5 SECONDS) -/mob/living/simple_animal/bot/floorbot/proc/eattile(obj/item/stack/tile/plasteel/T) +/mob/living/simple_animal/bot/floorbot/proc/make_floor(turf/simulated/floor/F) + if(mode != BOT_REPAIRING) + return + + F.broken = FALSE + F.burnt = FALSE + F.ChangeTurf(/turf/simulated/floor/plasteel) + mode = BOT_IDLE + amount-- + update_icon(UPDATE_ICON_STATE) + anchored = FALSE + target = null + +/mob/living/simple_animal/bot/floorbot/proc/make_bridge_plating(turf/target_turf) + if(mode != BOT_REPAIRING) + return + + if(autotile) //Build the floor and include a tile. + target_turf.ChangeTurf(/turf/simulated/floor/plasteel) + else //Build a hull plating without a floor tile. + target_turf.ChangeTurf(/turf/simulated/floor/plating) + mode = BOT_IDLE + amount-- + update_icon(UPDATE_ICON_STATE) + anchored = FALSE + target = null + +/mob/living/simple_animal/bot/floorbot/proc/start_eattile(obj/item/stack/tile/plasteel/T) if(!istype(T, /obj/item/stack/tile/plasteel)) return visible_message("[src] begins to collect tiles.") mode = BOT_REPAIRING - spawn(20) - if(isnull(T)) - target = null - mode = BOT_IDLE - return - if(amount + T.amount > 50) - var/i = 50 - amount - amount += i - T.amount -= i - else - amount += T.amount - qdel(T) + addtimer(CALLBACK(src, .proc/do_eattile, T), 2 SECONDS) + +/mob/living/simple_animal/bot/floorbot/proc/do_eattile(obj/item/stack/tile/plasteel/T) + if(isnull(T)) target = null mode = BOT_IDLE - update_icon(UPDATE_ICON_STATE) + return + if(amount + T.amount > 50) + var/i = 50 - amount + amount += i + T.amount -= i + else + amount += T.amount + qdel(T) + target = null + mode = BOT_IDLE + update_icon(UPDATE_ICON_STATE) -/mob/living/simple_animal/bot/floorbot/proc/maketile(obj/item/stack/sheet/metal/M) +/mob/living/simple_animal/bot/floorbot/proc/start_maketile(obj/item/stack/sheet/metal/M) if(!istype(M, /obj/item/stack/sheet/metal)) return visible_message("[src] begins to create tiles.") mode = BOT_REPAIRING - spawn(20) - if(isnull(M)) - target = null - mode = BOT_IDLE - return - var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel - T.amount = 4 - T.forceMove(M.loc) - if(M.amount > 1) - M.amount-- - else - qdel(M) + addtimer(CALLBACK(src, .proc/do_maketile, M), 2 SECONDS) + +/mob/living/simple_animal/bot/floorbot/proc/do_maketile(obj/item/stack/sheet/metal/M) + if(isnull(M)) target = null mode = BOT_IDLE + return + var/obj/item/stack/tile/plasteel/T = new /obj/item/stack/tile/plasteel + T.amount = 4 + T.forceMove(M.loc) + if(M.amount > 1) + M.amount-- + else + qdel(M) + target = null + mode = BOT_IDLE /mob/living/simple_animal/bot/floorbot/update_icon_state() if(mode == BOT_REPAIRING) @@ -416,15 +435,12 @@ do_sparks(3, 1, src) ..() -/obj/machinery/bot_core/floorbot - req_one_access = list(ACCESS_CONSTRUCTION, ACCESS_ROBOTICS) - /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) + start_eattile(A) else if(istype(A,/obj/item/stack/sheet/metal)) - maketile(A) + start_maketile(A) else ..() diff --git a/code/modules/mob/living/simple_animal/bot/griefsky.dm b/code/modules/mob/living/simple_animal/bot/griefsky.dm index f978b2fa9e2..07d5797c65f 100644 --- a/code/modules/mob/living/simple_animal/bot/griefsky.dm +++ b/code/modules/mob/living/simple_animal/bot/griefsky.dm @@ -29,14 +29,11 @@ block_chance_melee = 1 block_chance_ranged = 1 stun_chance = 0 - bot_core_type = /obj/machinery/bot_core/toy + req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE, ACCESS_ROBOTICS) weapon = /obj/item/toy/sword frustration_number = 5 locked = FALSE -/obj/machinery/bot_core/toy - req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE, ACCESS_ROBOTICS) - /mob/living/simple_animal/bot/secbot/griefsky/proc/spam_flag_false() //used for addtimer to not spam comms spam_flag = 0 @@ -82,9 +79,11 @@ ..() /mob/living/simple_animal/bot/secbot/griefsky/proc/sword_attack(mob/living/carbon/C) // esword attack - src.do_attack_animation(C) + do_attack_animation(C) playsound(loc, 'sound/weapons/blade1.ogg', 50, 1, -1) - spawn(2) + addtimer(CALLBACK(src, .proc/do_sword_attack, C), 2) + +/mob/living/simple_animal/bot/secbot/griefsky/proc/do_sword_attack(mob/living/carbon/C) icon_state = spin_icon var/threat = C.assess_threat(src) if(ishuman(C)) diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm index 375c83f7673..2f4d419a380 100644 --- a/code/modules/mob/living/simple_animal/bot/honkbot.dm +++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm @@ -13,7 +13,7 @@ bot_type = HONK_BOT bot_filter = RADIO_HONKBOT model = "Honkbot" - bot_core_type = /obj/machinery/bot_core/honkbot + req_access = list(ACCESS_CLOWN, ACCESS_ROBOTICS, ACCESS_MIME) window_id = "autohonk" window_name = "Honkomatic Bike Horn Unit v1.0.7" data_hud_type = DATA_HUD_SECURITY_BASIC // show jobs @@ -30,9 +30,6 @@ var/threatlevel = FALSE var/arrest_type = FALSE -/obj/machinery/bot_core/honkbot - req_one_access = list(ACCESS_CLOWN, ACCESS_ROBOTICS, ACCESS_MIME) - /mob/living/simple_animal/bot/honkbot/Initialize(mapload) . = ..() update_icon() diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 16bae48ce8c..bb29897db7f 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -16,7 +16,7 @@ bot_filter = RADIO_MEDBOT model = "Medibot" bot_purpose = "seek out hurt crewmembers and ensure that they are healed" - bot_core_type = /obj/machinery/bot_core/medbot + req_access = list(ACCESS_MEDICAL, ACCESS_ROBOTICS) window_id = "automed" window_name = "Automatic Medical Unit v1.1" path_image_color = "#DDDDFF" @@ -87,7 +87,7 @@ treatment_fire = "kelotane" treatment_tox = "charcoal" syndicate_aligned = TRUE - bot_core_type = /obj/machinery/bot_core/medbot/syndicate + req_access = list(ACCESS_SYNDICATE) control_freq = BOT_FREQ + 1000 // make it not show up on lists radio_channel = "Syndicate" radio_config = list("Common" = 1, "Medical" = 1, "Syndicate" = 1) @@ -508,31 +508,31 @@ bot_reset() return else - if(!emagged && check_overdose(patient,reagent_id,injection_amount)) + if(!emagged && check_overdose(patient, reagent_id, injection_amount)) soft_reset() return C.visible_message("[src] is trying to inject [patient]!", \ "[src] is trying to inject you!") - spawn(30)//replace with do mob - if((get_dist(src, patient) <= 1) && on && assess_patient(patient)) - if(inject_beaker) - if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume) - var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1) - reagent_glass.reagents.reaction(patient, REAGENT_INGEST, fraction) - reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead. - else - patient.reagents.add_reagent(reagent_id,injection_amount) - C.visible_message("[src] injects [patient] with its syringe!", \ - "[src] injects you with its syringe!") - else - visible_message("[src] retracts its syringe.") - update_icon() - soft_reset() - return + addtimer(CALLBACK(src, .proc/do_inject, C, inject_beaker, reagent_id), 3 SECONDS) + return - reagent_id = null - return +/mob/living/simple_animal/bot/medbot/proc/do_inject(mob/living/carbon/C, inject_beaker, reagent_id) + if((get_dist(src, patient) <= 1) && on && assess_patient(patient)) + if(inject_beaker) + if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume) + var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1) + reagent_glass.reagents.reaction(patient, REAGENT_INGEST, fraction) + reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead. + else + patient.reagents.add_reagent(reagent_id, injection_amount) + + C.visible_message("[src] injects [patient] with its syringe!", "[src] injects you with its syringe!") + else + visible_message("[src] retracts its syringe.") + + update_icon() + soft_reset() /mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount) var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id] @@ -598,8 +598,3 @@ spawn(200) //Twenty seconds declare_cooldown = 0 -/obj/machinery/bot_core/medbot - req_one_access = list(ACCESS_MEDICAL, ACCESS_ROBOTICS) - -/obj/machinery/bot_core/medbot/syndicate - req_one_access = list(ACCESS_SYNDICATE) diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index e17620fcf4f..d0507e7f864 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -25,12 +25,17 @@ bot_filter = RADIO_MULEBOT model = "MULE" bot_purpose = "deliver crates and other packages between departments, as requested" - bot_core_type = /obj/machinery/bot_core/mulebot + req_access = list(ACCESS_CARGO) path_image_color = "#7F5200" suffix = "" + /// Delay in deciseconds between each step + var/step_delay = 0 + /// world.time of next move + var/next_move_time = 0 + var/global/mulebot_count = 0 var/atom/movable/load = null var/mob/living/passenger = null @@ -50,6 +55,8 @@ var/currentBloodColor = "#A10808" var/currentDNA = null + var/num_steps + /mob/living/simple_animal/bot/mulebot/get_cell() return cell @@ -250,7 +257,7 @@ update_controls() /mob/living/simple_animal/bot/mulebot/proc/toggle_lock(mob/user) - if(bot_core.allowed(user)) + if(allowed(user)) locked = !locked update_controls() return 1 @@ -442,7 +449,7 @@ // with items dropping as mobs are loaded for(var/atom/movable/AM in src) - if(AM == cell || AM == access_card || AM == Radio || AM == bot_core || AM == paicard) + if(AM == cell || AM == access_card || AM == Radio || AM == paicard) continue AM.forceMove(loc) @@ -466,109 +473,100 @@ if(!has_power()) on = FALSE return - if(on) - var/speed = (!wires.is_cut(WIRE_MOTOR1) ? 1 : 0) + (!wires.is_cut(WIRE_MOTOR2) ? 2 : 0) - var/num_steps = 0 - switch(speed) - if(0) - // do nothing - if(1) - num_steps = 10 - if(2) - num_steps = 5 - if(3) - num_steps = 3 - - if(num_steps) - process_bot() - num_steps-- - if(mode != BOT_IDLE) - spawn(0) - for(var/i=num_steps,i>0,i--) - sleep(2) - process_bot() - -/mob/living/simple_animal/bot/mulebot/proc/process_bot() if(!on) return - update_icon() + + var/new_speed = (!wires.is_cut(WIRE_MOTOR1) ? 1 : 0) + (!wires.is_cut(WIRE_MOTOR2) ? 2 : 0) + if(!new_speed)//Devide by zero man bad + return + + + num_steps = round(10 / new_speed) //10, 5, or 3 steps, depending on how many wires we have cut + step_delay = num_steps // step_delay shouldnt change, num_steps should + START_PROCESSING(SSfastprocess, src) + +/mob/living/simple_animal/bot/mulebot/process() + if(!on) + return PROCESS_KILL + + num_steps-- switch(mode) if(BOT_IDLE) // idle return if(BOT_DELIVER, BOT_GO_HOME, BOT_BLOCKED) // navigating to deliver,home, or blocked + if(world.time < next_move_time) + return + + next_move_time = world.time + step_delay + if(loc == target) // reached target at_target() return - else if(path.len > 0 && target) // valid path + else if(length(path) && target) // valid path var/turf/next = path[1] - reached_target = 0 + reached_target = FALSE if(next == loc) - increment_path() + path -= next return - if(istype(next, /turf/simulated)) -// to_chat(world, "at ([x],[y]) moving to ([next.x],[next.y])") - + if(isturf(next)) var/oldloc = loc - var/moved = step_towards(src, next) // attempt to move - if(cell) cell.use(1) - if(moved && oldloc!=loc) // successful move -// to_chat(world, "Successful move.") + var/moved = step_towards(src, next) // attempt to move + if(moved && oldloc!=loc) // successful move blockcount = 0 - increment_path() - + path -= loc if(destination == home_destination) mode = BOT_GO_HOME else mode = BOT_DELIVER - else // failed to move + else // failed to move -// to_chat(world, "Unable to move.") blockcount++ mode = BOT_BLOCKED if(blockcount == 3) buzz(ANNOYED) - if(blockcount > 10) // attempt 10 times before recomputing + if(blockcount > 10) // attempt 10 times before recomputing // find new path excluding blocked turf buzz(SIGH) mode = BOT_WAIT_FOR_NAV blockcount = 0 - spawn(20) - calc_path(avoid=next) - if(path.len > 0) - buzz(DELIGHT) - mode = BOT_BLOCKED + addtimer(CALLBACK(src, .proc/process_blocked, next), 2 SECONDS) return return else buzz(ANNOYED) -// to_chat(world, "Bad turf.") mode = BOT_NAV return else -// to_chat(world, "No path.") mode = BOT_NAV return - if(BOT_NAV) // calculate new path -// to_chat(world, "Calc new path.") + if(BOT_NAV) // calculate new path mode = BOT_WAIT_FOR_NAV - spawn(0) - calc_path() + INVOKE_ASYNC(src, .proc/process_nav) - if(path.len > 0) - blockcount = 0 - mode = BOT_BLOCKED - buzz(DELIGHT) +/mob/living/simple_animal/bot/mulebot/proc/process_blocked(turf/next) + calc_path(avoid=next) + if(length(path)) + buzz(DELIGHT) + mode = BOT_BLOCKED - else - buzz(SIGH) +/mob/living/simple_animal/bot/mulebot/proc/process_nav() + calc_path() - mode = BOT_NO_ROUTE + if(length(path)) + blockcount = 0 + mode = BOT_BLOCKED + buzz(DELIGHT) + + else + buzz(SIGH) + + mode = BOT_NO_ROUTE // calculates a path to the current destination // given an optional turf to avoid @@ -599,9 +597,11 @@ /mob/living/simple_animal/bot/mulebot/proc/start_home() if(!on) return - spawn(0) - set_destination(home_destination) - mode = BOT_BLOCKED + INVOKE_ASYNC(src, .proc/do_start_home) + +/mob/living/simple_animal/bot/mulebot/proc/do_start_home() + set_destination(home_destination) + mode = BOT_BLOCKED update_icon() // called when bot reaches current target @@ -732,72 +732,52 @@ to_chat(src, "DELIVER [load] TO [destination]") else to_chat(src, "PICK UP DELIVERY AT [destination]") - if("unload") + + if("unload", "load") if(load) to_chat(src, "UNLOAD") else to_chat(src, "LOAD") - if("autoret", "autopick", "target") - else - ..() -/mob/living/simple_animal/bot/mulebot/receive_signal(datum/signal/signal) - if(wires.is_cut(WIRE_REMOTE_RX) || ..()) - return TRUE - var/recv = signal.data["command"] + +/mob/living/simple_animal/bot/mulebot/handle_command(mob/user, command, list/params) + if(wires.is_cut(WIRE_REMOTE_RX) || !..()) + return FALSE + + if(client) + bot_control_message(command, user, null) + return + + . = TRUE // process control input - switch(recv) + switch(command) if("start") start() - if("target") - set_destination(signal.data["destination"]) + if("stop") + bot_reset() + + if("home") + start_home() if("unload") - if(client) - return 1 if(loc == target) unload(loaddir) else unload(0) - if("home") - start_home() + if("target") + var/dest = input("Select Bot Destination", "Mulebot [suffix] Interlink", destination) as null|anything in GLOB.deliverybeacontags + if(dest) + set_destination(dest) - if("autoret") - auto_return = text2num(signal.data["value"]) + if("set_auto_return") + auto_return = text2num(params["autoret"]) - if("autopick") - auto_pickup = text2num(signal.data["value"]) - - else - return 0 - return 1 - -// send a radio signal with multiple data key/values -/mob/living/simple_animal/bot/mulebot/post_signal_multiple(freq, list/keyval) - if(wires.is_cut(WIRE_REMOTE_TX)) - return - - ..() - -// signals bot status etc. to controller -/mob/living/simple_animal/bot/mulebot/send_status() - var/list/kv = list( - "type" = MULE_BOT, - "name" = suffix, - "loca" = get_area(src), - "mode" = mode, - "powr" = (cell ? cell.percent() : 0), - "dest" = destination, - "home" = home_destination, - "load" = load, - "retn" = auto_return, - "pick" = auto_pickup, - ) - post_signal_multiple(control_freq, kv) + if("set_pickup_type") + auto_pickup = text2num(params["autopick"]) // player on mulebot attempted to move /mob/living/simple_animal/bot/mulebot/relaymove(mob/user) @@ -874,5 +854,3 @@ #undef ANNOYED #undef DELIGHT -/obj/machinery/bot_core/mulebot - req_access = list(ACCESS_CARGO) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 2c15bbf09c5..be8bd8f6320 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -17,7 +17,7 @@ bot_filter = RADIO_SECBOT model = "Securitron" bot_purpose = "seek out criminals, handcuff them, and report their location to security" - bot_core_type = /obj/machinery/bot_core/secbot + req_access = list(ACCESS_SECURITY) window_id = "autosec" window_name = "Automatic Security Unit v1.6" path_image_color = "#FF0000" @@ -264,8 +264,7 @@ playsound(loc, 'sound/weapons/genhit1.ogg', 50, 1, -1) do_attack_animation(C) icon_state = "[base_icon]-c" - spawn(2) - icon_state = "[base_icon][on]" + addtimer(VARSET_CALLBACK(src, icon_state, "[base_icon][on]"), 2) var/threat = C.assess_threat(src) if(ishuman(C) && harmbaton) // Bots with harmbaton enabled become shitcurity. - Dave C.apply_damage(10, BRUTE) @@ -395,15 +394,13 @@ target = null last_found = world.time frustration = 0 - spawn(0) - handle_automated_action() //ensure bot quickly responds + INVOKE_ASYNC(src, .proc/handle_automated_action) /mob/living/simple_animal/bot/secbot/proc/back_to_hunt() anchored = FALSE frustration = 0 mode = BOT_HUNT - spawn(0) - handle_automated_action() //ensure bot quickly responds + INVOKE_ASYNC(src, .proc/handle_automated_action) // look for a criminal in view of the bot /mob/living/simple_animal/bot/secbot/proc/look_for_perp() @@ -427,8 +424,7 @@ playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0) visible_message("[src] points at [C.name]!") mode = BOT_HUNT - spawn(0) - handle_automated_action() // ensure bot quickly responds to a perp + INVOKE_ASYNC(src, .proc/handle_automated_action) break else continue @@ -476,7 +472,4 @@ return ..() -/obj/machinery/bot_core/secbot - req_access = list(ACCESS_SECURITY) - #undef BATON_COOLDOWN diff --git a/code/modules/mob/living/simple_animal/bot/syndicate.dm b/code/modules/mob/living/simple_animal/bot/syndicate.dm index bbe55ccdfa7..24d3f1a5d0b 100644 --- a/code/modules/mob/living/simple_animal/bot/syndicate.dm +++ b/code/modules/mob/living/simple_animal/bot/syndicate.dm @@ -173,7 +173,7 @@ return shootAt(A) -/mob/living/simple_animal/bot/ed209/syndicate/cuff(mob/living/carbon/C) +/mob/living/simple_animal/bot/ed209/syndicate/start_cuffing(mob/living/carbon/C) shootAt(C) /mob/living/simple_animal/bot/ed209/syndicate/stun_attack(mob/living/carbon/C) diff --git a/code/modules/pda/PDA.dm b/code/modules/pda/PDA.dm index 55974349805..a6a30af5cfc 100755 --- a/code/modules/pda/PDA.dm +++ b/code/modules/pda/PDA.dm @@ -250,7 +250,7 @@ GLOBAL_LIST_EMPTY(PDAs) playsound(src, 'sound/machines/pda_button1.ogg', 50, TRUE) return -/obj/item/pda/attackby(obj/item/C as obj, mob/user as mob, params) +/obj/item/pda/attackby(obj/item/C, mob/user, params) ..() if(istype(C, /obj/item/cartridge) && !cartridge) cartridge = C @@ -260,8 +260,6 @@ GLOBAL_LIST_EMPTY(PDAs) update_shortcuts() to_chat(user, "You insert [cartridge] into [src].") SStgui.update_uis(src) - if(cartridge.radio) - cartridge.radio.hostpda = src playsound(src, 'sound/machines/pda_button1.ogg', 50, TRUE) else if(istype(C, /obj/item/card/id)) diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm index 6e703b39d69..3b48da0b607 100644 --- a/code/modules/pda/cart.dm +++ b/code/modules/pda/cart.dm @@ -9,8 +9,6 @@ /// Integrated signaler for captain, science & generic signaler cartridge var/obj/item/assembly/signaler/integ_signaler - var/obj/item/integrated_radio/radio = null - var/charges = 0 var/list/stored_data = list() @@ -18,7 +16,6 @@ var/list/messenger_plugins = list() /obj/item/cartridge/Destroy() - QDEL_NULL(radio) QDEL_LIST(programs) QDEL_LIST(messenger_plugins) return ..() @@ -70,10 +67,6 @@ new /datum/data/pda/app/secbot_control ) -/obj/item/cartridge/security/Initialize(mapload) - . = ..() - radio = new /obj/item/integrated_radio/beepsky(src) - /obj/item/cartridge/detective name = "D.E.T.E.C.T. Cartridge" icon_state = "cart-s" @@ -148,10 +141,6 @@ new /datum/data/pda/app/mule_control ) -/obj/item/cartridge/quartermaster/Initialize(mapload) - . = ..() - radio = new /obj/item/integrated_radio/mule(src) - /obj/item/cartridge/head name = "Easy-Record DELUXE" icon_state = "cart-h" @@ -170,10 +159,6 @@ new /datum/data/pda/app/status_display ) -/obj/item/cartridge/hop/Initialize(mapload) - . = ..() - radio = new /obj/item/integrated_radio/mule(src) - /obj/item/cartridge/hos name = "R.O.B.U.S.T. DELUXE" icon_state = "cart-hos" @@ -183,10 +168,6 @@ new /datum/data/pda/app/status_display ) -/obj/item/cartridge/hos/Initialize(mapload) - . = ..() - radio = new /obj/item/integrated_radio/beepsky(src) - /obj/item/cartridge/ce name = "Power-On DELUXE" icon_state = "cart-ce" @@ -242,7 +223,6 @@ /obj/item/cartridge/captain/Initialize(mapload) . = ..() - radio = new /obj/item/integrated_radio/beepsky(src) integ_signaler = new /obj/item/assembly/signaler(src) /obj/item/cartridge/supervisor @@ -271,10 +251,6 @@ new /datum/data/pda/app/status_display ) -/obj/item/cartridge/centcom/Initialize(mapload) - . = ..() - radio = new /obj/item/integrated_radio/beepsky(src) - /obj/item/cartridge/syndicate name = "Detomatix Cartridge" icon_state = "cart" diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm index 3b6c0300a8c..1dabee72ebf 100644 --- a/code/modules/pda/cart_apps.dm +++ b/code/modules/pda/cart_apps.dm @@ -201,40 +201,41 @@ template = "pda_secbot" category = "Security" + var/active_uid = null + /datum/data/pda/app/secbot_control/update_ui(mob/user as mob, list/data) var/list/botsData = list() var/list/beepskyData = list() - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - var/obj/item/integrated_radio/beepsky/SC = pda.cartridge.radio - beepskyData["active"] = SC.active ? sanitize(SC.active.name) : null - has_back = SC.active ? 1 : 0 - if(SC.active && !isnull(SC.botstatus)) - var/area/loca = SC.botstatus["loca"] - var/loca_name = sanitize(loca.name) - beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) - else - beepskyData["botstatus"] = list("loca" = null, "mode" = -1) - var/botsCount=0 - if(SC.botlist && SC.botlist.len) - for(var/mob/living/simple_animal/bot/B in SC.botlist) - botsCount++ - if(B.loc) - botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "uid" = "[B.UID()]") - if(!botsData.len) + var/mob/living/simple_animal/bot/secbot/active_bot = locateUID(active_uid) + + if(active_bot && !QDELETED(active_bot)) + beepskyData["active"] = active_bot ? sanitize(active_bot.name) : null + has_back = !!active_bot + if(active_bot && !isnull(active_bot.mode)) + var/area/loca = get_area(active_bot) + var/loca_name = sanitize(loca.name) + beepskyData["botstatus"] = list("loca" = loca_name, "mode" = active_bot.mode) + + else + var/botsCount = 0 + var/list/mob/living/simple_animal/bot/bots = list() + for(var/mob/living/simple_animal/bot/secbot/SB in GLOB.bots_list) + bots += SB + for(var/mob/living/simple_animal/bot/ed209/ED in GLOB.bots_list) + bots += ED + + for(var/mob/living/simple_animal/bot/B in bots) + botsCount++ + if(B.loc) + botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(get_area(B).name), "uid" = "[B.UID()]") + + if(!length(botsData)) botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null) beepskyData["bots"] = botsData beepskyData["count"] = botsCount - else - beepskyData["active"] = 0 - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null) - beepskyData["botstatus"] = list("loca" = null, "mode" = null) - beepskyData["bots"] = botsData - beepskyData["count"] = 0 - has_back = 0 - data["beepsky"] = beepskyData /datum/data/pda/app/secbot_control/ui_act(action, list/params) @@ -246,36 +247,26 @@ . = TRUE - // Aight listen up. Its time for a comment rant again. - // The old way of doing this was to proxy things directly from the NanoUI into the PDA's cartridge's radio Topic() function directly - // It was AWFUL and took me 30 minutes to even understand - // This is in no way a good solution, but it works atleast - // Why do we rely on this whole "magical radio system" anyways - // Hell, I would rather take GLOBs with direct interactions over this - // WHYYYYYYYYYYYYYYY -aa07 - switch(action) - if("Back") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "botlist")) - if("Rescan") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "scanbots")) - if("AccessBot") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "control", bot = params["uid"])) - if("Stop") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "stop")) - if("Go") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "go")) - if("Home") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "home")) - if("Summon") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky)) - pda.cartridge.radio.Topic(null, list(op = "summon")) + if("control") + active_uid = params["bot"] + + if("botlist", "Back") // "Back" is part of the PDA TGUI itself. + active_uid = null + + if("stop", "go", "home") + var/mob/living/simple_animal/bot/active_bot = locateUID(active_uid) + if(active_bot && !QDELETED(active_bot)) + active_bot.handle_command(usr, action) + else + active_uid = null + + if("summon") + var/mob/living/simple_animal/bot/active_bot = locateUID(active_uid) + if(active_bot && !QDELETED(active_bot)) + active_bot.handle_command(usr, "summon", list("target" = get_turf(usr), "useraccess" = usr.get_access())) + else + active_uid = null /datum/data/pda/app/mule_control name = "Delivery Bot Control" @@ -283,27 +274,37 @@ template = "pda_mule" category = "Quartermaster" + var/active_uid = null + /datum/data/pda/app/mule_control/update_ui(mob/user as mob, list/data) var/list/muleData = list() var/list/mulebotsData = list() - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - var/obj/item/integrated_radio/mule/QC = pda.cartridge.radio - muleData["active"] = QC.active ? sanitize(QC.active.name) : null - has_back = QC.active ? 1 : 0 - if(QC.active && !isnull(QC.botstatus)) - var/area/loca = QC.botstatus["loca"] + + var/mob/living/simple_animal/bot/mulebot/active_bot = locateUID(active_uid) + + if(active_bot && !QDELETED(active_bot)) + muleData["active"] = active_bot ? sanitize(active_bot.name) : null + has_back = !!active_bot + if(active_bot && !isnull(active_bot.mode)) + var/area/loca = get_area(active_bot) var/loca_name = sanitize(loca.name) - muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) + muleData["botstatus"] = list( + "loca" = loca_name, + "mode" = active_bot.mode, + "home" = active_bot.home_destination, + "powr" = (active_bot.cell ? active_bot.cell.percent() : 0), + "retn" = active_bot.auto_return, + "pick" = active_bot.auto_pickup, + "load" = active_bot.load, + "dest" = sanitize(active_bot.destination) + ) - else - muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) - - - var/mulebotsCount=0 - for(var/mob/living/simple_animal/bot/B in QC.botlist) + else + var/mulebotsCount = 0 + for(var/mob/living/simple_animal/bot/mulebot/B in GLOB.bots_list) mulebotsCount++ if(B.loc) - mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "uid" = "[B.UID()]") + mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = get_area(B).name, "uid" = "[B.UID()]") if(!mulebotsData.len) mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null) @@ -311,14 +312,6 @@ muleData["bots"] = mulebotsData muleData["count"] = mulebotsCount - else - muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) - muleData["active"] = 0 - mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null) - muleData["bots"] = mulebotsData - muleData["count"] = 0 - has_back = 0 - data["mulebot"] = muleData /datum/data/pda/app/mule_control/ui_act(action, list/params) @@ -330,40 +323,26 @@ . = TRUE - // Heres the exact same shit as before, but worse - // See L257 to L263 for explanation - switch(action) - if("Back") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "botlist")) - if("Rescan") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "scanbots")) - if("AccessBot") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "control", bot = params["uid"])) - if("Unload") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "unload")) - if("SetDest") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "setdest")) - if("SetAutoReturn") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = params["autoReturnType"])) // "retoff" or "reton" - if("SetAutoPickup") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = params["autoPickupType"])) // "pickoff" or "pickon" - if("Stop") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "stop")) - if("Start") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "start")) - if("ReturnHome") - if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule)) - pda.cartridge.radio.Topic(null, list(op = "home")) + if("control") + active_uid = params["bot"] + + if("botlist", "Back") // "Back" is part of the PDA TGUI itself. + active_uid = null + + if("stop", "start", "home", "unload", "target") + var/mob/living/simple_animal/bot/active_bot = locateUID(active_uid) + if(active_bot && !QDELETED(active_bot)) + active_bot.handle_command(usr, action) + else + active_uid = null + + if("set_auto_return", "set_pickup_type") + var/mob/living/simple_animal/bot/active_bot = locateUID(active_uid) + if(active_bot && !QDELETED(active_bot)) + active_bot.handle_command(usr, action, params) + else + active_uid = null /datum/data/pda/app/supply name = "Supply Records" diff --git a/code/modules/pda/pda_tgui.dm b/code/modules/pda/pda_tgui.dm index c79af319a88..e77ac2da45a 100644 --- a/code/modules/pda/pda_tgui.dm +++ b/code/modules/pda/pda_tgui.dm @@ -86,8 +86,6 @@ scanmode = null if(current_app in C.programs) start_program(find_program(/datum/data/pda/app/main_menu)) - if(C.radio) - C.radio.hostpda = null for(var/datum/data/pda/P in notifying_programs) if(P in C.programs) P.unnotify() diff --git a/code/modules/pda/radio.dm b/code/modules/pda/radio.dm deleted file mode 100644 index b7068ee07eb..00000000000 --- a/code/modules/pda/radio.dm +++ /dev/null @@ -1,145 +0,0 @@ -//TODO convert this crap over to proper radios or find a way to utilize regualr radios for this object, this thing needs to go. - -/obj/item/integrated_radio - name = "\improper PDA radio module" - desc = "An electronic radio system of Nanotrasen origin." - icon = 'icons/obj/module.dmi' - icon_state = "power_mod" - var/obj/item/pda/hostpda = null - var/list/botlist = null // list of bots - var/mob/living/simple_animal/bot/active // the active bot; if null, show bot list - var/list/botstatus // the status signal sent by the bot - var/bot_type //The type of bot it is. - var/bot_filter //Determines which radio filter to use. - - var/control_freq = 1447 - - var/on = FALSE //Are we currently active?? - var/menu_message = "" - -/obj/item/integrated_radio/Initialize(mapload) - . = ..() - if(istype(loc.loc, /obj/item/pda)) - hostpda = loc.loc - if(bot_filter) - add_to_radio(bot_filter) - -/obj/item/integrated_radio/Destroy() - if(SSradio) - SSradio.remove_object(src, control_freq) - hostpda = null - return ..() - -/obj/item/integrated_radio/proc/post_signal(freq, key, value, key2, value2, key3, value3, key4, value4, s_filter) - -// to_chat(world, "Post: [freq]: [key]=[value], [key2]=[value2]") - var/datum/radio_frequency/frequency = SSradio.return_frequency(freq) - - if(!frequency) - return - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = 1 - signal.data[key] = value - if(key2) - signal.data[key2] = value2 - if(key3) - signal.data[key3] = value3 - if(key4) - signal.data[key4] = value4 - - frequency.post_signal(src, signal, filter = s_filter) - -/obj/item/integrated_radio/receive_signal(datum/signal/signal) - if(bot_type && istype(signal.source, /obj/machinery/bot_core) && signal.data["type"] == bot_type) - if(!botlist) - botlist = new() - - var/obj/machinery/bot_core/core = signal.source - - if(istype(core) && !(core.owner in botlist)) - botlist += core.owner - - if(active == core.owner) - var/list/b = signal.data - botstatus = b.Copy() - -/obj/item/integrated_radio/Topic(href, href_list) - ..() - switch(href_list["op"]) - if("control") - active = locateUID(href_list["bot"]) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) - - if("scanbots") // find all bots - botlist = null - post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) - - if("botlist") - active = null - - if("stop", "go", "home") - post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) - - if("summon") - post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(hostpda), "useraccess", hostpda.GetAccess(), "user", usr, s_filter = bot_filter) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) - -/obj/item/integrated_radio/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. - if(SSradio) - SSradio.add_object(src, control_freq, filter = bot_filter) - -/obj/item/integrated_radio/honkbot - bot_filter = RADIO_HONKBOT - bot_type = HONK_BOT - -/obj/item/integrated_radio/beepsky - bot_filter = RADIO_SECBOT - bot_type = SEC_BOT - -/obj/item/integrated_radio/medbot - bot_filter = RADIO_MEDBOT - bot_type = MED_BOT - -/obj/item/integrated_radio/floorbot - bot_filter = RADIO_FLOORBOT - bot_type = FLOOR_BOT - -/obj/item/integrated_radio/cleanbot - bot_filter = RADIO_CLEANBOT - bot_type = CLEAN_BOT - -/obj/item/integrated_radio/mule - bot_filter = RADIO_MULEBOT - bot_type = MULE_BOT - -/obj/item/integrated_radio/mule/Topic(href, href_list) - ..() - switch(href_list["op"]) - if("start") - post_signal(control_freq, "command", "start", "active", active, s_filter = RADIO_MULEBOT) - - if("unload") - post_signal(control_freq, "command", "unload", "active", active, s_filter = RADIO_MULEBOT) - - if("setdest") - if(GLOB.deliverybeacons) - var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in GLOB.deliverybeacontags - if(dest) - post_signal(control_freq, "command", "target", "active", active, "destination", dest, s_filter = RADIO_MULEBOT) - - if("retoff") - post_signal(control_freq, "command", "autoret", "active", active, "value", 0, s_filter = RADIO_MULEBOT) - - if("reton") - post_signal(control_freq, "command", "autoret", "active", active, "value", 1, s_filter = RADIO_MULEBOT) - - if("pickoff") - post_signal(control_freq, "command", "autopick", "active", active, "value", 0, s_filter = RADIO_MULEBOT) - - if("pickon") - post_signal(control_freq, "command", "autopick", "active", active, "value", 1, s_filter = RADIO_MULEBOT) - - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_MULEBOT) diff --git a/paradise.dme b/paradise.dme index fc1dfdd7707..cce964c1fca 100644 --- a/paradise.dme +++ b/paradise.dme @@ -2251,7 +2251,6 @@ #include "code\modules\pda\PDA.dm" #include "code\modules\pda\pda_tgui.dm" #include "code\modules\pda\pdas.dm" -#include "code\modules\pda\radio.dm" #include "code\modules\pda\utilities.dm" #include "code\modules\persistence\persistence.dm" #include "code\modules\power\apc.dm" diff --git a/tgui/packages/tgui/interfaces/pda/pda_mule.js b/tgui/packages/tgui/interfaces/pda/pda_mule.js index d604324757a..f1076f4ca45 100644 --- a/tgui/packages/tgui/interfaces/pda/pda_mule.js +++ b/tgui/packages/tgui/interfaces/pda/pda_mule.js @@ -14,27 +14,15 @@ const BotList = (props, context) => { const { mulebot } = data; const { bots } = mulebot; - return ( - - {bots.map((b) => ( - -