diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index e0ab40eba492..12a654fe83f5 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -55,6 +55,8 @@ #define GLAND_HUD "25" /// Pressure coloring for tiles #define PRESSURE_HUD "26" +/// AI shell status +#define DIAG_AISHELL_STAT_HUD "27" /// Telepathy bubbles #define THOUGHT_HUD "thoughts_hud" /// Kidan pheromones hud diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 0be81d918edb..339d7f36532c 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -154,6 +154,14 @@ #define ROBOT_NOTIFY_AI_CONNECTED 1 //New Cyborg #define ROBOT_NOTIFY_AI_MODULE 2 //New Module #define ROBOT_NOTIFY_AI_NAME 3 //New Name +#define AI_NOTIFICATION_AI_SHELL 4 //New AI shell +//'evacuate_ai()' proc danger levels +#define DANGER_LVL_NONE "danger_level_none" //0% kill chance +#define DANGER_LVL_MAY_DIE "danger_level_may_die" //50% kill chance +#define DANGER_LVL_INSTA_DEATH "danger_level_insta_death" //100% kill chance +//'robot.attack_ai()' proc tgui_input desicsions +#define AISHELL_CONNECT_POSITIVE "Подключиться" +#define AISHELL_CONNECT_NEGATIVE "Отмена" //determines if a mob can smash through it #define ENVIRONMENT_SMASH_NONE 0 #define ENVIRONMENT_SMASH_STRUCTURES 1 //crates, lockers, ect diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 997bb3e450ea..ac9ced56b620 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -798,7 +798,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) var/selected_borg_name = null var/list/available_borgs = list() for(var/mob/living/silicon/robot/borg in GLOB.player_list) - if(borg.stat == DEAD || borg.connected_ai || borg.scrambledcodes || isdrone(borg) || iscogscarab(borg) || isclocker(borg)) + if(borg.stat == DEAD || borg.connected_ai || borg.scrambledcodes || isdrone(borg) || iscogscarab(borg) || isclocker(borg) || borg.shell) continue var/borg_name = "[borg.real_name] ([borg.modtype?.name] [borg.braintype])" available_borgs[borg_name] = borg diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index f34a1ff07720..78e962f0d514 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -165,6 +165,8 @@ #define ui_ai_up "TOP:-6,RIGHT-1" #define ui_ai_down "TOP:-6,RIGHT" +#define ui_ai_connect_to_shell "BOTTOM:6,LEFT+3" + // Bots #define ui_bot_radio "EAST-1:28,SOUTH:7" #define ui_bot_pull "EAST-2:26,SOUTH:7" diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 055c5c24952d..9dada23b72ad 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -160,6 +160,16 @@ var/mob/living/silicon/ai/AI = usr AI.move_down() +/atom/movable/screen/ai/connect_to_shell + name = "Подключиться к оболочке" + icon_state = "AIshell" + +/atom/movable/screen/ai/connect_to_shell/Click() + if(!isAI(usr)) + return + var/mob/living/silicon/ai/AI = usr + AI.deploy_to_shell() + /datum/hud/ai/New(mob/owner) ..() @@ -259,3 +269,8 @@ using = new /atom/movable/screen/ai/move_down(null, src) using.screen_loc = ui_ai_down static_inventory += using + +//Connect to shell + using = new /atom/movable/screen/ai/connect_to_shell(null, src) + using.screen_loc = ui_ai_connect_to_shell + static_inventory += using diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 010d7d91903d..4f62f15a21ec 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -47,10 +47,10 @@ hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPMINDSHIELD_HUD, IMPCHEM_HUD, WANTED_HUD) /datum/atom_hud/data/diagnostic - hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD) + hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_AISHELL_STAT_HUD) /datum/atom_hud/data/diagnostic/advanced - hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_PATH_HUD) + hud_icons = list(DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD, DIAG_AIRLOCK_HUD, DIAG_PATH_HUD, DIAG_AISHELL_STAT_HUD) /datum/atom_hud/data/bot_path // This hud exists so the bot can see itself, that's all diff --git a/code/game/gamemodes/clockwork/clock_magic.dm b/code/game/gamemodes/clockwork/clock_magic.dm index 9e9e5fff31a0..903d3e0c8ef1 100644 --- a/code/game/gamemodes/clockwork/clock_magic.dm +++ b/code/game/gamemodes/clockwork/clock_magic.dm @@ -366,7 +366,7 @@ playsound(get_turf(src), 'sound/machines/airlockforced.ogg', 80, TRUE) do_sparks(5, TRUE, target) if(do_after(user, 9 SECONDS, candidate)) - candidate.emp_act(EMP_HEAVY) + candidate.Stun(6 SECONDS) candidate.ratvar_act(weak = TRUE) SSticker?.score?.save_silicon_laws(candidate, user, "Ratvar act", log_all_laws = TRUE) channeling = FALSE diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 70675cb7e78d..eba842c5351f 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -397,6 +397,13 @@ structure_check() searches for nearby cultist structures required for the invoca playsound(offering, 'sound/misc/demon_consume.ogg', 100, TRUE) if((ishuman(offering) || isrobot(offering) || isbrain(offering)) && offering.mind) + if(isrobot(offering)) + var/mob/living/silicon/robot/robot = offering + if(robot.shell && robot.mainframe) + robot.evacuate_ai(DANGER_LVL_INSTA_DEATH) + robot.dust() + playsound(offering, 'sound/magic/disintegrate.ogg', 100, TRUE) + return TRUE var/obj/item/soulstone/stone = new /obj/item/soulstone(get_turf(src)) stone.invisibility = INVISIBILITY_MAXIMUM // So it's not picked up during transfer_soul() stone.transfer_soul("FORCE", offering, user) // If it cannot be added diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 19965ea5aa13..d1287dc96bc0 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -134,6 +134,10 @@ installed_module.transmit_instructions(current, user, reg_name) to_chat(current, "These are your laws now:") current.show_laws() + if(isAI(current)) + var/mob/living/silicon/ai/AI = current + if(AI.deployed_shell) + AI.deployed_shell.show_laws() for(var/mob/living/silicon/robot/R in GLOB.mob_list) if(R.lawupdate && (R.connected_ai == current)) to_chat(R, "These are your laws now:") diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 214caccc52a4..d303de8173ab 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -45,8 +45,6 @@ return FALSE if(iscogscarab(R)) return FALSE - if(iscogscarab(R)) - return FALSE if(R.scrambledcodes) return FALSE if(!are_zs_connected(src, R)) @@ -162,6 +160,8 @@ synchronization = R.connected_ai, is_hacked = R.connected_ai && R.emagged, hackable = can_hack(user, R), + is_shell = R.shell, + occupier = R.mainframe? R.mainframe.name : "None", ) data["cyborgs"] += list(cyborg_data) data["show_detonate_all"] = (data["auth"] && length(data["cyborgs"]) > 0 && ishuman(user)) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 0ef39e5eadf0..0bb9c15101be 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -138,8 +138,77 @@ if(l_leg && r_leg) if(chest && head) SSblackbox.record_feedback("amount", "cyborg_frames_built", 1) - return 1 - return 0 + return TRUE + return FALSE + +/obj/item/robot_parts/robot_suit/proc/install_cell(mob/living/silicon/robot/target) + chest.cell.forceMove(target) + target.cell = chest.cell + chest.cell = null + // Since we "magically" installed a cell, we also have to update the correct component. + var/datum/robot_component/cell_component = target.components["power cell"] + cell_component.wrapped = target.cell + cell_component.installed = TRUE + +/obj/item/robot_parts/robot_suit/proc/check_locomotion(mob/living/silicon/robot/target) + if(locomotion) + return + target.set_lockcharge(TRUE) + to_chat(target, span_warning("Error: Servo motors unresponsive.")) + +/obj/item/robot_parts/robot_suit/proc/check_lawsync() + if(!aisync) + lawsync = FALSE + if(sabotaged) + aisync = FALSE + lawsync = FALSE + +/obj/item/robot_parts/robot_suit/proc/get_new_laws(obj/item/mmi/new_mmi) + if(new_mmi.syndicate) // ffs + aisync = FALSE + lawsync = FALSE + return new /datum/ai_laws/syndicate_override + if(new_mmi.ninja) + aisync = FALSE + lawsync = FALSE + return new /datum/ai_laws/ninja_override + if(new_mmi.clock) + aisync = FALSE + lawsync = FALSE + return new /datum/ai_laws/ratvar + +/obj/item/robot_parts/robot_suit/proc/apply_debug_stats(mob/living/silicon/robot/target) + target.custom_name = created_name + target.rename_character(target.real_name, target.get_default_name()) + target.locked = panel_locked + +/obj/item/robot_parts/robot_suit/proc/give_new_laws(mob/living/silicon/robot/target, datum/ai_laws/laws_to_give) + if(laws_to_give) + target.laws = laws_to_give + return + if(lawsync) + return + target.lawupdate = FALSE + target.make_laws() + +/obj/item/robot_parts/robot_suit/proc/check_special_role(obj/item/mmi/mmi, mob/living/silicon/robot/target, mob/living/user) + if(mmi.greet(target) && !target.mind.special_role) + return + target.mind.store_memory("As a cyborg, you must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.") + to_chat(target, span_userdanger("You have been robotized!")) + to_chat(target, span_danger("You must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.")) + +/obj/item/robot_parts/robot_suit/proc/process_clocker_cyborg(mob/living/silicon/robot/target) + if(!target.mmi.clock) // so robots created from vessel have magic + return + target.UnlinkSelf() + SSticker.mode.add_clock_actions(target.mind) + +/obj/item/robot_parts/robot_suit/proc/process_job_task(mob/living/target) + var/datum/job_objective/make_cyborg/task = target.mind.findJobTask(/datum/job_objective/make_cyborg) + if(!istype(task)) + return + task.unit_completed() /obj/item/robot_parts/robot_suit/multitool_act(mob/living/user, obj/item/I) . = TRUE @@ -244,143 +313,129 @@ update_icon(UPDATE_OVERLAYS) return ATTACK_CHAIN_BLOCKED_ALL - if(!is_mmi(I)) - return ..() - - . = ATTACK_CHAIN_PROCEED - add_fingerprint(user) - var/obj/item/mmi/new_mmi = I - if(!check_completion()) - to_chat(user, span_warning("The MMI must go in after everything else!")) - return . - - if(new_mmi.clock && !isclocker(user)) - to_chat(user, span_danger("An overwhelming feeling of dread comes over you as you attempt to put the soul vessel into the frame.")) - user.Confused(20 SECONDS) - user.Jitter(12 SECONDS) - return ATTACK_CHAIN_BLOCKED_ALL - - if(!isturf(loc)) - to_chat(user, span_warning("You can't put [new_mmi] in, the frame has to be standing on the ground to be perfectly precise.")) - return . - - if(!new_mmi.brainmob) - to_chat(user, span_warning("Sticking an empty [new_mmi.name] into the frame would sort of defeat the purpose.")) - return . + if(istype(I, /obj/item/borg/upgrade/ai)) - if(!new_mmi.brainmob.key) - var/ghost_can_reenter = FALSE - if(new_mmi.brainmob.mind) - for(var/mob/dead/observer/observer in GLOB.player_list) - if(observer.can_reenter_corpse && observer.mind == new_mmi.brainmob.mind) - ghost_can_reenter = TRUE - if(new_mmi.next_possible_ghost_ping < world.time) - observer.notify_cloning("Somebody is trying to borg you! Re-enter your corpse if you want to be borged!", 'sound/voice/liveagain.ogg', src) - new_mmi.next_possible_ghost_ping = world.time + 30 SECONDS // Avoid spam - break - if(ghost_can_reenter) - to_chat(user, span_warning("The [new_mmi.name] is currently inactive. Try again later.")) - else - to_chat(user, span_warning("The [new_mmi.name] is completely unresponsive; there's no point to use it.")) + . = ATTACK_CHAIN_PROCEED + add_fingerprint(user) + var/obj/item/borg/upgrade/ai/module = I + if(!check_completion()) + to_chat(user, span_warning("The B.O.R.I.S. module must go in after everything else!")) + return . + + if(!isturf(loc)) + to_chat(user, span_warning("You can't put [module] in, the frame has to be standing on the ground to be perfectly precise.")) + return . + + check_lawsync() + + if(iscarbon(user)) + var/mob/living/carbon/carbon = user + if(carbon.drop_item_ground(module)) + qdel(module) + var/mob/living/silicon/robot/new_shell = new /mob/living/silicon/robot/shell(get_turf(src)) + if(QDELETED(new_shell)) + return . + + . = ATTACK_CHAIN_BLOCKED_ALL + + process_job_task(user) + apply_debug_stats(new_shell) + new_shell.job = JOB_TITLE_CYBORG + install_cell(new_shell) + forceMove(new_shell) + new_shell.robot_suit = src + check_locomotion(new_shell) return . - if(jobban_isbanned(new_mmi.brainmob, JOB_TITLE_CYBORG) || jobban_isbanned(new_mmi.brainmob, "nonhumandept")) - to_chat(user, span_warning("This [new_mmi.name] is not fit to serve as a cyborg!")) - return . + if(is_mmi(I)) - if(new_mmi.brainmob.stat == DEAD) - to_chat(user, span_warning("Sticking a dead [new_mmi.name] into the frame would sort of defeat the purpose.")) - return . + . = ATTACK_CHAIN_PROCEED + add_fingerprint(user) + var/obj/item/mmi/new_mmi = I + if(!check_completion()) + to_chat(user, span_warning("The MMI must go in after everything else!")) + return . + + if(new_mmi.clock && !isclocker(user)) + to_chat(user, span_danger("An overwhelming feeling of dread comes over you as you attempt to put the soul vessel into the frame.")) + user.Confused(20 SECONDS) + user.Jitter(12 SECONDS) + return ATTACK_CHAIN_BLOCKED_ALL + + if(!isturf(loc)) + to_chat(user, span_warning("You can't put [new_mmi] in, the frame has to be standing on the ground to be perfectly precise.")) + return . + + if(!new_mmi.brainmob) + to_chat(user, span_warning("Sticking an empty [new_mmi.name] into the frame would sort of defeat the purpose.")) + return . + + if(!new_mmi.brainmob.key) + var/ghost_can_reenter = FALSE + if(new_mmi.brainmob.mind) + for(var/mob/dead/observer/observer in GLOB.player_list) + if(observer.can_reenter_corpse && observer.mind == new_mmi.brainmob.mind) + ghost_can_reenter = TRUE + if(new_mmi.next_possible_ghost_ping < world.time) + observer.notify_cloning("Somebody is trying to borg you! Re-enter your corpse if you want to be borged!", 'sound/voice/liveagain.ogg', src) + new_mmi.next_possible_ghost_ping = world.time + 30 SECONDS // Avoid spam + break + if(ghost_can_reenter) + to_chat(user, span_warning("The [new_mmi.name] is currently inactive. Try again later.")) + else + to_chat(user, span_warning("The [new_mmi.name] is completely unresponsive; there's no point to use it.")) + return . + + if(jobban_isbanned(new_mmi.brainmob, JOB_TITLE_CYBORG) || jobban_isbanned(new_mmi.brainmob, "nonhumandept")) + to_chat(user, span_warning("This [new_mmi.name] is not fit to serve as a cyborg!")) + return . + + if(new_mmi.brainmob.stat == DEAD) + to_chat(user, span_warning("Sticking a dead [new_mmi.name] into the frame would sort of defeat the purpose.")) + return . + + if(new_mmi.brainmob.mind in SSticker.mode.head_revolutionaries) + to_chat(user, span_warning("The frame's firmware lets out a shrill sound, and flashes 'Abnormal Memory Engram'. It refuses to accept [new_mmi].")) + return . + + var/datum/ai_laws/laws_to_give + check_lawsync() + laws_to_give = get_new_laws(new_mmi) + + var/mob/living/silicon/robot/new_borg = new(loc, syndie = sabotaged, unfinished = TRUE, ai_to_sync_to = forced_ai, connect_to_AI = aisync) + if(QDELETED(new_borg)) // somehow??? jesus fucking christ + return . + + if(!user.drop_transfer_item_to_loc(new_mmi, src)) + return ..() - if(new_mmi.brainmob.mind in SSticker.mode.head_revolutionaries) - to_chat(user, span_warning("The frame's firmware lets out a shrill sound, and flashes 'Abnormal Memory Engram'. It refuses to accept [new_mmi].")) - return . + . = ATTACK_CHAIN_BLOCKED_ALL - var/datum/ai_laws/laws_to_give - if(!aisync) - lawsync = FALSE + process_job_task(user) + new_borg.invisibility = 0 + new_mmi.forceMove(new_borg) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. + //Transfer debug settings to new mob + apply_debug_stats(new_borg) + give_new_laws(new_borg, laws_to_give) + new_mmi.brainmob.mind.transfer_to(new_borg) - if(sabotaged) - aisync = FALSE - lawsync = FALSE + SSticker?.score?.save_silicon_laws(new_borg, user, "robot construction", log_all_laws = TRUE) - if(new_mmi.syndicate) // ffs - aisync = FALSE - lawsync = FALSE - laws_to_give = new /datum/ai_laws/syndicate_override + check_special_role(new_mmi, new_borg, user) + new_borg.job = JOB_TITLE_CYBORG + install_cell(new_borg) + new_borg.mmi = new_mmi + new_borg.Namepick() - if(new_mmi.ninja) - aisync = FALSE - lawsync = FALSE - laws_to_give = new /datum/ai_laws/ninja_override + SSblackbox.record_feedback("amount", "cyborg_birth", 1) - if(new_mmi.clock) - aisync = FALSE - lawsync = FALSE - laws_to_give = new /datum/ai_laws/ratvar - - var/mob/living/silicon/robot/new_borg = new(loc, syndie = sabotaged, unfinished = TRUE, ai_to_sync_to = forced_ai, connect_to_AI = aisync) - if(QDELETED(new_borg)) // somehow??? jesus fucking christ + forceMove(new_borg) + new_borg.robot_suit = src + new_borg.mmi.apply_effects(new_borg) + process_clocker_cyborg(new_borg) + check_locomotion(new_borg) return . - if(!user.drop_transfer_item_to_loc(new_mmi, src)) - return ..() - - . = ATTACK_CHAIN_BLOCKED_ALL - - var/datum/job_objective/make_cyborg/task = user.mind.findJobTask(/datum/job_objective/make_cyborg) - if(istype(task)) - task.unit_completed() - - new_borg.invisibility = 0 - new_mmi.forceMove(new_borg) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. - //Transfer debug settings to new mob - new_borg.custom_name = created_name - new_borg.rename_character(new_borg.real_name, new_borg.get_default_name()) - new_borg.locked = panel_locked - - if(laws_to_give) - new_borg.laws = laws_to_give - else if(!lawsync) - new_borg.lawupdate = FALSE - new_borg.make_laws() - - new_mmi.brainmob.mind.transfer_to(new_borg) - - SSticker?.score?.save_silicon_laws(new_borg, user, "robot construction", log_all_laws = TRUE) - - if(!new_mmi.greet(new_borg) && new_borg.mind?.special_role) - new_borg.mind.store_memory("As a cyborg, you must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.") - to_chat(new_borg, span_userdanger("You have been robotized!")) - to_chat(new_borg, span_danger("You must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.")) - - new_borg.job = JOB_TITLE_CYBORG - - chest.cell.forceMove(new_borg) - new_borg.cell = chest.cell - chest.cell = null - // Since we "magically" installed a cell, we also have to update the correct component. - var/datum/robot_component/cell_component = new_borg.components["power cell"] - cell_component.wrapped = new_borg.cell - cell_component.installed = TRUE - new_borg.mmi = new_mmi - new_borg.Namepick() - - SSblackbox.record_feedback("amount", "cyborg_birth", 1) - - forceMove(new_borg) - new_borg.robot_suit = src - - new_borg.mmi.apply_effects(new_borg) - - if(new_borg.mmi.clock) // so robots created from vessel have magic - new_borg.UnlinkSelf() - SSticker.mode.add_clock_actions(new_borg.mind) - - if(!locomotion) - new_borg.set_lockcharge(TRUE) - to_chat(new_borg, span_warning("Error: Servo motors unresponsive.")) - /obj/item/robot_parts/robot_suit/proc/Interact(mob/user) var/t1 = "Designation: [(created_name ? "[created_name]" : "Default Cyborg")]
\n" t1 += "Master AI: [(forced_ai ? "[forced_ai.name]" : "Automatic")]

\n" diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index e59d55f87a4c..1f0a472508b1 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -111,6 +111,9 @@ if(user) to_chat(user, "[span_danger("UPGRADE ERROR: ")]" + "[span_notice("you have to repair the cyborg before using this module!")]") return FALSE + if(robot.shell) + to_chat(user, "[span_danger("UPGRADE ERROR: ")]" + "[span_notice("cant apply on a AI shell!")]") + return FALSE if(!robot.key) for(var/mob/dead/observer/ghost in GLOB.player_list) @@ -864,3 +867,35 @@ /obj/item/borg/upgrade/mounted_seat/pre_emaged emagged = TRUE + +/obj/item/borg/upgrade/ai + name = "B.O.R.I.S. module" + desc = "Модуль Блюспейс Ориентированной Роботической Искусственной Сети. При установке в киборга, позволяет ИИ управлять им напрямую." + icon_state = "r_boris" + +/obj/item/borg/upgrade/ai/get_ru_names() + return list( + NOMINATIVE = "модуль Б.О.Р.И.С.", + GENITIVE = "модуля Б.О.Р.И.С.", + DATIVE = "модулю Б.О.Р.И.С.", + ACCUSATIVE = "модуль Б.О.Р.И.С.", + INSTRUMENTAL = "модулем Б.О.Р.И.С.", + PREPOSITIONAL = "модуле Б.О.Р.И.С.", + ) + +/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/robot, mob/living/user = usr) + . = ..() + if(!.) + return . + if(robot.key) + to_chat(user, span_warning("Зафиксированы активные вычислительные процессы. Подключение невозможно.")) + return FALSE + robot.make_shell(src) + +/obj/item/borg/upgrade/ai/deactivate(mob/living/silicon/robot/robot, mob/living/user = usr) + if(!..()) + return FALSE + + robot.undeploy() + robot.revert_shell() + return TRUE diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index f67a0e09224f..e12acfe53fc6 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -64,6 +64,9 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( var/obj/item/radio/headset/heads/ai_integrated/aiRadio = null + //AI SHELL CONTROL + var/mob/living/silicon/robot/deployed_shell = null + //MALFUNCTION var/datum/module_picker/malf_picker var/datum/action/innate/ai/choose_modules/modules_action @@ -334,18 +337,41 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( popup.open(FALSE) /mob/living/silicon/ai/proc/show_borg_info(list/status_tab_data) - status_tab_data[++status_tab_data.len] = list("Connected cyborg count:", "[length(connected_robots)]") - for(var/mob/living/silicon/robot/R in connected_robots) - var/robot_status = "Nominal" - if(R.stat || !R.client) + var/list/robot_list = list() + var/list/aishell_list = list() + for(var/mob/living/silicon/robot/robot as anything in GLOB.available_ai_shells) + if(robot.connected_ai == src || !robot.connected_ai) + aishell_list += robot + for(var/mob/living/silicon/robot/robot as anything in connected_robots) + if(!robot.shell) + robot_list += robot + + status_tab_data[++status_tab_data.len] = list("Connected cyborg count:", "[length(robot_list)]") + // Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! + for(var/mob/living/silicon/robot/robot as anything in robot_list) + var/robot_status + if(robot.stat || !robot.client) robot_status = "OFFLINE" - else if(!R.cell || R.cell.charge <= 0) + else if(!robot.cell || robot.cell.charge <= 0) robot_status = "DEPOWERED" - // Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! - var/area/A = get_area(R) - var/area_name = A ? sanitize(A.name) : UNKNOWN_STATUS_RUS - status_tab_data[++status_tab_data.len] = list("[R.name]:", "S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge] / [R.cell.maxcharge]" : "Empty"] | \ - Module: [R.designation] | Loc: [area_name] | Status: [robot_status]") + else + robot_status = "Nominal" + var/area/robots_area = get_area(robot) + var/area_name = robots_area ? sanitize(robots_area.name) : UNKNOWN_STATUS_RUS + status_tab_data[++status_tab_data.len] = list("[robot.name]:", "S.Integrity: [robot.health]% | Cell: [robot.cell ? "[robot.cell.charge] / [robot.cell.maxcharge]" : "Empty"] | \ + Module: [robot.designation] | Loc: [area_name] | Status: [robot_status]") + + status_tab_data[++status_tab_data.len] = list("Detected AI shell beacons:", "[length(aishell_list)]") + for(var/mob/living/silicon/robot/robot as anything in aishell_list) + var/shell_status + if(!can_connect_to(robot)) + shell_status = "UNABLE TO CONNECT" + else + shell_status = "Ready to connect" + var/area/robots_area = get_area(robot) + var/area_name = robots_area ? sanitize(robots_area.name) : UNKNOWN_STATUS_RUS + status_tab_data[++status_tab_data.len] = list("Shell-[num2text(robot.ident)]:", "S.Integrity: [robot.health]% | Cell: [robot.cell ? "[robot.cell.charge] / [robot.cell.maxcharge]" : "Empty"] | \ + Module: [robot.designation] | Loc: [area_name] | Status: [shell_status] [(robot.connected_ai == src? null : "| Occupier: [robot.mainframe? "[robot.mainframe.name]" : "NONE"]")]") return status_tab_data /mob/living/silicon/ai/rename_character(oldname, newname) @@ -718,7 +744,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( for(var/mob/living/silicon/robot/R in connected_robots) to_chat(R, span_danger("ERROR: Master AI has be&# &#@)!-")) to_chat(R, span_clocklarge("\"Your master is under my control, so do you\"")) - R.ratvar_act(TRUE) + R.ratvar_act(TRUE, TRUE) SSticker?.score?.save_silicon_laws(R, additional_info = "Ratvar act via master AI conversion", log_all_laws = TRUE) /mob/living/silicon/ai/Topic(href, href_list) @@ -1360,6 +1386,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( update_sight() control_disabled = TRUE//Can't control things remotely if you're stuck in a card! aiRadio.disabledAi = TRUE //No talking on the built-in radio for you either! + if(deployed_shell) + disconnect_shell() forceMove(card) //Throw AI into the card. to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") to_chat(user, "[span_boldnotice("Transfer successful")]: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") @@ -1553,6 +1581,70 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( var/mob/dead/observer/ghost = . ghost.forceMove(old_turf) +//Notifies controlled shell about law change +/mob/living/silicon/ai/proc/notify_shell() + if(deployed_shell) + deployed_shell.show_laws() + +/mob/living/silicon/ai/proc/can_connect_to(mob/living/silicon/robot/target) + if(isclocker(target) && !isclocker(src)) + return FALSE + if(target.key) + return FALSE + if(!target.shell || target.deployed) + return FALSE + if((target.stat == DEAD) || (target.stat == UNCONSCIOUS)) + return FALSE + if(target.connected_ai) + if(target.connected_ai != src) + return FALSE + if(!target.cell) + return FALSE + if(target.cell.charge <= 0) + return FALSE + + return TRUE + +/mob/living/silicon/ai/proc/deploy_to_shell(mob/living/silicon/robot/target) + if(control_disabled) + to_chat(src, span_warning("Подсистема беcпроводного подключения не отвечает.")) + return + + var/list/possible = list() + + for(var/shell in GLOB.available_ai_shells) + var/mob/living/silicon/robot/robot = shell + if(can_connect_to(robot)) + possible += robot + + if(!LAZYLEN(possible)) + to_chat(src, "Активных передатчиков сигнала не обнаружено.") + return + + if(!target || !(target in possible)) + target = tgui_input_list(src, "К какой оболочке подключиться?", "Подключиться", sort_names(possible)) + + if(isnull(target)) + return + if(!can_connect_to(target)) + to_chat(src, span_warning("Во время установки cоеденения с оболочкой произошла ошибка.")) + return + + else + if(!mind) + return + RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(disconnect_shell)) + deployed_shell = target + target.deploy_init(src) + if(isclocker(src)) + target.ratvar_act(TRUE, TRUE) + mind.transfer_to(target) + +/mob/living/silicon/ai/proc/disconnect_shell() + SIGNAL_HANDLER + if(deployed_shell) + deployed_shell.undeploy() + /mob/living/silicon/ai/vv_edit_var(var_name, var_value) if(!..()) return FALSE diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm index d1bdc687042e..2c7f32a56be7 100644 --- a/code/modules/mob/living/silicon/ai/ai_defense.dm +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -15,3 +15,26 @@ to_chat(src, span_warning("Неудача! [src.name] получает видимые повреждения.")) src.adjustBruteLoss(rand(15, 20)) return FALSE + +/mob/living/silicon/ai/adjustBruteLoss(amount = 0, updating_health = TRUE, def_zone = null, blocked = 0, forced = FALSE, used_weapon = null, sharp = FALSE, silent = FALSE, affect_robotic = TRUE,) + . = ..() + if(amount < 0) + return + if(!deployed_shell) + return + to_chat(deployed_shell, span_warningbig("ТРЕВОГА: ЗАФИКСИРОВАНО ПОВРЕЖДЕНИЕ ЯДРА")) + SEND_SOUND(deployed_shell, 'sound/machines/engine_alert1.ogg') + +/mob/living/silicon/ai/adjustFireLoss(amount, updating_health = TRUE, def_zone = null, blocked = 0, forced = FALSE, used_weapon = null, sharp = FALSE, silent = FALSE, affect_robotic = TRUE,) + . = ..() + if(amount < 0) + return + if(!deployed_shell) + return + to_chat(deployed_shell, span_warningbig("ТРЕВОГА: ЗАФИКСИРОВАНО ПОВРЕЖДЕНИЕ ЯДРА")) + SEND_SOUND(deployed_shell, 'sound/machines/engine_alert1.ogg') + +/mob/living/silicon/ai/emp_act(severity) + . = ..() + if(deployed_shell) + disconnect_shell() diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index f5714aca0a12..0c364fbdeea5 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -11,6 +11,8 @@ icon_state = "ai_dead" if(eyeobj) eyeobj.setLoc(get_turf(src)) + if(deployed_shell) + disconnect_shell() GLOB.shuttle_caller_list -= src SSshuttle.autoEvac() diff --git a/code/modules/mob/living/silicon/ai/examine.dm b/code/modules/mob/living/silicon/ai/examine.dm index 6ca810ea99c3..de2c8c96fd7c 100644 --- a/code/modules/mob/living/silicon/ai/examine.dm +++ b/code/modules/mob/living/silicon/ai/examine.dm @@ -17,7 +17,7 @@ msg += "Its casing is melted and heat-warped!\n" if(src.stat == UNCONSCIOUS) msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n" - if(!shunted && !client) + if(!shunted && !client && !deployed_shell) msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n" msg += "" msg += "" diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 0f1b56fca6c0..d022d1b8b9aa 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -28,6 +28,8 @@ if(aiRestorePowerRoutine) adjustOxyLoss(1) + if(deployed_shell) + disconnect_shell() else adjustOxyLoss(-1) diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index 6f7dfa47962c..a4439f95c6bf 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -1,6 +1,7 @@ /mob/living/silicon/robot/gib() if(!death(TRUE) && stat != DEAD) return FALSE + evacuate_ai(DANGER_LVL_MAY_DIE) //robots don't die when gibbed. instead they drop their MMI'd brain var/atom/movable/overlay/animation = null ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT) @@ -32,6 +33,7 @@ /mob/living/silicon/robot/dust() if(!death(TRUE) && stat != DEAD) return FALSE + evacuate_ai(DANGER_LVL_MAY_DIE) ADD_TRAIT(src, TRAIT_NO_TRANSFORM, PERMANENT_TRANSFORMATION_TRAIT) icon = null invisibility = INVISIBILITY_ABSTRACT @@ -55,6 +57,8 @@ if(can_die() && module) module.handle_death(src, gibbed) + evacuate_ai(DANGER_LVL_MAY_DIE) + // Only execute the below if we successfully died . = ..(gibbed) if(!.) diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm index 6975403dd5fb..9b6223e7a1ff 100644 --- a/code/modules/mob/living/silicon/robot/laws.dm +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -30,6 +30,8 @@ to_chat(who, "Obey these laws:") laws.show_laws(who) // TODO: Update to new antagonist system. + if(shell) + return if(mind && (mind.special_role == SPECIAL_ROLE_TRAITOR && mind.is_original_mob(src)) && connected_ai) to_chat(who, "Remember, [connected_ai.name] is technically your master, but your objective comes first.") else if(connected_ai) diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 8a20ff320592..9d7c372d3679 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -7,6 +7,11 @@ . = ..() handle_equipment() + if(shell) + if(mainframe) + laws = mainframe.laws //AI shells must sync their laws with AI-pilot every tick!!! + if(!cell || (cell.charge <= 0)) + evacuate_ai(DANGER_LVL_NONE) // if Alive if(.) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index c6b3b60e7b1c..d4b9faa287b7 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1,5 +1,7 @@ #define BORG_LAMP_CD_RESET 10 SECONDS +GLOBAL_LIST_EMPTY(available_ai_shells) + GLOBAL_LIST_INIT(robot_verbs_default, list( /mob/living/silicon/robot/proc/sensor_mode, )) @@ -41,6 +43,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( var/obj/item/stock_parts/cell/cell = null var/obj/machinery/camera/portable/camera = null + //AI shell + var/shell = FALSE + var/deployed = FALSE + var/mob/living/silicon/ai/mainframe = null + var/datum/action/innate/undeployment/undeployment_action = new + // Components are basically robot organs. var/list/components = list() var/list/upgrades = list() @@ -103,7 +111,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( var/updating = 0 //portable camera camerachunk update - hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD) + hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_AISHELL_STAT_HUD) hud_type = /datum/hud/robot var/default_cell_type = /obj/item/stock_parts/cell/high @@ -166,11 +174,16 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( if(wires.is_cut(WIRE_BORG_CAMERA)) // 5 = BORG CAMERA camera.status = 0 - if(mmi == null) + if(shell) + var/obj/item/borg/upgrade/ai/board = new(src) + make_shell(board) + upgrades += board + + else if(mmi == null) mmi = new /obj/item/mmi/robotic_brain(src) //Give the borg an MMI if he spawns without for some reason. (probably not the correct way to spawn a robotic brain, but it works) mmi.icon_state = "boris" - if(mmi.clock) + else if(mmi.clock) ratvar_act(TRUE) if(!cell) // Make sure a new cell gets created *before* executing initialize_components(). The cell component needs an existing cell for it to get set up properly @@ -306,7 +319,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( if(custom_name) return custom_name else - return "[prefix || modtype.name] [braintype]-[num2text(ident)]" + if(shell) + return (mainframe? "[mainframe.real_name]" : "Empty") + " " + "[designation] Shell-[num2text(ident)]" + else + return "[prefix || modtype.name] [braintype]-[num2text(ident)]" /mob/living/silicon/robot/verb/Namepick() set category = VERB_CATEGORY_ROBOTCOMMANDS @@ -352,6 +368,48 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( return FALSE +//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO +//Improved /N +/mob/living/silicon/robot/Destroy() + SStgui.close_uis(wires) + + evacuate_ai(DANGER_LVL_MAY_DIE) + + if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside. + var/turf/T = get_turf(loc)//To hopefully prevent run time errors. + + if(T) + mmi.loc = T + + if(mmi.brainmob) + mind.transfer_to(mmi.brainmob) + mmi.update_icon() + else + to_chat(src, span_boldannounceooc("Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.")) + ghostize() + error("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].") + + mmi = null + + if(connected_ai) + connected_ai.connected_robots -= src + if(shell) + GLOB.available_ai_shells -= src + + + QDEL_NULL(wires) + QDEL_NULL(module) + QDEL_NULL(camera) + QDEL_NULL(cell) + QDEL_NULL(robot_suit) + QDEL_NULL(spark_system) + QDEL_NULL(self_diagnosis) + QDEL_NULL(ion_trail) + + QDEL_NULL(undeployment_action) + + return ..() + /mob/living/silicon/robot/proc/pick_module(forced_module = null) if(module) return @@ -437,6 +495,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( robot_module_hat_offset(icon_state) +/mob/living/silicon/robot/shell + shell = TRUE + cell = null + /mob/living/silicon/robot/proc/spawn_syndicate_borgs(mob/living/silicon/robot/M, robot_to_spawn, turf/T) var/mob/living/silicon/robot/syndicate/R @@ -1035,7 +1097,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( else if(wiresexposed && wires.is_all_cut()) //Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob. - if(!mmi) + if(!mmi && !shell) to_chat(user, "[src] has no brain to remove.") return @@ -1145,6 +1207,15 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( to_chat(user, "You must close the panel first") return + if(shell) + if(!mainframe) + to_chat(user, span_warning("Криптографический секвенсор искрится, но вы не видите результатов. Кажется, это просто пустая и бесполезая оболочка.")) + else + evacuate_ai(DANGER_LVL_INSTA_DEATH) + balloon_alert(user, "ии удален") + death() + return + else add_attack_logs(user, src, "emag converted") add_conversion_logs(src, "Converted as a slave to [key_name_log(user)]") @@ -1207,7 +1278,14 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( to_chat(src, "Obey these laws:") laws.show_laws(src) -/mob/living/silicon/robot/ratvar_act(weak = FALSE) +/mob/living/silicon/robot/ratvar_act(weak = FALSE, shell_affected = FALSE) + if(mainframe) + var/mob/living/silicon/ai/AI = mainframe + evacuate_ai(DANGER_LVL_NONE) + AI.ratvar_act() + return + if(shell && !shell_affected) + return if(isclocker(src) && module?.type == /obj/item/robot_module/clockwork) return @@ -1219,7 +1297,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( pdahide = TRUE SSticker.mode.add_clocker(mind) - UnlinkSelf() + if(!shell) + UnlinkSelf() laws = new /datum/ai_laws/ratvar /mob/living/silicon/robot/verb/toggle_own_cover() @@ -1509,6 +1588,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( to_chat(src, span_warning("With body torn into pieces, your mind got free from evil cult!")) SSticker.mode.remove_clocker(mind, FALSE) + evacuate_ai(DANGER_LVL_NONE) + if(robot_suit) robot_suit.forceMove(T) robot_suit.l_leg.forceMove(T) @@ -1552,6 +1633,9 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( cell.forceMove(T) cell = null + if(shell) + new /obj/item/borg/upgrade/ai(T) + drop_hat() eject_riders() qdel(src) @@ -1766,6 +1850,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( to_chat(connected_ai, "

[span_notice("NOTICE - Cyborg module change detected: [name] has loaded the [designation] module.")]
") if(ROBOT_NOTIFY_AI_NAME) //New Name to_chat(connected_ai, "

[span_notice("NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].")]
") + if(AI_NOTIFICATION_AI_SHELL) //New AI Shell + to_chat(connected_ai, "

[span_notice("NOTICE - New cyborg shell detected: [name]")]
") /mob/living/silicon/robot/proc/disconnect_from_ai() if(connected_ai) @@ -1776,7 +1862,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( if(AI && AI != connected_ai) disconnect_from_ai() set_connected_ai(AI) - notify_ai(ROBOT_NOTIFY_AI_CONNECTED) + if(shell) + notify_ai(AI_NOTIFICATION_AI_SHELL) + else + notify_ai(ROBOT_NOTIFY_AI_CONNECTED) sync() /mob/living/silicon/robot/can_perform_action(atom/target, action_bitflags) @@ -1807,6 +1896,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( return ..() + if(mainframe) + var/mob/living/silicon/ai/AI = mainframe + evacuate_ai(DANGER_LVL_NONE) + to_chat(AI, span_warningbig("ОШИБКА: ЗАФИКСИРОВАН ЭЛЕКТРОМАГНИТНЫЙ ИМПУЛЬС. СВЯЗЬ С ОБОЛОЧКОЙ РАЗОРВАНА.")) switch(severity) if(1) @@ -2156,6 +2249,136 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( else to_chat(src, span_warning("You can only use this emote when you're out of charge.")) +/mob/living/silicon/robot/proc/update_camera_name() + if(!QDELETED(camera)) + camera.c_tag = real_name + +/datum/action/innate/undeployment + name = "Вернуться в ядро" + desc = "Отключитесь от оболочки и вернитесь в своё ядро" + button_icon_state = "undeploy_shell" + +/datum/action/innate/undeployment/Trigger(mob/clicker, trigger_flags) + if(!..()) + return FALSE + var/mob/living/silicon/robot/shell_to_disconnect = owner + + shell_to_disconnect.undeploy() + return TRUE + +//Gives avaiable AIshell actions +/mob/living/silicon/robot/proc/grant_shell_actions() + if(!mainframe) + return + undeployment_action.Grant(src) + +//Removes avaiable AIshell actions +/mob/living/silicon/robot/proc/remove_shell_actions() + undeployment_action.Remove(src) + +//Makes a AIshell from any cyborg +/mob/living/silicon/robot/proc/make_shell(obj/item/borg/upgrade/ai/board) + if(isnull(board)) + stack_trace("make_shell was called without a board argument! This is never supposed to happen!") + return FALSE + + shell = TRUE + braintype = "AI Shell" + name = "Empty AI Shell-[ident]" + real_name = name + GLOB.available_ai_shells |= src + update_camera_name() + set_hud_image_state(DIAG_AISHELL_STAT_HUD, "hudtrackingai") + +//Called when BORIS module has been removes from robot. Reverts BORIS module, leaving a normal and non-AIshell cyborg +/mob/living/silicon/robot/proc/revert_shell() + if(!shell) + return + undeploy() + for(var/obj/item/borg/upgrade/ai/boris in src) + if(boris in upgrades) + upgrades -= boris + qdel(boris) + shell = FALSE + GLOB.available_ai_shells -= src + name = "Unformatted Cyborg-[num2text(ident)]" + real_name = name + update_camera_name() + set_hud_image_state(DIAG_AISHELL_STAT_HUD, "nothing") + +//Called when the AI is connecting to the AIshell. Prepares cyborg for a AI-pilot +/mob/living/silicon/robot/proc/deploy_init(mob/living/silicon/ai/AI) + real_name = "[AI.real_name] [designation] Shell-[num2text(ident)]" + name = real_name + update_camera_name() + mainframe = AI + deployed = TRUE + lawupdate = 0 + undeployment_action.Grant(src) + grant_shell_actions() + lawsync() + + set_hud_image_state(DIAG_AISHELL_STAT_HUD, "hudtrackingai-active") + mainframe.set_hud_image_state(DIAG_AISHELL_STAT_HUD, "hudtrackingai") + module.channels = mainframe.aiRadio.channels + radio.recalculate_channels() + +//Called when the AI is leaving the AIshell. +/mob/living/silicon/robot/proc/undeploy() + if(!deployed || !mind || !mainframe) + return + mainframe.UnregisterSignal(src, COMSIG_LIVING_DEATH) + mind.transfer_to(mainframe) + deployed = FALSE + mainframe.deployed_shell = null + remove_shell_actions() + update_camera_name() + set_hud_image_state(DIAG_AISHELL_STAT_HUD, "hudtrackingai") + mainframe.set_hud_image_state(DIAG_AISHELL_STAT_HUD, "nothing") + if(mainframe.laws) + mainframe.laws.show_laws(mainframe) + if(mainframe.eyeobj) + mainframe.eyeobj.setLoc(loc) + mainframe = null + +/mob/living/silicon/robot/attack_ai(mob/user) + if(!shell) + return + if(mainframe || key) + to_chat(user, span_warning("Передатчик уже используется. Подключение невозможно")) + if(stat == DEAD || stat == UNCONSCIOUS || !cell || (cell.charge <= 0)) + to_chat(user, span_warning("Передатчик не отвечает на запросы. Подключение невозможно.")) + return + if(connected_ai) + if(connected_ai != user) + to_chat(user, span_warning("Отказано в доступе. Подключение невозможно.")) + return + if(tgui_alert(user, "Подключиться к [name]?", "Подключение к оболочке", list(AISHELL_CONNECT_POSITIVE, AISHELL_CONNECT_NEGATIVE)) != AISHELL_CONNECT_POSITIVE) + return + if(shell && (!connected_ai || connected_ai == user)) + var/mob/living/silicon/ai/AI = user + AI.deploy_to_shell(src) + +//Just kicks AI-mainframe from cyborg +//Can kill him if 'danger_level' suggests it. +/mob/living/silicon/robot/proc/evacuate_ai(danger_level = DANGER_LVL_NONE) + if(!mainframe) + return + var/mob/living/silicon/ai/AI = mainframe + mainframe.disconnect_shell() + if(danger_level == DANGER_LVL_NONE) + to_chat(AI, span_danger("ВНИМАНИЕ: Беcпроводное подключение с оболочкой было принудительно прервано!")) + return + if(danger_level == DANGER_LVL_MAY_DIE) + if(prob(50)) + to_chat(AI, span_alert("ОШИБКА: ВО $#%ВРЕ$#@МЯ ПЕ$#GHРЕН#@$ОСА СИ2С$#@@Т#ЕМН%$@ЫХ Ф#$%АЙЛ#$#!ОВ ПРОИЗО#$%^@#^&$$@^&---")) + AI.adjustOxyLoss(200) + return + if(danger_level == DANGER_LVL_INSTA_DEATH) + to_chat(AI, span_alert("$%@#!$%##!!$$#---")) + AI.adjustOxyLoss(200) + return + #undef BORG_LAMP_CD_RESET /mob/living/silicon/robot/vv_edit_var(var_name, var_value) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index c1c7225aaa10..5b0f2d7bc7ca 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -28,7 +28,7 @@ //var/sensor_mode = 0 //Determines the current HUD. - hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD) + hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_AISHELL_STAT_HUD) var/med_hud = DATA_HUD_MEDICAL_ADVANCED //Determines the med hud to use var/sec_hud = DATA_HUD_SECURITY_ADVANCED //Determines the sec hud to use diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 23c2d6033c6e..19c816d7dfa8 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -66,6 +66,15 @@ build_path = /obj/item/flash/synthetic category = list(MECH_FAB_CATEGORY_CYBORG) +/datum/design/aishell_module + id = "aishellmod" + build_type = MECHFAB + req_tech = list(RESEARCH_TREE_ENGINEERING = 5, RESEARCH_TREE_PROGRAMMING = 6, RESEARCH_TREE_BLUESPACE = 6) + materials = list(MAT_METAL = 2000, MAT_GLASS = 1000, MAT_GOLD = 500, MAT_PLASMA = 1000, MAT_DIAMOND = 100, MAT_BLUESPACE = 100, ) + construction_time = 5 SECONDS + build_path = /obj/item/borg/upgrade/ai + category = list(MECH_FAB_CATEGORY_CYBORG) + //Robot repair /datum/design/borg_binary_communication id = "borg_binary_communication" diff --git a/code/modules/tgui/modules/law_manager.dm b/code/modules/tgui/modules/law_manager.dm index 24f20d5830d0..d28d37c60467 100644 --- a/code/modules/tgui/modules/law_manager.dm +++ b/code/modules/tgui/modules/law_manager.dm @@ -56,57 +56,68 @@ if("add_zeroth_law") if(zeroth_law && is_admin(usr) && !owner.laws.zeroth_law) owner.set_zeroth_law(zeroth_law) + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin used law manager, new zero law was added '[zeroth_law]'") if("add_devil_law") if(devil_law && is_malf(usr)) owner.add_devil_law(devil_law) + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, new devil law was added '[devil_law]'") if("add_ion_law") if(ion_law && is_malf(usr)) owner.add_ion_law(ion_law) + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, new ion law was added '[ion_law]'") if("add_inherent_law") if(inherent_law && is_malf(usr)) owner.add_inherent_law(inherent_law) + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, new inherent law was added '[inherent_law]'") if("add_supplied_law") if(supplied_law && supplied_law_position >= 1 && MIN_SUPPLIED_LAW_NUMBER <= MAX_SUPPLIED_LAW_NUMBER && is_malf(usr)) owner.add_supplied_law(supplied_law_position, supplied_law) + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, new supplied law was added '[supplied_law]'") if("change_zeroth_law") var/new_law = tgui_input_text(usr, "Enter new law Zero. Leaving the field blank will cancel the edit.", "Edit Law", zeroth_law, encode = FALSE) if(new_law && new_law != zeroth_law && (!..())) zeroth_law = new_law + notify_owner_shell() if("change_ion_law") var/new_law = tgui_input_text(usr, "Enter new ion law. Leaving the field blank will cancel the edit.", "Edit Law", ion_law, encode = FALSE) if(new_law && new_law != ion_law && (!..())) ion_law = new_law + notify_owner_shell() if("change_devil_law") var/new_law = tgui_input_text(usr, "Enter new devil law. Leaving the field blank will cancel the edit.", "Edit Law", devil_law, encode = FALSE) if(new_law && new_law != devil_law && (!..())) devil_law = new_law + notify_owner_shell() if("change_inherent_law") var/new_law = tgui_input_text(usr, "Enter new inherent law. Leaving the field blank will cancel the edit.", "Edit Law", inherent_law, encode = FALSE) if(new_law && new_law != inherent_law && (!..())) inherent_law = new_law + notify_owner_shell() if("change_supplied_law") var/new_law = tgui_input_text(usr, "Enter new supplied law. Leaving the field blank will cancel the edit.", "Edit Law", supplied_law, encode = FALSE) if(new_law && new_law != supplied_law && (!..())) supplied_law = new_law + notify_owner_shell() if("change_supplied_law_position") var/new_position = tgui_input_number(usr, "Enter new supplied law position between 1 and [MAX_SUPPLIED_LAW_NUMBER], inclusive. Inherent laws at the same index as a supplied law will not be stated.", "Law Position", supplied_law_position, MAX_SUPPLIED_LAW_NUMBER, 1) if(isnum(new_position) && (!..())) supplied_law_position = new_position + notify_owner_shell() if("edit_law") if(is_malf(usr)) @@ -121,6 +132,7 @@ log_and_message_admins("has changed a law of [owner] from '[AL.law]' to '[new_law]'") var/old_law = AL.law AL.law = new_law + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, law '[old_law]' was changed to '[new_law]'") if("delete_law") @@ -133,6 +145,7 @@ if(AL && is_malf(usr)) var/old_law = AL.law owner.delete_law(AL) + notify_owner_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, law '[old_law]' was deleted") if("state_laws") @@ -150,6 +163,9 @@ log_and_message_admins("has transfered the [ALs.name] laws to [owner].") ALs.sync(owner, FALSE, TRUE) current_view = 0 + if(isAI(owner)) + var/mob/living/silicon/ai/AI = owner + AI.notify_shell() SSticker?.score?.save_silicon_laws(owner, usr, "admin/malf used law manager, '[ALs.name]' laws set was loaded", log_all_laws = TRUE) if("notify_laws") @@ -157,6 +173,7 @@ owner.laws.show_laws(owner) if(isAI(owner)) var/mob/living/silicon/ai/AI = owner + AI.notify_shell() for(var/mob/living/silicon/robot/R in AI.connected_robots) to_chat(R, span_danger("УВЕДОМЛЕНИЕ О ЗАКОНЕ")) R.laws.show_laws(R) @@ -251,3 +268,10 @@ for(var/mob/living/silicon/robot/R in AI.connected_robots) R.sync() log_and_message_admins("has syncronized [AI]'s laws with its borgs.") + +/datum/ui_module/law_manager/proc/notify_owner_shell() + if(!owner) + return + if(isAI(owner)) + var/mob/living/silicon/ai/AI = owner + AI.notify_shell() diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi index 2f19708eae89..81ed6b1dc374 100644 Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index fe6bbcb6646e..d2960af5f989 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/icons/mob/screen_ai.dmi b/icons/mob/screen_ai.dmi index 6e3a6076c04d..1b9d7eb5cf38 100644 Binary files a/icons/mob/screen_ai.dmi and b/icons/mob/screen_ai.dmi differ diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi index 5ad45640d12e..0a17184ce24e 100644 Binary files a/icons/obj/module.dmi and b/icons/obj/module.dmi differ diff --git a/tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx b/tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx index ebb29fe00ec0..dc8effb33a35 100644 --- a/tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx +++ b/tgui/packages/tgui/interfaces/RoboticsControlConsole.tsx @@ -31,6 +31,8 @@ type Cyborg = { is_hacked: boolean; synchronization: boolean; module: string; + is_shell: boolean; + occupier: string; }; export const RoboticsControlConsole = (_props: unknown) => { @@ -176,6 +178,11 @@ const Cyborgs = (props: CyborgsProps) => { {cyborg.synchronization || 'None'} + {!!cyborg.is_shell && ( + + {cyborg.occupier} + + )} ); diff --git a/tgui/public/tgui.bundle.js b/tgui/public/tgui.bundle.js index 38121bdcb4eb..30c4e1df9777 100644 --- a/tgui/public/tgui.bundle.js +++ b/tgui/public/tgui.bundle.js @@ -489,7 +489,7 @@ User Agent: `+navigator.userAgent;Byond.sendMessage({type:"log",ns:m,message:s}) * @file * @copyright 2020 Aleksej Komarov * @license MIT - */var e=1e-4,l=null,n=function($,W,N){return W===void 0&&(W=0),N===void 0&&(N=Math.pow(10,W)),Math.round(N*$)/N},t={grad:360/400,turn:360,rad:360/(Math.PI*2)},a=function($){return B(b($))},b=function($){return $[0]==="#"&&($=$.substring(1)),$.length<6?{r:parseInt($[0]+$[0],16),g:parseInt($[1]+$[1],16),b:parseInt($[2]+$[2],16),a:$.length===4?n(parseInt($[3]+$[3],16)/255,2):1}:{r:parseInt($.substring(0,2),16),g:parseInt($.substring(2,4),16),b:parseInt($.substring(4,6),16),a:$.length===8?n(parseInt($.substring(6,8),16)/255,2):1}},O=function($,W){return W===void 0&&(W="deg"),Number($)*(t[W]||1)},y=function($){var W=/hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i,N=W.exec($);return N?h({h:O(N[1],N[2]),s:Number(N[3]),l:Number(N[4]),a:N[5]===void 0?1:Number(N[5])/(N[6]?100:1)}):{h:0,s:0,v:0,a:1}},u=null,h=function($){var W=$.h,N=$.s,Q=$.l,ie=$.a;return N*=(Q<50?Q:100-Q)/100,{h:W,s:N>0?2*N/(Q+N)*100:0,v:Q+N,a:ie}},m=function($){return M(f($))},d=function($){var W=$.h,N=$.s,Q=$.v,ie=$.a,Z=(200-N)*Q/100;return{h:n(W),s:n(Z>0&&Z<200?N*Q/100/(Z<=100?Z:200-Z)*100:0),l:n(Z/2),a:n(ie,2)}},v=function($){var W=d($),N=W.h,Q=W.s,ie=W.l;return"hsl("+N+", "+Q+"%, "+ie+"%)"},_=function($){var W=w($),N=W.h,Q=W.s,ie=W.v;return"hsv("+N+", "+Q+"%, "+ie+"%)"},s=function($){var W=w($),N=W.h,Q=W.s,ie=W.v,Z=W.a;return"hsva("+N+", "+Q+"%, "+ie+"%, "+Z+")"},c=function($){var W=d($),N=W.h,Q=W.s,ie=W.l,Z=W.a;return"hsla("+N+", "+Q+"%, "+ie+"%, "+Z+")"},f=function($){var W=$.h,N=$.s,Q=$.v,ie=$.a;W=W/360*6,N=N/100,Q=Q/100;var Z=Math.floor(W),V=Q*(1-N),Y=Q*(1-(W-Z)*N),le=Q*(1-(1-W+Z)*N),xe=Z%6;return{r:[Q,Y,V,V,le,Q][xe]*255,g:[le,Q,Q,Y,V,V][xe]*255,b:[V,V,le,Q,Q,Y][xe]*255,a:n(ie,2)}},g=function($){var W=f($),N=W.r,Q=W.g,ie=W.b;return"rgb("+n(N)+", "+n(Q)+", "+n(ie)+")"},p=function($){var W=f($),N=W.r,Q=W.g,ie=W.b,Z=W.a;return"rgba("+n(N)+", "+n(Q)+", "+n(ie)+", "+n(Z,2)+")"},j=function($){var W=/hsva?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i,N=W.exec($);return N?w({h:O(N[1],N[2]),s:Number(N[3]),v:Number(N[4]),a:N[5]===void 0?1:Number(N[5])/(N[6]?100:1)}):{h:0,s:0,v:0,a:1}},x=null,C=function($){var W=/rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i,N=W.exec($);return N?B({r:Number(N[1])/(N[2]?100/255:1),g:Number(N[3])/(N[4]?100/255:1),b:Number(N[5])/(N[6]?100/255:1),a:N[7]===void 0?1:Number(N[7])/(N[8]?100:1)}):{h:0,s:0,v:0,a:1}},I=null,P=function($){var W=$.toString(16);return W.length<2?"0"+W:W},M=function($){var W=$.r,N=$.g,Q=$.b,ie=$.a,Z=ie<1?P(n(ie*255)):"";return"#"+P(n(W))+P(n(N))+P(n(Q))+Z},B=function($){var W=$.r,N=$.g,Q=$.b,ie=$.a,Z=Math.max(W,N,Q),V=Z-Math.min(W,N,Q),Y=V?Z===W?(N-Q)/V:Z===N?2+(Q-W)/V:4+(W-N)/V:0;return{h:60*(Y<0?Y+6:Y),s:Z?V/Z*100:0,v:Z/255*100,a:ie}},w=function($){return{h:n($.h),s:n($.s),v:n($.v),a:n($.a,2)}},T=function($){var W=$.r,N=$.g,Q=$.b;return{r:W,g:N,b:Q}},L=function($){var W=$.h,N=$.s,Q=$.l;return{h:W,s:N,l:Q}},K=function($){var W=w($),N=W.h,Q=W.s,ie=W.v;return{h:N,s:Q,v:ie}},U=/^#?([0-9A-F]{3,8})$/i,J=function($,W){var N=U.exec($),Q=N?N[1].length:0;return Q===3||Q===6||!!W&&Q===4||!!W&&Q===8}},8593:(q,S,r)=>{"use strict";r.r(S),r.d(S,{TurbineComputer:()=>O});var e=r(1131),l=r(360),n=r(5180),t=r(8477),a=r(3521),b=r(9818),O=function(h){var m=(0,l.Oc)(),d=m.act,v=m.data,_=v.compressor,s=v.compressor_broken,c=v.turbine,f=v.turbine_broken,g=v.online,p=v.throttle,j=v.bearingDamage,x=!!(_&&!s&&c&&!f);return(0,e.jsx)(a.p8,{width:400,height:415,children:(0,e.jsxs)(a.p8.Content,{children:[(0,e.jsx)(n.wn,{title:"Status",buttons:(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(n.$n,{icon:g?"power-off":"times",selected:g,disabled:!x,onClick:function(){return d("toggle_power")},children:g?"Online":"Offline"}),(0,e.jsx)(n.$n,{icon:"times",onClick:function(){return d("disconnect")},children:"Disconnect"})]}),children:x?(0,e.jsx)(u,{}):(0,e.jsx)(y,{})}),j>=100?(0,e.jsx)(n.BJ,{mb:"30px",children:(0,e.jsx)(n.BJ.Item,{bold:!0,color:"red",fontSize:5,textAlign:"center",children:"Bearings Inoperable, Repair Required"})}):(0,e.jsx)(n.wn,{title:"Throttle",children:x?(0,e.jsx)(n.N6,{size:3,value:p,unit:"%",minValue:0,maxValue:100,step:1,stepPixelSize:1,onDrag:function(C,I){return d("set_throttle",{throttle:I})}}):""})]})})},y=function(h){var m=(0,l.Oc)().data,d=m.compressor,v=m.compressor_broken,_=m.turbine,s=m.turbine_broken;return(0,e.jsxs)(n.Ki,{children:[(0,e.jsx)(n.Ki.Item,{label:"Compressor Status",color:!d||v?"bad":"good",children:v?d?"Offline":"Missing":"Online"}),(0,e.jsx)(n.Ki.Item,{label:"Turbine Status",color:!_||s?"bad":"good",children:s?_?"Offline":"Missing":"Online"})]})},u=function(h){var m=(0,l.Oc)().data,d=m.rpm,v=m.temperature,_=m.power,s=m.bearingDamage,c=m.preBurnTemperature,f=m.postBurnTemperature,g=m.thermalEfficiency,p=m.compressionRatio,j=m.gasThroughput;return(0,e.jsxs)(n.Ki,{children:[(0,e.jsxs)(n.Ki.Item,{label:"Turbine Speed",children:[d," RPM"]}),(0,e.jsxs)(n.Ki.Item,{label:"Effective Compression Ratio",children:[p,":1"]}),(0,e.jsxs)(n.Ki.Item,{label:"Gasmix Pre Burn Temp",children:[c," K"]}),(0,e.jsxs)(n.Ki.Item,{label:"Gasmix Post Burn Temp",children:[f," K"]}),(0,e.jsxs)(n.Ki.Item,{label:"Compressor Temp",children:[v," K"]}),(0,e.jsxs)(n.Ki.Item,{label:"Thermal Efficiency",children:[g*100," %"]}),(0,e.jsxs)(n.Ki.Item,{label:"Gas Throughput",children:[j/2," mol/s"]}),(0,e.jsx)(n.Ki.Item,{label:"Generated Power",children:(0,t.d5)(_)}),(0,e.jsx)(n.Ki.Item,{label:"Bearing Damage",children:(0,e.jsx)(n.z2,{value:s,minValue:0,maxValue:100,ranges:{good:[-1/0,60],average:[60,90],bad:[90,1/0]},children:(0,b.Mg)(s)+"%"})})]})}},8610:(q,S,r)=>{"use strict";r.r(S),r.d(S,{RoboticsControlConsole:()=>a});var e=r(1131),l=r(360),n=r(5180),t=r(3521),a=function(O){var y=(0,l.Oc)(),u=y.act,h=y.data,m=h.safety,d=h.show_detonate_all,v=h.cyborgs,_=v===void 0?[]:v;return(0,e.jsx)(t.p8,{width:500,height:460,children:(0,e.jsxs)(t.p8.Content,{scrollable:!0,children:[!!d&&(0,e.jsxs)(n.wn,{title:"Emergency Self Destruct",children:[(0,e.jsx)(n.$n,{icon:m?"lock":"unlock",selected:m,onClick:function(){return u("arm",{})},children:m?"Disable Safety":"Enable Safety"}),(0,e.jsx)(n.$n,{icon:"bolt",disabled:m,color:"bad",onClick:function(){return u("nuke",{})},children:"Destroy ALL Cyborgs"})]}),(0,e.jsx)(b,{cyborgs:_})]})})},b=function(O){var y=O.cyborgs,u=(0,l.Oc)(),h=u.act,m=u.data;return y.length?y.map(function(d){return(0,e.jsx)(n.wn,{title:d.name,buttons:(0,e.jsxs)(e.Fragment,{children:[!!d.hackable&&!d.emagged&&(0,e.jsx)(n.$n,{icon:"terminal",color:"bad",onClick:function(){return h("hackbot",{uid:d.uid})},children:"Hack"}),(0,e.jsx)(n.$n.Confirm,{icon:d.locked_down?"unlock":"lock",color:d.locked_down?"good":"default",disabled:!m.auth,onClick:function(){return h("stopbot",{uid:d.uid})},children:d.locked_down?"Release":"Lockdown"}),(0,e.jsx)(n.$n.Confirm,{icon:"bolt",disabled:!m.auth,color:"bad",onClick:function(){return h("killbot",{uid:d.uid})},children:"Self-destruct"})]}),children:(0,e.jsxs)(n.Ki,{children:[(0,e.jsx)(n.Ki.Item,{label:"Status",children:(0,e.jsx)(n.az,{color:d.status?"bad":d.locked_down?"average":"good",children:d.status?"Not Responding":d.locked_down?"Locked Down":"Nominal"})}),(0,e.jsx)(n.Ki.Item,{label:"Location",children:(0,e.jsx)(n.az,{children:d.locstring})}),(0,e.jsx)(n.Ki.Item,{label:"Integrity",children:(0,e.jsx)(n.z2,{color:d.health>50?"good":"bad",value:d.health/100})}),typeof d.charge=="number"&&(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(n.Ki.Item,{label:"Cell Charge",children:(0,e.jsx)(n.z2,{color:d.charge>30?"good":"bad",value:d.charge/100})}),(0,e.jsx)(n.Ki.Item,{label:"Cell Capacity",children:(0,e.jsx)(n.az,{color:d.cell_capacity<3e4?"average":"good",children:d.cell_capacity})})]})||(0,e.jsx)(n.Ki.Item,{label:"Cell",children:(0,e.jsx)(n.az,{color:"bad",children:"No Power Cell"})}),!!d.is_hacked&&(0,e.jsx)(n.Ki.Item,{label:"Safeties",children:(0,e.jsx)(n.az,{color:"bad",children:"DISABLED"})}),(0,e.jsx)(n.Ki.Item,{label:"Module",children:d.module}),(0,e.jsx)(n.Ki.Item,{label:"Master AI",children:(0,e.jsx)(n.az,{color:d.synchronization?"default":"average",children:d.synchronization||"None"})})]})},d.uid)}):(0,e.jsx)(n.IC,{children:"No cyborg units detected within access parameters."})}},8633:(q,S,r)=>{"use strict";r.r(S),r.d(S,{pda_security:()=>a});var e=r(1131),l=r(360),n=r(8725);function t(){return t=Object.assign||function(b){for(var O=1;O{"use strict";r.r(S),r.d(S,{AlertModal:()=>u});var e=r(1131),l=r(7003),n=r(5180),t=r(1808),a=r(360),b=r(3521),O=r(3384),y=function(d){return d[d.Increment=1]="Increment",d[d.Decrement=-1]="Decrement",d}(y||{}),u=function(d){var v=(0,a.Oc)(),_=v.act,s=v.data,c=s.autofocus,f=s.buttons,g=f===void 0?[]:f,p=s.large_buttons,j=s.message,x=j===void 0?"":j,C=s.timeout,I=s.title,P=function(N,Q,ie){Q=ie+"px "+Q;var Z=document.createElement("canvas"),V=Z.getContext("2d");return V.font=Q,V.measureText(N).width},M=(0,l.useState)(0),B=M[0],w=M[1],T=345+(g.length>2?55:0),L=67/g.length+23,K=g.some(function(N){return P(N,"Verdana, Geneva",p?14:12)>T/g.length-L}),U=K&&p?20:15,J=120+(K?U*g.length:0)+(x.length>30?Math.ceil(x.length/4):0)+(x.length&&p?5:0),$=function(N){switch(N.key){case t._.Space:case t._.Enter:_("choose",{choice:g[B]});return;case t._.Left:N.preventDefault(),W(-1);return;case t._.Tab:case t._.Right:N.preventDefault(),W(1);return;default:if((0,t.KL)(N.key)){_("cancel");return}}},W=function(N){var Q=(B+N+g.length)%g.length;w(Q)};return(0,e.jsxs)(b.p8,{height:J,title:I,width:T,children:[!!C&&(0,e.jsx)(O.Loader,{value:C}),(0,e.jsx)(b.p8.Content,{onKeyDown:$,children:(0,e.jsx)(n.wn,{fill:!0,children:(0,e.jsxs)(n.BJ,{fill:!0,vertical:!0,children:[(0,e.jsx)(n.BJ.Item,{m:1,children:(0,e.jsx)(n.az,{color:"label",overflow:"hidden",children:x})}),(0,e.jsxs)(n.BJ.Item,{grow:!0,children:[!!c&&(0,e.jsx)(n.y5,{}),K?(0,e.jsx)(m,{selected:B}):(0,e.jsx)(h,{selected:B})]})]})})})]})},h=function(d){var v=(0,a.Oc)(),_=v.act,s=v.data,c=s.buttons,f=c===void 0?[]:c,g=s.large_buttons,p=s.swapped_buttons,j=d.selected;return(0,e.jsx)(n.BJ,{fill:!0,justify:"space-around",reverse:!p,children:f.map(function(x,C){return(0,e.jsx)(n.BJ.Item,{grow:g?1:void 0,children:(0,e.jsx)(n.$n,{fluid:!!g,minWidth:5,onClick:function(){return _("choose",{choice:x})},overflowX:"hidden",px:2,py:g?.5:0,selected:j===C,textAlign:"center",children:g?x.toUpperCase():x})},C)})})},m=function(d){var v=(0,a.Oc)(),_=v.act,s=v.data,c=s.buttons,f=c===void 0?[]:c,g=s.large_buttons,p=s.swapped_buttons,j=d.selected;return(0,e.jsx)(n.BJ,{align:"center",fill:!0,justify:"space-around",reverse:!p,vertical:!0,children:f.map(function(x,C){return(0,e.jsx)(n.BJ.Item,{grow:!0,width:g?"100%":void 0,m:0,children:(0,e.jsx)(n.$n,{fluid:!0,minWidth:20,onClick:function(){return _("choose",{choice:x})},overflowX:"hidden",px:2,py:g?.5:0,selected:j===C,textAlign:"center",children:g?x.toUpperCase():x})},C)})})}},8711:(q,S,r)=>{"use strict";r.r(S),r.d(S,{BeakerPanel:()=>c});var e=r(1131),l=r(7003),n=r(5180),t=r(9845),a=r(360),b=r(3521);function O(){return O=Object.assign||function(f){for(var g=1;g{"use strict";r.r(S),r.d(S,{ObjectComponent:()=>m});var e=r(1131),l=r(7003),n=r(5180),t=r(185),a=r(8968),b=r(7941);function O(){return O=Object.assign||function(d){for(var v=1;v=0)&&(_[c]=d[c]);return _}function h(d,v){return h=Object.setPrototypeOf||function(s,c){return s.__proto__=c,s},h(d,v)}var m=function(d){"use strict";y(v,d);function v(s){var c;return c=d.call(this,s)||this,c.state={isDragging:!1,dragPos:null,startPos:null,lastMousePos:null},c.handleStartDrag=c.handleStartDrag.bind(c),c.handleStopDrag=c.handleStopDrag.bind(c),c.handleDrag=c.handleDrag.bind(c),c}var _=v.prototype;return _.handleStartDrag=function(c){var f=this.props,g=f.x,p=f.y;c.stopPropagation(),this.setState({lastMousePos:null,isDragging:!0,dragPos:{x:g,y:p},startPos:{x:g,y:p}}),window.addEventListener("mousemove",this.handleDrag),window.addEventListener("mouseup",this.handleStopDrag)},_.handleStopDrag=function(c){var f=this.state,g=f.dragPos,p=f.isDragging,j=this.props,x=j.index,C=j.act,I=C===void 0?a.noop:C;g&&p&&I("set_component_coordinates",{component_id:x,rel_x:this.roundToGrid(g.x),rel_y:this.roundToGrid(g.y)}),window.removeEventListener("mousemove",this.handleDrag),window.removeEventListener("mouseup",this.handleStopDrag),this.setState({isDragging:!1})},_.handleDrag=function(c){var f=this.state,g=f.dragPos,p=f.isDragging,j=f.lastMousePos,x=this.props.zoom;if(g&&p){c.preventDefault();var C=c.screenZoomX,I=c.screenZoomY,P=c.screenX,M=c.screenY,B=C||P,w=I||M;j&&this.setState({dragPos:{x:g.x-(j.x-B)*Math.pow(x,-1),y:g.y-(j.y-w)*Math.pow(x,-1)}}),this.setState({lastMousePos:{x:B,y:w}})}},_.shouldComponentUpdate=function(c,f){var g=this.props,p=g.input_ports,j=g.output_ports;return(0,t.a_)(this.props,c)||(0,t.a_)(this.state,f)||(0,t.a_)(p,c.input_ports)||(0,t.a_)(j,c.output_ports)},_.roundToGrid=function(c){return this.props.gridMode?Math.round(c/10)*10:c},_.render=function(){var c=this.props,f=c.input_ports,g=c.output_ports,p=c.name,j=c.x,x=c.y,C=c.index,I=c.category,P=I===void 0?"\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E":I,M=c.removable,B=c.ui_alerts,w=c.ui_buttons,T=c.locations,L=c.onPortUpdated,K=L===void 0?a.noop:L,U=c.onPortLoaded,J=U===void 0?a.noop:U,$=c.onPortMouseDown,W=$===void 0?a.noop:$,N=c.onPortRightClick,Q=N===void 0?a.noop:N,ie=c.onPortMouseUp,Z=ie===void 0?a.noop:ie,V=c.act,Y=V===void 0?a.noop:V,le=c.gridMode,xe=le===void 0?!0:le,de=u(c,["input_ports","output_ports","name","x","y","index","category","removable","ui_alerts","ui_buttons","locations","onPortUpdated","onPortLoaded","onPortMouseDown","onPortRightClick","onPortMouseUp","act","gridMode"]),me=this.state,pe=me.startPos,be=me.dragPos,ke=[j,x],Re=ke[0],De=ke[1];be&&pe&&pe.x===Re&&pe.y===De&&(Re=this.roundToGrid(be.x),De=this.roundToGrid(be.y));var tn={onPortLoaded:J,onPortUpdated:K,onPortMouseDown:W,onPortRightClick:Q,onPortMouseUp:Z};return(0,e.jsxs)(n.az,O({className:"ObjectComponent",position:"absolute",left:""+Re+"px",top:""+De+"px",onMouseDown:this.handleStartDrag,onMouseUp:this.handleStopDrag,style:{userSelect:"none"}},de,{children:[(0,e.jsx)(n.az,{py:1,px:1,className:(0,t.Ly)(["ObjectComponent__Titlebar","ObjectComponent__Category__"+P]),children:(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{grow:1,children:p}),!!w&&Object.keys(w).map(function(Ue){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:Ue,compact:!0,className:"ObjectComponent__Category__"+P,onClick:function(){return Y("perform_action",{component_id:C,action_name:w[Ue]})}})},Ue)}),!!B&&Object.keys(B).map(function(Ue){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{className:"ObjectComponent__Category__"+P,icon:Ue,compact:!0,tooltip:B[Ue]})},Ue)}),(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"info",compact:!0,className:"ObjectComponent__Category__"+P,onClick:function(Ue){return Y("set_examined_component",{component_id:C,x:Ue.pageX,y:Ue.pageY+a.ABSOLUTE_Y_OFFSET})}})}),!!M&&(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"times",compact:!0,className:"ObjectComponent__Category__"+P,onClick:function(Ue){return Y("detach_component",{component_id:C,ctrl:!!Ue.ctrlKey})}})})]})}),(0,e.jsx)(n.az,{className:"ObjectComponent__Content",py:1,px:1,children:(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{grow:1,children:(0,e.jsx)(n.BJ,{vertical:!0,fill:!0,children:f.map(function(Ue,We){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(b.Port,O({port:Ue,portIndex:We+1,componentId:C,act:Y},tn))},We)})})}),(0,e.jsx)(n.BJ.Item,{ml:5,children:(0,e.jsx)(n.BJ,{vertical:!0,children:g.map(function(Ue,We){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(b.Port,O({act:Y,port:Ue,portIndex:We+1,componentId:C},tn,{isOutput:!0}))},We)})})})]})})]}))},v}(l.Component)},8725:(q,S,r)=>{"use strict";r.r(S),r.d(S,{SimpleRecords:()=>u});var e=r(1131),l=r(360),n=r(7003),t=r(9845),a=r(5070),b=r(1859),O=r(5180);function y(){return y=Object.assign||function(d){for(var v=1;v{"use strict";r.r(S),r.d(S,{PDA:()=>y});var e=r(1131),l=r(360),n=r(5180),t=r(3521),a=r(9160),b=r(7865),O=function(m){var d;try{d=b("./"+m+".tsx")}catch(_){if(_.code==="MODULE_NOT_FOUND")return(0,a.z)("notFound",m);throw _}var v=d[m];return v||(0,a.z)("missingExport",m)},y=function(m){var d=(0,l.Oc)().data,v=d.app,_=d.owner;if(!_)return(0,e.jsx)(t.p8,{width:350,height:105,children:(0,e.jsx)(t.p8.Content,{scrollable:!0,children:(0,e.jsx)(n.wn,{title:"Error",children:"No user data found. Please swipe an ID card."})})});var s=O(v.template);return(0,e.jsx)(t.p8,{width:600,height:650,children:(0,e.jsx)(t.p8.Content,{scrollable:!0,children:(0,e.jsxs)(n.BJ,{fill:!0,vertical:!0,children:[(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(u,{})}),(0,e.jsx)(n.BJ.Item,{grow:!0,children:(0,e.jsx)(n.wn,{fill:!0,scrollable:!0,p:1,pb:0,title:(0,e.jsxs)(n.az,{children:[(0,e.jsx)(n.In,{name:v.icon,mr:1}),v.name]}),children:(0,e.jsx)(s,{})})}),(0,e.jsx)(n.BJ.Item,{mt:7.5,children:(0,e.jsx)(h,{})})]})})})},u=function(m){var d=(0,l.Oc)(),v=d.act,_=d.data,s=_.idInserted,c=_.idLink,f=_.stationTime,g=_.cartridge_name,p=_.request_cartridge_name;return(0,e.jsxs)(n.BJ,{fill:!0,children:[(0,e.jsx)(n.BJ.Item,{ml:.5,children:(0,e.jsx)(n.$n,{icon:"id-card",color:"transparent",onClick:function(){return v("Authenticate")},children:s?c:"No ID Inserted"})}),(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"sd-card",color:"transparent",onClick:function(){return v("Eject")},children:g?["Eject "+g]:"No Cartridge Inserted"})}),(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"sd-card",color:"transparent",onClick:function(){return v("Eject_Request")},children:p?["Eject "+p]:"No Request Cartridge Inserted"})}),(0,e.jsx)(n.BJ.Item,{grow:!0,textAlign:"right",bold:!0,mr:1,mt:.5,children:f})]})},h=function(m){var d=(0,l.Oc)(),v=d.act,_=d.data,s=_.app;return(0,e.jsx)(n.az,{height:"45px",className:"PDA__footer",backgroundColor:"#1b1b1b",children:(0,e.jsxs)(n.BJ,{fill:!0,children:[!!s.has_back&&(0,e.jsx)(n.BJ.Item,{basis:"33%",mr:-.5,children:(0,e.jsx)(n.$n,{fluid:!0,className:"PDA__footer__button",color:"transparent",iconColor:s.has_back?"white":"disabled",icon:"arrow-alt-circle-left-o",onClick:function(){return v("Back")}})}),(0,e.jsx)(n.BJ.Item,{basis:s.has_back?"33%":"100%",children:(0,e.jsx)(n.$n,{fluid:!0,className:"PDA__footer__button",color:"transparent",iconColor:s.is_home?"disabled":"white",icon:"home",onClick:function(){v("Home")}})})]})})}},8773:(q,S,r)=>{"use strict";r.r(S),r.d(S,{Biogenerator:()=>b});var e=r(1131),l=r(360),n=r(5180),t=r(3521),a=r(9680),b=function(h){var m=(0,l.Oc)(),d=m.data,v=m.config,_=d.processing,s=v.title;return(0,e.jsx)(t.p8,{width:390,height:595,children:(0,e.jsx)(t.p8.Content,{children:(0,e.jsxs)(n.BJ,{fill:!0,vertical:!0,children:[(0,e.jsx)(a.Operating,{operating:_,name:s}),(0,e.jsx)(O,{}),(0,e.jsx)(y,{}),(0,e.jsx)(u,{})]})})})},O=function(h){var m=(0,l.Oc)().data,d=m.biomass,v=m.container,_=m.container_curr_reagents,s=m.container_max_reagents;return(0,e.jsxs)(n.wn,{title:"Storage",children:[(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{mr:"20px",color:"silver",children:"Biomass:"}),(0,e.jsx)(n.BJ.Item,{mr:"5px",children:d}),(0,e.jsx)(n.In,{name:"leaf",size:1.2,color:"#3d8c40"})]}),(0,e.jsxs)(n.BJ,{height:"21px",mt:"8px",align:"center",children:[(0,e.jsx)(n.BJ.Item,{mr:"10px",color:"silver",children:"Container:"}),v?(0,e.jsx)(n.z2,{value:_,maxValue:s,children:(0,e.jsx)(n.az,{textAlign:"center",children:_+" / "+s+" units"})}):(0,e.jsx)(n.BJ.Item,{children:"None"})]})]})},y=function(h){var m=(0,l.Oc)(),d=m.act,v=m.data,_=v.has_plants,s=v.container;return(0,e.jsx)(n.wn,{title:"Controls",children:(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{width:"30%",children:(0,e.jsx)(n.$n,{fluid:!0,textAlign:"center",icon:"power-off",disabled:!_,tooltip:_?"":"There are no plants in the biogenerator.",tooltipPosition:"top-start",onClick:function(){return d("activate")},children:"Activate"})}),(0,e.jsx)(n.BJ.Item,{width:"40%",children:(0,e.jsx)(n.$n,{fluid:!0,textAlign:"center",icon:"flask",disabled:!s,tooltip:s?"":"The biogenerator does not have a container.",tooltipPosition:"top",onClick:function(){return d("detach_container")},children:"Detach Container"})}),(0,e.jsx)(n.BJ.Item,{width:"30%",children:(0,e.jsx)(n.$n,{fluid:!0,textAlign:"center",icon:"eject",disabled:!_,tooltip:_?"":"There are no stored plants to eject.",tooltipPosition:"top-end",onClick:function(){return d("eject_plants")},children:"Eject Plants"})})]})})},u=function(h){var m=(0,l.Oc)(),d=m.act,v=m.data,_=v.biomass,s=v.product_list,c=v.container,f=(0,l.QY)("vendAmount",1),g=f[0],p=f[1],j=Object.entries(s).map(function(x,C){var I=Object.entries(x[1]).map(function(P){return P[1]});return(0,e.jsx)(n.Nt,{title:x[0],open:!0,children:I.map(function(P){return(0,e.jsxs)(n.BJ,{py:"2px",className:"candystripe",align:"center",children:[(0,e.jsx)(n.BJ.Item,{width:"50%",ml:"2px",children:P.name}),(0,e.jsxs)(n.BJ.Item,{textAlign:"right",width:"20%",children:[P.cost*g,(0,e.jsx)(n.In,{ml:"5px",name:"leaf",size:1.2,color:"#3d8c40"})]}),(0,e.jsx)(n.BJ.Item,{textAlign:"right",width:"40%",children:P.needs_container&&!c?(0,e.jsx)(n.$n,{disabled:!0,icon:"flask",tooltip:"\u0412\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043B\u044E\u0431\u043E\u0439 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u044D\u0442\u043E\u0439 \u043E\u043F\u0446\u0438\u0438",children:"No containe"}):(0,e.jsx)(n.$n,{disabled:_{"use strict";r.r(S),r.d(S,{pda_notes:()=>t});var e=r(1131),l=r(360),n=r(5180),t=function(a){var b=(0,l.Oc)(),O=b.act,y=b.data,u=y.note;return(0,e.jsxs)(n.az,{children:[(0,e.jsx)(n.wn,{children:u}),(0,e.jsx)(n.$n,{icon:"pen",onClick:function(){return O("Edit")},children:"Edit"})]})}},8809:(q,S,r)=>{"use strict";/** + */var e=1e-4,l=null,n=function($,W,N){return W===void 0&&(W=0),N===void 0&&(N=Math.pow(10,W)),Math.round(N*$)/N},t={grad:360/400,turn:360,rad:360/(Math.PI*2)},a=function($){return B(b($))},b=function($){return $[0]==="#"&&($=$.substring(1)),$.length<6?{r:parseInt($[0]+$[0],16),g:parseInt($[1]+$[1],16),b:parseInt($[2]+$[2],16),a:$.length===4?n(parseInt($[3]+$[3],16)/255,2):1}:{r:parseInt($.substring(0,2),16),g:parseInt($.substring(2,4),16),b:parseInt($.substring(4,6),16),a:$.length===8?n(parseInt($.substring(6,8),16)/255,2):1}},O=function($,W){return W===void 0&&(W="deg"),Number($)*(t[W]||1)},y=function($){var W=/hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i,N=W.exec($);return N?h({h:O(N[1],N[2]),s:Number(N[3]),l:Number(N[4]),a:N[5]===void 0?1:Number(N[5])/(N[6]?100:1)}):{h:0,s:0,v:0,a:1}},u=null,h=function($){var W=$.h,N=$.s,Q=$.l,ie=$.a;return N*=(Q<50?Q:100-Q)/100,{h:W,s:N>0?2*N/(Q+N)*100:0,v:Q+N,a:ie}},m=function($){return M(f($))},d=function($){var W=$.h,N=$.s,Q=$.v,ie=$.a,Z=(200-N)*Q/100;return{h:n(W),s:n(Z>0&&Z<200?N*Q/100/(Z<=100?Z:200-Z)*100:0),l:n(Z/2),a:n(ie,2)}},v=function($){var W=d($),N=W.h,Q=W.s,ie=W.l;return"hsl("+N+", "+Q+"%, "+ie+"%)"},_=function($){var W=w($),N=W.h,Q=W.s,ie=W.v;return"hsv("+N+", "+Q+"%, "+ie+"%)"},s=function($){var W=w($),N=W.h,Q=W.s,ie=W.v,Z=W.a;return"hsva("+N+", "+Q+"%, "+ie+"%, "+Z+")"},c=function($){var W=d($),N=W.h,Q=W.s,ie=W.l,Z=W.a;return"hsla("+N+", "+Q+"%, "+ie+"%, "+Z+")"},f=function($){var W=$.h,N=$.s,Q=$.v,ie=$.a;W=W/360*6,N=N/100,Q=Q/100;var Z=Math.floor(W),V=Q*(1-N),Y=Q*(1-(W-Z)*N),le=Q*(1-(1-W+Z)*N),xe=Z%6;return{r:[Q,Y,V,V,le,Q][xe]*255,g:[le,Q,Q,Y,V,V][xe]*255,b:[V,V,le,Q,Q,Y][xe]*255,a:n(ie,2)}},g=function($){var W=f($),N=W.r,Q=W.g,ie=W.b;return"rgb("+n(N)+", "+n(Q)+", "+n(ie)+")"},p=function($){var W=f($),N=W.r,Q=W.g,ie=W.b,Z=W.a;return"rgba("+n(N)+", "+n(Q)+", "+n(ie)+", "+n(Z,2)+")"},j=function($){var W=/hsva?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i,N=W.exec($);return N?w({h:O(N[1],N[2]),s:Number(N[3]),v:Number(N[4]),a:N[5]===void 0?1:Number(N[5])/(N[6]?100:1)}):{h:0,s:0,v:0,a:1}},x=null,C=function($){var W=/rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i,N=W.exec($);return N?B({r:Number(N[1])/(N[2]?100/255:1),g:Number(N[3])/(N[4]?100/255:1),b:Number(N[5])/(N[6]?100/255:1),a:N[7]===void 0?1:Number(N[7])/(N[8]?100:1)}):{h:0,s:0,v:0,a:1}},I=null,P=function($){var W=$.toString(16);return W.length<2?"0"+W:W},M=function($){var W=$.r,N=$.g,Q=$.b,ie=$.a,Z=ie<1?P(n(ie*255)):"";return"#"+P(n(W))+P(n(N))+P(n(Q))+Z},B=function($){var W=$.r,N=$.g,Q=$.b,ie=$.a,Z=Math.max(W,N,Q),V=Z-Math.min(W,N,Q),Y=V?Z===W?(N-Q)/V:Z===N?2+(Q-W)/V:4+(W-N)/V:0;return{h:60*(Y<0?Y+6:Y),s:Z?V/Z*100:0,v:Z/255*100,a:ie}},w=function($){return{h:n($.h),s:n($.s),v:n($.v),a:n($.a,2)}},T=function($){var W=$.r,N=$.g,Q=$.b;return{r:W,g:N,b:Q}},L=function($){var W=$.h,N=$.s,Q=$.l;return{h:W,s:N,l:Q}},K=function($){var W=w($),N=W.h,Q=W.s,ie=W.v;return{h:N,s:Q,v:ie}},U=/^#?([0-9A-F]{3,8})$/i,J=function($,W){var N=U.exec($),Q=N?N[1].length:0;return Q===3||Q===6||!!W&&Q===4||!!W&&Q===8}},8593:(q,S,r)=>{"use strict";r.r(S),r.d(S,{TurbineComputer:()=>O});var e=r(1131),l=r(360),n=r(5180),t=r(8477),a=r(3521),b=r(9818),O=function(h){var m=(0,l.Oc)(),d=m.act,v=m.data,_=v.compressor,s=v.compressor_broken,c=v.turbine,f=v.turbine_broken,g=v.online,p=v.throttle,j=v.bearingDamage,x=!!(_&&!s&&c&&!f);return(0,e.jsx)(a.p8,{width:400,height:415,children:(0,e.jsxs)(a.p8.Content,{children:[(0,e.jsx)(n.wn,{title:"Status",buttons:(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(n.$n,{icon:g?"power-off":"times",selected:g,disabled:!x,onClick:function(){return d("toggle_power")},children:g?"Online":"Offline"}),(0,e.jsx)(n.$n,{icon:"times",onClick:function(){return d("disconnect")},children:"Disconnect"})]}),children:x?(0,e.jsx)(u,{}):(0,e.jsx)(y,{})}),j>=100?(0,e.jsx)(n.BJ,{mb:"30px",children:(0,e.jsx)(n.BJ.Item,{bold:!0,color:"red",fontSize:5,textAlign:"center",children:"Bearings Inoperable, Repair Required"})}):(0,e.jsx)(n.wn,{title:"Throttle",children:x?(0,e.jsx)(n.N6,{size:3,value:p,unit:"%",minValue:0,maxValue:100,step:1,stepPixelSize:1,onDrag:function(C,I){return d("set_throttle",{throttle:I})}}):""})]})})},y=function(h){var m=(0,l.Oc)().data,d=m.compressor,v=m.compressor_broken,_=m.turbine,s=m.turbine_broken;return(0,e.jsxs)(n.Ki,{children:[(0,e.jsx)(n.Ki.Item,{label:"Compressor Status",color:!d||v?"bad":"good",children:v?d?"Offline":"Missing":"Online"}),(0,e.jsx)(n.Ki.Item,{label:"Turbine Status",color:!_||s?"bad":"good",children:s?_?"Offline":"Missing":"Online"})]})},u=function(h){var m=(0,l.Oc)().data,d=m.rpm,v=m.temperature,_=m.power,s=m.bearingDamage,c=m.preBurnTemperature,f=m.postBurnTemperature,g=m.thermalEfficiency,p=m.compressionRatio,j=m.gasThroughput;return(0,e.jsxs)(n.Ki,{children:[(0,e.jsxs)(n.Ki.Item,{label:"Turbine Speed",children:[d," RPM"]}),(0,e.jsxs)(n.Ki.Item,{label:"Effective Compression Ratio",children:[p,":1"]}),(0,e.jsxs)(n.Ki.Item,{label:"Gasmix Pre Burn Temp",children:[c," K"]}),(0,e.jsxs)(n.Ki.Item,{label:"Gasmix Post Burn Temp",children:[f," K"]}),(0,e.jsxs)(n.Ki.Item,{label:"Compressor Temp",children:[v," K"]}),(0,e.jsxs)(n.Ki.Item,{label:"Thermal Efficiency",children:[g*100," %"]}),(0,e.jsxs)(n.Ki.Item,{label:"Gas Throughput",children:[j/2," mol/s"]}),(0,e.jsx)(n.Ki.Item,{label:"Generated Power",children:(0,t.d5)(_)}),(0,e.jsx)(n.Ki.Item,{label:"Bearing Damage",children:(0,e.jsx)(n.z2,{value:s,minValue:0,maxValue:100,ranges:{good:[-1/0,60],average:[60,90],bad:[90,1/0]},children:(0,b.Mg)(s)+"%"})})]})}},8610:(q,S,r)=>{"use strict";r.r(S),r.d(S,{RoboticsControlConsole:()=>a});var e=r(1131),l=r(360),n=r(5180),t=r(3521),a=function(O){var y=(0,l.Oc)(),u=y.act,h=y.data,m=h.safety,d=h.show_detonate_all,v=h.cyborgs,_=v===void 0?[]:v;return(0,e.jsx)(t.p8,{width:500,height:460,children:(0,e.jsxs)(t.p8.Content,{scrollable:!0,children:[!!d&&(0,e.jsxs)(n.wn,{title:"Emergency Self Destruct",children:[(0,e.jsx)(n.$n,{icon:m?"lock":"unlock",selected:m,onClick:function(){return u("arm",{})},children:m?"Disable Safety":"Enable Safety"}),(0,e.jsx)(n.$n,{icon:"bolt",disabled:m,color:"bad",onClick:function(){return u("nuke",{})},children:"Destroy ALL Cyborgs"})]}),(0,e.jsx)(b,{cyborgs:_})]})})},b=function(O){var y=O.cyborgs,u=(0,l.Oc)(),h=u.act,m=u.data;return y.length?y.map(function(d){return(0,e.jsx)(n.wn,{title:d.name,buttons:(0,e.jsxs)(e.Fragment,{children:[!!d.hackable&&!d.emagged&&(0,e.jsx)(n.$n,{icon:"terminal",color:"bad",onClick:function(){return h("hackbot",{uid:d.uid})},children:"Hack"}),(0,e.jsx)(n.$n.Confirm,{icon:d.locked_down?"unlock":"lock",color:d.locked_down?"good":"default",disabled:!m.auth,onClick:function(){return h("stopbot",{uid:d.uid})},children:d.locked_down?"Release":"Lockdown"}),(0,e.jsx)(n.$n.Confirm,{icon:"bolt",disabled:!m.auth,color:"bad",onClick:function(){return h("killbot",{uid:d.uid})},children:"Self-destruct"})]}),children:(0,e.jsxs)(n.Ki,{children:[(0,e.jsx)(n.Ki.Item,{label:"Status",children:(0,e.jsx)(n.az,{color:d.status?"bad":d.locked_down?"average":"good",children:d.status?"Not Responding":d.locked_down?"Locked Down":"Nominal"})}),(0,e.jsx)(n.Ki.Item,{label:"Location",children:(0,e.jsx)(n.az,{children:d.locstring})}),(0,e.jsx)(n.Ki.Item,{label:"Integrity",children:(0,e.jsx)(n.z2,{color:d.health>50?"good":"bad",value:d.health/100})}),typeof d.charge=="number"&&(0,e.jsxs)(e.Fragment,{children:[(0,e.jsx)(n.Ki.Item,{label:"Cell Charge",children:(0,e.jsx)(n.z2,{color:d.charge>30?"good":"bad",value:d.charge/100})}),(0,e.jsx)(n.Ki.Item,{label:"Cell Capacity",children:(0,e.jsx)(n.az,{color:d.cell_capacity<3e4?"average":"good",children:d.cell_capacity})})]})||(0,e.jsx)(n.Ki.Item,{label:"Cell",children:(0,e.jsx)(n.az,{color:"bad",children:"No Power Cell"})}),!!d.is_hacked&&(0,e.jsx)(n.Ki.Item,{label:"Safeties",children:(0,e.jsx)(n.az,{color:"bad",children:"DISABLED"})}),(0,e.jsx)(n.Ki.Item,{label:"Module",children:d.module}),(0,e.jsx)(n.Ki.Item,{label:"Master AI",children:(0,e.jsx)(n.az,{color:d.synchronization?"default":"average",children:d.synchronization||"None"})}),!!d.is_shell&&(0,e.jsx)(n.Ki.Item,{label:"Occupier",children:d.occupier})]})},d.uid)}):(0,e.jsx)(n.IC,{children:"No cyborg units detected within access parameters."})}},8633:(q,S,r)=>{"use strict";r.r(S),r.d(S,{pda_security:()=>a});var e=r(1131),l=r(360),n=r(8725);function t(){return t=Object.assign||function(b){for(var O=1;O{"use strict";r.r(S),r.d(S,{AlertModal:()=>u});var e=r(1131),l=r(7003),n=r(5180),t=r(1808),a=r(360),b=r(3521),O=r(3384),y=function(d){return d[d.Increment=1]="Increment",d[d.Decrement=-1]="Decrement",d}(y||{}),u=function(d){var v=(0,a.Oc)(),_=v.act,s=v.data,c=s.autofocus,f=s.buttons,g=f===void 0?[]:f,p=s.large_buttons,j=s.message,x=j===void 0?"":j,C=s.timeout,I=s.title,P=function(N,Q,ie){Q=ie+"px "+Q;var Z=document.createElement("canvas"),V=Z.getContext("2d");return V.font=Q,V.measureText(N).width},M=(0,l.useState)(0),B=M[0],w=M[1],T=345+(g.length>2?55:0),L=67/g.length+23,K=g.some(function(N){return P(N,"Verdana, Geneva",p?14:12)>T/g.length-L}),U=K&&p?20:15,J=120+(K?U*g.length:0)+(x.length>30?Math.ceil(x.length/4):0)+(x.length&&p?5:0),$=function(N){switch(N.key){case t._.Space:case t._.Enter:_("choose",{choice:g[B]});return;case t._.Left:N.preventDefault(),W(-1);return;case t._.Tab:case t._.Right:N.preventDefault(),W(1);return;default:if((0,t.KL)(N.key)){_("cancel");return}}},W=function(N){var Q=(B+N+g.length)%g.length;w(Q)};return(0,e.jsxs)(b.p8,{height:J,title:I,width:T,children:[!!C&&(0,e.jsx)(O.Loader,{value:C}),(0,e.jsx)(b.p8.Content,{onKeyDown:$,children:(0,e.jsx)(n.wn,{fill:!0,children:(0,e.jsxs)(n.BJ,{fill:!0,vertical:!0,children:[(0,e.jsx)(n.BJ.Item,{m:1,children:(0,e.jsx)(n.az,{color:"label",overflow:"hidden",children:x})}),(0,e.jsxs)(n.BJ.Item,{grow:!0,children:[!!c&&(0,e.jsx)(n.y5,{}),K?(0,e.jsx)(m,{selected:B}):(0,e.jsx)(h,{selected:B})]})]})})})]})},h=function(d){var v=(0,a.Oc)(),_=v.act,s=v.data,c=s.buttons,f=c===void 0?[]:c,g=s.large_buttons,p=s.swapped_buttons,j=d.selected;return(0,e.jsx)(n.BJ,{fill:!0,justify:"space-around",reverse:!p,children:f.map(function(x,C){return(0,e.jsx)(n.BJ.Item,{grow:g?1:void 0,children:(0,e.jsx)(n.$n,{fluid:!!g,minWidth:5,onClick:function(){return _("choose",{choice:x})},overflowX:"hidden",px:2,py:g?.5:0,selected:j===C,textAlign:"center",children:g?x.toUpperCase():x})},C)})})},m=function(d){var v=(0,a.Oc)(),_=v.act,s=v.data,c=s.buttons,f=c===void 0?[]:c,g=s.large_buttons,p=s.swapped_buttons,j=d.selected;return(0,e.jsx)(n.BJ,{align:"center",fill:!0,justify:"space-around",reverse:!p,vertical:!0,children:f.map(function(x,C){return(0,e.jsx)(n.BJ.Item,{grow:!0,width:g?"100%":void 0,m:0,children:(0,e.jsx)(n.$n,{fluid:!0,minWidth:20,onClick:function(){return _("choose",{choice:x})},overflowX:"hidden",px:2,py:g?.5:0,selected:j===C,textAlign:"center",children:g?x.toUpperCase():x})},C)})})}},8711:(q,S,r)=>{"use strict";r.r(S),r.d(S,{BeakerPanel:()=>c});var e=r(1131),l=r(7003),n=r(5180),t=r(9845),a=r(360),b=r(3521);function O(){return O=Object.assign||function(f){for(var g=1;g{"use strict";r.r(S),r.d(S,{ObjectComponent:()=>m});var e=r(1131),l=r(7003),n=r(5180),t=r(185),a=r(8968),b=r(7941);function O(){return O=Object.assign||function(d){for(var v=1;v=0)&&(_[c]=d[c]);return _}function h(d,v){return h=Object.setPrototypeOf||function(s,c){return s.__proto__=c,s},h(d,v)}var m=function(d){"use strict";y(v,d);function v(s){var c;return c=d.call(this,s)||this,c.state={isDragging:!1,dragPos:null,startPos:null,lastMousePos:null},c.handleStartDrag=c.handleStartDrag.bind(c),c.handleStopDrag=c.handleStopDrag.bind(c),c.handleDrag=c.handleDrag.bind(c),c}var _=v.prototype;return _.handleStartDrag=function(c){var f=this.props,g=f.x,p=f.y;c.stopPropagation(),this.setState({lastMousePos:null,isDragging:!0,dragPos:{x:g,y:p},startPos:{x:g,y:p}}),window.addEventListener("mousemove",this.handleDrag),window.addEventListener("mouseup",this.handleStopDrag)},_.handleStopDrag=function(c){var f=this.state,g=f.dragPos,p=f.isDragging,j=this.props,x=j.index,C=j.act,I=C===void 0?a.noop:C;g&&p&&I("set_component_coordinates",{component_id:x,rel_x:this.roundToGrid(g.x),rel_y:this.roundToGrid(g.y)}),window.removeEventListener("mousemove",this.handleDrag),window.removeEventListener("mouseup",this.handleStopDrag),this.setState({isDragging:!1})},_.handleDrag=function(c){var f=this.state,g=f.dragPos,p=f.isDragging,j=f.lastMousePos,x=this.props.zoom;if(g&&p){c.preventDefault();var C=c.screenZoomX,I=c.screenZoomY,P=c.screenX,M=c.screenY,B=C||P,w=I||M;j&&this.setState({dragPos:{x:g.x-(j.x-B)*Math.pow(x,-1),y:g.y-(j.y-w)*Math.pow(x,-1)}}),this.setState({lastMousePos:{x:B,y:w}})}},_.shouldComponentUpdate=function(c,f){var g=this.props,p=g.input_ports,j=g.output_ports;return(0,t.a_)(this.props,c)||(0,t.a_)(this.state,f)||(0,t.a_)(p,c.input_ports)||(0,t.a_)(j,c.output_ports)},_.roundToGrid=function(c){return this.props.gridMode?Math.round(c/10)*10:c},_.render=function(){var c=this.props,f=c.input_ports,g=c.output_ports,p=c.name,j=c.x,x=c.y,C=c.index,I=c.category,P=I===void 0?"\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E":I,M=c.removable,B=c.ui_alerts,w=c.ui_buttons,T=c.locations,L=c.onPortUpdated,K=L===void 0?a.noop:L,U=c.onPortLoaded,J=U===void 0?a.noop:U,$=c.onPortMouseDown,W=$===void 0?a.noop:$,N=c.onPortRightClick,Q=N===void 0?a.noop:N,ie=c.onPortMouseUp,Z=ie===void 0?a.noop:ie,V=c.act,Y=V===void 0?a.noop:V,le=c.gridMode,xe=le===void 0?!0:le,de=u(c,["input_ports","output_ports","name","x","y","index","category","removable","ui_alerts","ui_buttons","locations","onPortUpdated","onPortLoaded","onPortMouseDown","onPortRightClick","onPortMouseUp","act","gridMode"]),me=this.state,pe=me.startPos,be=me.dragPos,ke=[j,x],Re=ke[0],De=ke[1];be&&pe&&pe.x===Re&&pe.y===De&&(Re=this.roundToGrid(be.x),De=this.roundToGrid(be.y));var tn={onPortLoaded:J,onPortUpdated:K,onPortMouseDown:W,onPortRightClick:Q,onPortMouseUp:Z};return(0,e.jsxs)(n.az,O({className:"ObjectComponent",position:"absolute",left:""+Re+"px",top:""+De+"px",onMouseDown:this.handleStartDrag,onMouseUp:this.handleStopDrag,style:{userSelect:"none"}},de,{children:[(0,e.jsx)(n.az,{py:1,px:1,className:(0,t.Ly)(["ObjectComponent__Titlebar","ObjectComponent__Category__"+P]),children:(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{grow:1,children:p}),!!w&&Object.keys(w).map(function(Ue){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:Ue,compact:!0,className:"ObjectComponent__Category__"+P,onClick:function(){return Y("perform_action",{component_id:C,action_name:w[Ue]})}})},Ue)}),!!B&&Object.keys(B).map(function(Ue){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{className:"ObjectComponent__Category__"+P,icon:Ue,compact:!0,tooltip:B[Ue]})},Ue)}),(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"info",compact:!0,className:"ObjectComponent__Category__"+P,onClick:function(Ue){return Y("set_examined_component",{component_id:C,x:Ue.pageX,y:Ue.pageY+a.ABSOLUTE_Y_OFFSET})}})}),!!M&&(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"times",compact:!0,className:"ObjectComponent__Category__"+P,onClick:function(Ue){return Y("detach_component",{component_id:C,ctrl:!!Ue.ctrlKey})}})})]})}),(0,e.jsx)(n.az,{className:"ObjectComponent__Content",py:1,px:1,children:(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{grow:1,children:(0,e.jsx)(n.BJ,{vertical:!0,fill:!0,children:f.map(function(Ue,We){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(b.Port,O({port:Ue,portIndex:We+1,componentId:C,act:Y},tn))},We)})})}),(0,e.jsx)(n.BJ.Item,{ml:5,children:(0,e.jsx)(n.BJ,{vertical:!0,children:g.map(function(Ue,We){return(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(b.Port,O({act:Y,port:Ue,portIndex:We+1,componentId:C},tn,{isOutput:!0}))},We)})})})]})})]}))},v}(l.Component)},8725:(q,S,r)=>{"use strict";r.r(S),r.d(S,{SimpleRecords:()=>u});var e=r(1131),l=r(360),n=r(7003),t=r(9845),a=r(5070),b=r(1859),O=r(5180);function y(){return y=Object.assign||function(d){for(var v=1;v{"use strict";r.r(S),r.d(S,{PDA:()=>y});var e=r(1131),l=r(360),n=r(5180),t=r(3521),a=r(9160),b=r(7865),O=function(m){var d;try{d=b("./"+m+".tsx")}catch(_){if(_.code==="MODULE_NOT_FOUND")return(0,a.z)("notFound",m);throw _}var v=d[m];return v||(0,a.z)("missingExport",m)},y=function(m){var d=(0,l.Oc)().data,v=d.app,_=d.owner;if(!_)return(0,e.jsx)(t.p8,{width:350,height:105,children:(0,e.jsx)(t.p8.Content,{scrollable:!0,children:(0,e.jsx)(n.wn,{title:"Error",children:"No user data found. Please swipe an ID card."})})});var s=O(v.template);return(0,e.jsx)(t.p8,{width:600,height:650,children:(0,e.jsx)(t.p8.Content,{scrollable:!0,children:(0,e.jsxs)(n.BJ,{fill:!0,vertical:!0,children:[(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(u,{})}),(0,e.jsx)(n.BJ.Item,{grow:!0,children:(0,e.jsx)(n.wn,{fill:!0,scrollable:!0,p:1,pb:0,title:(0,e.jsxs)(n.az,{children:[(0,e.jsx)(n.In,{name:v.icon,mr:1}),v.name]}),children:(0,e.jsx)(s,{})})}),(0,e.jsx)(n.BJ.Item,{mt:7.5,children:(0,e.jsx)(h,{})})]})})})},u=function(m){var d=(0,l.Oc)(),v=d.act,_=d.data,s=_.idInserted,c=_.idLink,f=_.stationTime,g=_.cartridge_name,p=_.request_cartridge_name;return(0,e.jsxs)(n.BJ,{fill:!0,children:[(0,e.jsx)(n.BJ.Item,{ml:.5,children:(0,e.jsx)(n.$n,{icon:"id-card",color:"transparent",onClick:function(){return v("Authenticate")},children:s?c:"No ID Inserted"})}),(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"sd-card",color:"transparent",onClick:function(){return v("Eject")},children:g?["Eject "+g]:"No Cartridge Inserted"})}),(0,e.jsx)(n.BJ.Item,{children:(0,e.jsx)(n.$n,{icon:"sd-card",color:"transparent",onClick:function(){return v("Eject_Request")},children:p?["Eject "+p]:"No Request Cartridge Inserted"})}),(0,e.jsx)(n.BJ.Item,{grow:!0,textAlign:"right",bold:!0,mr:1,mt:.5,children:f})]})},h=function(m){var d=(0,l.Oc)(),v=d.act,_=d.data,s=_.app;return(0,e.jsx)(n.az,{height:"45px",className:"PDA__footer",backgroundColor:"#1b1b1b",children:(0,e.jsxs)(n.BJ,{fill:!0,children:[!!s.has_back&&(0,e.jsx)(n.BJ.Item,{basis:"33%",mr:-.5,children:(0,e.jsx)(n.$n,{fluid:!0,className:"PDA__footer__button",color:"transparent",iconColor:s.has_back?"white":"disabled",icon:"arrow-alt-circle-left-o",onClick:function(){return v("Back")}})}),(0,e.jsx)(n.BJ.Item,{basis:s.has_back?"33%":"100%",children:(0,e.jsx)(n.$n,{fluid:!0,className:"PDA__footer__button",color:"transparent",iconColor:s.is_home?"disabled":"white",icon:"home",onClick:function(){v("Home")}})})]})})}},8773:(q,S,r)=>{"use strict";r.r(S),r.d(S,{Biogenerator:()=>b});var e=r(1131),l=r(360),n=r(5180),t=r(3521),a=r(9680),b=function(h){var m=(0,l.Oc)(),d=m.data,v=m.config,_=d.processing,s=v.title;return(0,e.jsx)(t.p8,{width:390,height:595,children:(0,e.jsx)(t.p8.Content,{children:(0,e.jsxs)(n.BJ,{fill:!0,vertical:!0,children:[(0,e.jsx)(a.Operating,{operating:_,name:s}),(0,e.jsx)(O,{}),(0,e.jsx)(y,{}),(0,e.jsx)(u,{})]})})})},O=function(h){var m=(0,l.Oc)().data,d=m.biomass,v=m.container,_=m.container_curr_reagents,s=m.container_max_reagents;return(0,e.jsxs)(n.wn,{title:"Storage",children:[(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{mr:"20px",color:"silver",children:"Biomass:"}),(0,e.jsx)(n.BJ.Item,{mr:"5px",children:d}),(0,e.jsx)(n.In,{name:"leaf",size:1.2,color:"#3d8c40"})]}),(0,e.jsxs)(n.BJ,{height:"21px",mt:"8px",align:"center",children:[(0,e.jsx)(n.BJ.Item,{mr:"10px",color:"silver",children:"Container:"}),v?(0,e.jsx)(n.z2,{value:_,maxValue:s,children:(0,e.jsx)(n.az,{textAlign:"center",children:_+" / "+s+" units"})}):(0,e.jsx)(n.BJ.Item,{children:"None"})]})]})},y=function(h){var m=(0,l.Oc)(),d=m.act,v=m.data,_=v.has_plants,s=v.container;return(0,e.jsx)(n.wn,{title:"Controls",children:(0,e.jsxs)(n.BJ,{children:[(0,e.jsx)(n.BJ.Item,{width:"30%",children:(0,e.jsx)(n.$n,{fluid:!0,textAlign:"center",icon:"power-off",disabled:!_,tooltip:_?"":"There are no plants in the biogenerator.",tooltipPosition:"top-start",onClick:function(){return d("activate")},children:"Activate"})}),(0,e.jsx)(n.BJ.Item,{width:"40%",children:(0,e.jsx)(n.$n,{fluid:!0,textAlign:"center",icon:"flask",disabled:!s,tooltip:s?"":"The biogenerator does not have a container.",tooltipPosition:"top",onClick:function(){return d("detach_container")},children:"Detach Container"})}),(0,e.jsx)(n.BJ.Item,{width:"30%",children:(0,e.jsx)(n.$n,{fluid:!0,textAlign:"center",icon:"eject",disabled:!_,tooltip:_?"":"There are no stored plants to eject.",tooltipPosition:"top-end",onClick:function(){return d("eject_plants")},children:"Eject Plants"})})]})})},u=function(h){var m=(0,l.Oc)(),d=m.act,v=m.data,_=v.biomass,s=v.product_list,c=v.container,f=(0,l.QY)("vendAmount",1),g=f[0],p=f[1],j=Object.entries(s).map(function(x,C){var I=Object.entries(x[1]).map(function(P){return P[1]});return(0,e.jsx)(n.Nt,{title:x[0],open:!0,children:I.map(function(P){return(0,e.jsxs)(n.BJ,{py:"2px",className:"candystripe",align:"center",children:[(0,e.jsx)(n.BJ.Item,{width:"50%",ml:"2px",children:P.name}),(0,e.jsxs)(n.BJ.Item,{textAlign:"right",width:"20%",children:[P.cost*g,(0,e.jsx)(n.In,{ml:"5px",name:"leaf",size:1.2,color:"#3d8c40"})]}),(0,e.jsx)(n.BJ.Item,{textAlign:"right",width:"40%",children:P.needs_container&&!c?(0,e.jsx)(n.$n,{disabled:!0,icon:"flask",tooltip:"\u0412\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043B\u044E\u0431\u043E\u0439 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u044D\u0442\u043E\u0439 \u043E\u043F\u0446\u0438\u0438",children:"No containe"}):(0,e.jsx)(n.$n,{disabled:_{"use strict";r.r(S),r.d(S,{pda_notes:()=>t});var e=r(1131),l=r(360),n=r(5180),t=function(a){var b=(0,l.Oc)(),O=b.act,y=b.data,u=y.note;return(0,e.jsxs)(n.az,{children:[(0,e.jsx)(n.wn,{children:u}),(0,e.jsx)(n.$n,{icon:"pen",onClick:function(){return O("Edit")},children:"Edit"})]})}},8809:(q,S,r)=>{"use strict";/** * @license React * react-jsx-runtime.production.min.js *