From a1576977cccc9cb18ce53ac97e3cf3c2cf8b861f Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:12:31 +0100 Subject: [PATCH] Robot upgrades (#16481) * initial * variable cell durability and hp increase on upgrades * cell hp * cell influences components * set defaults for most * value tgui * . * . * . * fix copy typoes * also this * . * sanity that * . --- code/datums/mutable_appearance.dm | 2 +- code/modules/admin/modify_robot.dm | 98 +++++- code/modules/client/client procs.dm | 2 +- .../mob/living/silicon/robot/component.dm | 68 +++- .../mob/living/silicon/robot/robot_damage.dm | 6 + code/modules/power/cell.dm | 1 + code/modules/power/cells/device_cells_vr.dm | 1 + code/modules/power/cells/power_cells.dm | 7 + code/modules/research/prosfab_designs.dm | 44 +++ .../ModifyRobotTabs/ModifyRobotComponent.tsx | 292 ++++++++++-------- .../ModifyRobotComponentTabs.tsx | 247 +++++++++++++++ .../tgui/interfaces/ModifyRobot/constants.ts | 8 + .../tgui/interfaces/ModifyRobot/index.tsx | 20 +- .../tgui/interfaces/ModifyRobot/types.ts | 23 ++ 14 files changed, 665 insertions(+), 154 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponentTabs.tsx diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm index 98ece935a6..56faf42469 100644 --- a/code/datums/mutable_appearance.dm +++ b/code/datums/mutable_appearance.dm @@ -4,7 +4,7 @@ // Mutable appearances are children of images, just so you know. -/image/mutable_appearance/New(copy_from, ...) +/mutable_appearance/New(copy_from, ...) ..() if(!copy_from) plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 9166f3be29..f2847943f3 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -89,6 +89,13 @@ .["target"]["components"] = get_components() .["cell"] = list("name" = target.cell?.name, "charge" = target.cell?.charge, "maxcharge" = target.cell?.maxcharge) .["cell_options"] = get_cells() + .["camera_options"] = get_component("camera") + .["radio_options"] = get_component("radio") + .["actuator_options"] = get_component("actuator") + .["diagnosis_options"] = get_component("diagnosis") + .["comms_options"] = get_component("comms") + .["armour_options"] = get_component("armour") + .["current_gear"] = get_gear() // Access .["id_icon"] = icon2html(target.idcard, user, sourceonly=TRUE) var/list/active_access = list() @@ -198,7 +205,7 @@ target.module.contents.Add(add_item) spawn(0) SEND_SIGNAL(add_item, COMSIG_OBSERVER_MOVED) - target.hud_used.update_robot_modules_display() + target.hud_used?.update_robot_modules_display() if(istype(add_item, /obj/item/stack/)) var/obj/item/stack/item_with_synth = add_item for(var/synth in item_with_synth.synths) @@ -243,7 +250,7 @@ if("rem_module") var/obj/item/rem_item = locate(params["module"]) target.uneq_all() - target.hud_used.update_robot_modules_display(TRUE) + target.hud_used?.update_robot_modules_display(TRUE) target.module.emag.Remove(rem_item) target.module.modules.Remove(rem_item) target.module.contents.Remove(rem_item) @@ -262,14 +269,14 @@ source.emag_items = 1 // Target target.uneq_all() - target.hud_used.update_robot_modules_display(TRUE) + target.hud_used?.update_robot_modules_display(TRUE) qdel(target.module) target.modtype = mod_type module_type = robot_modules[mod_type] target.transform_with_anim() new module_type(target) target.hands.icon_state = target.get_hud_module_icon() - target.hud_used.update_robot_modules_display() + target.hud_used?.update_robot_modules_display() return TRUE if("ert_toggle") target.crisis_override = !target.crisis_override @@ -299,7 +306,7 @@ if(!U.action(target)) return FALSE U.loc = target - target.hud_used.update_robot_modules_display() + target.hud_used?.update_robot_modules_display() return TRUE if("install_modkit") var/new_modkit = text2path(params["modkit"]) @@ -348,22 +355,34 @@ var/datum/robot_component/C = locate(params["component"]) if(C.wrapped) qdel(C.wrapped) + var/new_component = text2path(params["new_part"]) if(istype(C, /datum/robot_component/actuator)) - C.wrapped = new /obj/item/robot_parts/robot_component/actuator(target) + if(!new_component) + new_component = /obj/item/robot_parts/robot_component/actuator + C.wrapped = new new_component(target) else if(istype(C, /datum/robot_component/radio)) - C.wrapped = new /obj/item/robot_parts/robot_component/radio(target) + if(!new_component) + new_component = /obj/item/robot_parts/robot_component/radio + C.wrapped = new new_component(target) else if(istype(C, /datum/robot_component/cell)) - var/new_cell = text2path(params["cell"]) - target.cell = new new_cell(target) + target.cell = new new_component(target) C.wrapped = target.cell else if(istype(C, /datum/robot_component/diagnosis_unit)) - C.wrapped = new /obj/item/robot_parts/robot_component/diagnosis_unit(target) + if(!new_component) + new_component = /obj/item/robot_parts/robot_component/diagnosis_unit + C.wrapped = new new_component(target) else if(istype(C, /datum/robot_component/camera)) - C.wrapped = new /obj/item/robot_parts/robot_component/camera(target) + if(!new_component) + new_component = /obj/item/robot_parts/robot_component/camera + C.wrapped = new new_component(target) else if(istype(C, /datum/robot_component/binary_communication)) - C.wrapped = new /obj/item/robot_parts/robot_component/binary_communication_device(target) + if(!new_component) + new_component = /obj/item/robot_parts/robot_component/binary_communication_device + C.wrapped = new new_component(target) else if(istype(C, /datum/robot_component/armour)) - C.wrapped = new /obj/item/robot_parts/robot_component/armour(target) + if(!new_component) + new_component = /obj/item/robot_parts/robot_component/armour + C.wrapped = new new_component(target) C.brute_damage = 0 C.electronics_damage = 0 C.install() @@ -533,7 +552,7 @@ target.clear_inherent_laws() target.laws = new global.using_map.default_law_type target.laws.show_laws(target) - target.hud_used.update_robot_modules_display() + target.hud_used?.update_robot_modules_display() else target.emagged = 1 target.lawupdate = 0 @@ -545,7 +564,7 @@ if(!target.bolt.malfunction) target.bolt.malfunction = MALFUNCTION_PERMANENT target.laws.show_laws(target) - target.hud_used.update_robot_modules_display() + target.hud_used?.update_robot_modules_display() return TRUE /datum/eventkit/modify_robot/proc/get_target_items(var/mob/user) @@ -672,14 +691,59 @@ continue if(cell_options[initial(C.name)]) // empty cells are defined after normal cells! continue - cell_options += list(initial(C.name) = list("path" = "[C]", "charge" = initial(C.maxcharge), "max_charge" = initial(C.maxcharge), "charge_amount" = initial(C.charge_amount) , "self_charge" = initial(C.self_recharge))) // our cells do not have their charge predefined, they do it on init, so both maaxcharge for now + cell_options += list(initial(C.name) = list("path" = "[C]", "charge" = initial(C.maxcharge), "max_charge" = initial(C.maxcharge), "charge_amount" = initial(C.charge_amount) , "self_charge" = initial(C.self_recharge), "max_damage" = initial(C.robot_durability))) // our cells do not have their charge predefined, they do it on init, so both maaxcharge for now return cell_options +/datum/eventkit/modify_robot/proc/get_component(var/type) + var/path + switch(type) + if("camera") + path = /obj/item/robot_parts/robot_component/camera + if("radio") + path = /obj/item/robot_parts/robot_component/radio + if("actuator") + path = /obj/item/robot_parts/robot_component/actuator + if("diagnosis") + path = /obj/item/robot_parts/robot_component/diagnosis_unit + if("comms") + path = /obj/item/robot_parts/robot_component/binary_communication_device + if("armour") + path = /obj/item/robot_parts/robot_component/armour + if(!path) + return + var/list/components = list() + for(var/component in typesof(path)) + var/obj/item/robot_parts/robot_component/C = component + components += list("[initial(C.name)]" = list("path" = "[component]", "idle_usage" = "[C.idle_usage]", "active_usage" = "[C.active_usage]", "max_damage" = "[C.max_damage]")) + return components + +/datum/eventkit/modify_robot/proc/get_gear() + var/list/equip = list() + for (var/V in target.components) + var/datum/robot_component/C = target.components[V] + var/component_name + if(istype(C.wrapped, /obj/item/robot_parts/robot_component)) + component_name = C.wrapped?.name + switch(V) + if("actuator") + equip += list("[lowertext(C.name)]" = "[component_name]") + if("radio") + equip += list("[lowertext(C.name)]" = "[component_name]") + if("diagnosis unit") + equip += list("[lowertext(C.name)]" = "[component_name]") + if("camera") + equip += list("[lowertext(C.name)]" = "[component_name]") + if("comms") + equip += list("[lowertext(C.name)]" = "[component_name]") + if("armour") + equip += list("[lowertext(C.name)]" = "[component_name]") + return equip + /datum/eventkit/modify_robot/proc/get_components() var/list/components = list() for(var/entry in target.components) var/datum/robot_component/C = target.components[entry] - components += list(list("name" = C.name, "ref" = "\ref[C]", "brute_damage" = C.brute_damage, "electronics_damage" = C.electronics_damage, "max_damage" = C.max_damage, "installed" = C.installed, "exists" = (C.wrapped ? TRUE : FALSE))) + components += list(list("name" = C.name, "ref" = "\ref[C]", "brute_damage" = C.brute_damage, "electronics_damage" = C.electronics_damage, "max_damage" = C.max_damage, "idle_usage" = C.idle_usage, "active_usage" = C.active_usage, "installed" = C.installed, "exists" = (C.wrapped ? TRUE : FALSE))) return components /datum/eventkit/modify_robot/proc/package_laws(var/list/data, var/field, var/list/datum/ai_law/laws) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index f7d4a940c1..86dffce176 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -518,7 +518,7 @@ /client/verb/game_options() set name = "Game Options" - set category = "Preferences.Character" + set category = "Preferences.Game" if(prefs) prefs.tgui_interact(usr) diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index f89061e88e..d57d1092a6 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -21,7 +21,20 @@ src.owner = R /datum/robot_component/proc/install() + if(istype(wrapped, /obj/item/robot_parts/robot_component)) + var/obj/item/robot_parts/robot_component/comp = wrapped + max_damage = comp.max_damage + idle_usage = comp.idle_usage + active_usage = comp.active_usage + return + if(istype(wrapped, /obj/item/cell)) + var/obj/item/cell/cell = wrapped + max_damage = cell.robot_durability + /datum/robot_component/proc/uninstall() + max_damage = initial(max_damage) + idle_usage = initial(idle_usage) + active_usage = initial(active_usage) /datum/robot_component/proc/destroy() var/brokenstate = "broken" // Generic icon @@ -231,24 +244,34 @@ var/brute = 0 var/burn = 0 var/icon_state_broken = "broken" + var/idle_usage = 0 + var/active_usage = 0 + var/max_damage = 0 /obj/item/robot_parts/robot_component/binary_communication_device name = "binary communication device" desc = "A module used for binary communications over encrypted frequencies, commonly used by synthetic robots." icon_state = "binradio" icon_state_broken = "binradio_broken" + idle_usage = 5 + active_usage = 25 + max_damage = 30 /obj/item/robot_parts/robot_component/actuator name = "actuator" desc = "A modular, hydraulic actuator used by exosuits and robots alike for movement and manipulation." icon_state = "motor" icon_state_broken = "motor_broken" + idle_usage = 0 + active_usage = 200 + max_damage = 50 /obj/item/robot_parts/robot_component/armour name = "armour plating" desc = "A pair of flexible, adaptable armor plates, used to protect the internals of robots." icon_state = "armor" icon_state_broken = "armor_broken" + max_damage = 90 /obj/item/robot_parts/robot_component/armour_platform name = "platform armour plating" @@ -256,21 +279,64 @@ icon_state = "armor" icon_state_broken = "armor_broken" color = COLOR_GRAY80 + max_damage = 140 /obj/item/robot_parts/robot_component/camera name = "camera" desc = "A modified camera module used as a visual receptor for robots and exosuits, also serving as a relay for wireless video feed." icon_state = "camera" icon_state_broken = "camera_broken" + idle_usage = 10 + max_damage = 40 /obj/item/robot_parts/robot_component/diagnosis_unit name = "diagnosis unit" desc = "An internal computer and sensors used by robots and exosuits to accurately diagnose any system discrepancies on their components." icon_state = "analyser" icon_state_broken = "analyser_broken" + active_usage = 1000 + max_damage = 30 /obj/item/robot_parts/robot_component/radio name = "radio" desc = "A modular, multi-frequency radio used by robots and exosuits to enable communication systems. Comes with built-in subspace receivers." icon_state = "radio" - icon_state_broken = "radio_broken" \ No newline at end of file + icon_state_broken = "radio_broken" + idle_usage = 15 + active_usage = 75 + max_damage = 40 + +// Improved components +/obj/item/robot_parts/robot_component/binary_communication_device/upgraded + name = "improved binary communication device" + idle_usage = 2.5 + active_usage = 12.5 + max_damage = 45 + +/obj/item/robot_parts/robot_component/radio/upgraded + name = "improved radio" + idle_usage = 5 + active_usage = 35 + max_damage = 40 + +/obj/item/robot_parts/robot_component/actuator/upgraded + name = "improved actuator" + idle_usage = 0 + active_usage = 100 + max_damage = 75 + +/obj/item/robot_parts/robot_component/diagnosis_unit/upgraded + name = "improved self-diagnosis unit" + active_usage = 500 + max_damage = 45 + +/obj/item/robot_parts/robot_component/camera/upgraded + name = "improved camera" + idle_usage = 5 + max_damage = 60 + +/obj/item/robot_parts/robot_component/armour/armour_titan + name = "prototype armour plating" + desc = "A pair of flexible, adaptable armor plates, used to protect the internals of robots." + max_damage = 220 + color = COLOR_OFF_WHITE diff --git a/code/modules/mob/living/silicon/robot/robot_damage.dm b/code/modules/mob/living/silicon/robot/robot_damage.dm index 907148e453..1ad7f5c48f 100644 --- a/code/modules/mob/living/silicon/robot/robot_damage.dm +++ b/code/modules/mob/living/silicon/robot/robot_damage.dm @@ -6,6 +6,12 @@ health = getMaxHealth() - (getBruteLoss() + getFireLoss()) return +/mob/living/silicon/robot/getMaxHealth() + . = ..() + for(var/V in components) + var/datum/robot_component/C = components[V] + . += C.max_damage - initial(C.max_damage) + /mob/living/silicon/robot/getBruteLoss() var/amount = 0 for(var/V in components) diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 2a98049b0b..e963b54849 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -27,6 +27,7 @@ var/last_use = 0 // A tracker for use in self-charging var/connector_type = "standard" //What connector sprite to use when in a cell charger, null if no connectors var/charge_delay = 0 // How long it takes for the cell to start recharging after last use + var/robot_durability = 50 matter = list(MAT_STEEL = 700, MAT_GLASS = 50) drop_sound = 'sound/items/drop/component.ogg' pickup_sound = 'sound/items/pickup/component.ogg' diff --git a/code/modules/power/cells/device_cells_vr.dm b/code/modules/power/cells/device_cells_vr.dm index f810799f84..8a62f646aa 100644 --- a/code/modules/power/cells/device_cells_vr.dm +++ b/code/modules/power/cells/device_cells_vr.dm @@ -29,6 +29,7 @@ matter = null standard_overlays = FALSE var/swaps_to = /obj/item/cell/device/weapon/recharge/alien + robot_durability = 100 /obj/item/cell/void/attack_self(var/mob/user) user.remove_from_mob(src) diff --git a/code/modules/power/cells/power_cells.dm b/code/modules/power/cells/power_cells.dm index 774c5d8817..f4a7c9d1aa 100644 --- a/code/modules/power/cells/power_cells.dm +++ b/code/modules/power/cells/power_cells.dm @@ -16,6 +16,7 @@ icon_state = "crap" maxcharge = 500 matter = list(MAT_STEEL = 700, MAT_GLASS = 40) + robot_durability = 20 /obj/item/cell/crap/update_icon() //No visible charge indicator return @@ -50,6 +51,7 @@ icon_state = "high" maxcharge = 10000 matter = list(MAT_STEEL = 700, MAT_GLASS = 60) + robot_durability = 55 /obj/item/cell/high/empty/New() ..() @@ -65,6 +67,7 @@ icon_state = "super" maxcharge = 20000 matter = list(MAT_STEEL = 700, MAT_GLASS = 70) + robot_durability = 60 /obj/item/cell/super/empty/New() ..() @@ -79,6 +82,7 @@ description_fluff = "Almost as good as a hyper." icon_state = "super" //We don't want roboticists confuse it with a low standard cell maxcharge = 25000 + robot_durability = 65 /* * Hyper @@ -89,6 +93,7 @@ icon_state = "hyper" maxcharge = 30000 matter = list(MAT_STEEL = 700, MAT_GLASS = 80) + robot_durability = 70 /obj/item/cell/hyper/empty/New() ..() @@ -143,6 +148,7 @@ origin_tech = null maxcharge = 30000 //determines how badly mobs get shocked matter = list(MAT_STEEL = 700, MAT_GLASS = 80) + robot_durability = 200 /obj/item/cell/infinite/check_charge() return 1 @@ -161,6 +167,7 @@ charge = 100 maxcharge = 300 minor_fault = 1 + robot_durability = 30 /* * Slime diff --git a/code/modules/research/prosfab_designs.dm b/code/modules/research/prosfab_designs.dm index 803ac462db..8bf0beb742 100644 --- a/code/modules/research/prosfab_designs.dm +++ b/code/modules/research/prosfab_designs.dm @@ -378,6 +378,50 @@ id = "mmi_ai_shell" build_path = /obj/item/mmi/inert/ai_remote +//////////////////// Advanced Components //////////////////// +/datum/design/item/prosfab/cyborg/component/radio_upgraded + name = "Improved Radio" + id = "improved_radio" + build_path = /obj/item/robot_parts/robot_component/radio/upgraded + req_tech = list(TECH_MAGNET = 7, TECH_MATERIAL = 5, TECH_PRECURSOR = 1) + materials = list(MAT_STEEL = 10000, MAT_DIAMOND = 2000, MAT_PLASTEEL = 3000, MAT_GLASS = 6500, MAT_SILVER = 3000, MAT_MORPHIUM = 560, MAT_DURASTEEL = 800) + +/datum/design/item/prosfab/cyborg/component/actuator_upgraded + name = "Improved Actuator" + id = "improved_actuator" + build_path = /obj/item/robot_parts/robot_component/actuator/upgraded + req_tech = list(TECH_MAGNET = 7, TECH_MATERIAL = 5, TECH_PRECURSOR = 1) + materials = list(MAT_STEEL = 10000, MAT_PLASTEEL = 2500, MAT_MORPHIUM = 500, MAT_DURASTEEL = 500) + +/datum/design/item/prosfab/cyborg/component/diagnosis_unit_upgraded + name = "Improved Diagnosis Unit" + id = "improved_diagnosis_unit" + build_path = /obj/item/robot_parts/robot_component/diagnosis_unit/upgraded + req_tech = list(TECH_MAGNET = 7, TECH_MATERIAL = 5, TECH_PRECURSOR = 1) + materials = list(MAT_STEEL = 10000, MAT_DIAMOND = 2000, MAT_URANIUM = 4000, MAT_PLASTEEL = 1000, MAT_GLASS = 400, MAT_SILVER = 1000, MAT_MORPHIUM = 420, MAT_DURASTEEL = 600) + +/datum/design/item/prosfab/cyborg/component/camera_upgraded + name = "Improved Camera" + id = "improved_camera" + build_path = /obj/item/robot_parts/robot_component/camera/upgraded + req_tech = list(TECH_MAGNET = 7, TECH_MATERIAL = 5, TECH_PRECURSOR = 1) + materials = list(MAT_STEEL = 10000, MAT_DIAMOND = 2000, MAT_PLASTEEL = 3000, MAT_GLASS = 6500, MAT_SILVER = 3000, MAT_MORPHIUM = 560, MAT_DURASTEEL = 800) + +/datum/design/item/prosfab/cyborg/component/binary_communication_device/upgraded + name = "Improved Binary Communication Device" + id = "improved_binary_communication_device" + build_path = /obj/item/robot_parts/robot_component/binary_communication_device/upgraded + req_tech = list(TECH_MAGNET = 7, TECH_MATERIAL = 5, TECH_PRECURSOR = 1) + materials = list(MAT_STEEL = 10000, MAT_DIAMOND = 2000, MAT_PLASTEEL = 3000, MAT_GLASS = 6500, MAT_GOLD = 3000, MAT_DURASTEEL = 800) + +/datum/design/item/prosfab/cyborg/component/armour_very_heavy + name = "Armour Plating (Prototype)" + id = "titan_armour" + build_path = /obj/item/robot_parts/robot_component/armour/armour_titan + req_tech = list(TECH_MATERIAL = 9, TECH_PRECURSOR = 3) + materials = list(MAT_STEEL = 12000, MAT_MORPHIUM = 3000, MAT_DURASTEEL = 5000) + + //////////////////// Cyborg Modules //////////////////// /datum/design/item/prosfab/robot_upgrade category = list("Cyborg Modules") diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx index a2ba8e8294..293db7da7d 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx @@ -1,40 +1,149 @@ -import { toFixed } from 'common/math'; import { capitalize } from 'common/string'; import { useState } from 'react'; import { useBackend } from 'tgui/backend'; import { - Box, Button, - Collapsible, Divider, - Dropdown, Flex, Icon, Image, Input, Section, - Slider, Stack, + Tabs, } from 'tgui/components'; import { NoSpriteWarning } from '../components'; +import { + ACTUATOR, + ARMOUR, + CAMERA, + COMMS, + DIAGNOSIS, + POWERCELL, + RADIO, +} from '../constants'; import { prepareSearch } from '../functions'; -import { Cell, Component, InstalledCell, Target } from '../types'; +import { Cell, Comp, Component, InstalledCell, Lookup, Target } from '../types'; +import { BadminTab, CellCommp, CompTab } from './ModifyRobotComponentTabs'; export const ModifyRobotComponent = (props: { target: Target; cell: InstalledCell; cells: Record; + cams: Record; + rads: Record; + acts: Record; + diags: Record; + comms: Record; + arms: Record; + gear: Record; }) => { - const { act } = useBackend(); - const { target, cell, cells } = props; + const { target, cell, cells, cams, rads, acts, diags, comms, arms, gear } = + props; const [searchComponentReplaceText, setSearchComponentReplaceText] = useState(''); const [searchComponentRemoveText, setSearchComponentRemoveText] = useState(''); const [selectedCell, setSelectedCell] = useState(cell.name || ''); + const [selectedCam, setSelectedCam] = useState(gear[CAMERA] || ''); + const [selectedRad, setSelectedRad] = useState(gear[RADIO] || ''); + const [selectedAct, setSelectedAct] = useState(gear[ACTUATOR] || ''); + const [selectedDiag, setSelectedDiag] = useState( + gear[DIAGNOSIS] || '', + ); + const [selectedComm, setSelectedComm] = useState(gear[COMMS] || ''); + const [selectedArm, setSelectedArm] = useState(gear[ARMOUR] || ''); + const [tab, setTab] = useState(0); const cell_options = Object.keys(cells) as Array; + const cam_options = Object.keys(cams) as Array; + const rad_options = Object.keys(rads) as Array; + const act_options = Object.keys(acts) as Array; + const diag_options = Object.keys(diags) as Array; + const comm_options = Object.keys(comms) as Array; + const arm_options = Object.keys(arms) as Array; + const tabs: React.JSX.Element[] = []; + + tabs[0] = ( + + ); + tabs[1] = ( + + ); + tabs[2] = ; + + const componentLookup: Lookup[] = []; + + componentLookup[ACTUATOR] = { + path: acts[selectedAct]?.path, + selected: selectedAct, + active: gear[ACTUATOR] || undefined, + }; + componentLookup[RADIO] = { + path: rads[selectedRad]?.path, + selected: selectedRad, + active: gear[RADIO] || undefined, + }; + componentLookup[POWERCELL] = { + path: cells[selectedCell]?.path, + selected: selectedCell, + active: cell.name || undefined, + }; + componentLookup[CAMERA] = { + path: cams[selectedCam]?.path, + selected: selectedCam, + active: gear[CAMERA] || undefined, + }; + + componentLookup[DIAGNOSIS] = { + path: diags[selectedDiag]?.path, + selected: selectedDiag, + active: gear[DIAGNOSIS] || undefined, + }; + + componentLookup[COMMS] = { + path: comms[selectedComm]?.path, + selected: selectedComm, + active: gear[COMMS] || undefined, + }; + + componentLookup[ARMOUR] = { + path: arms[selectedArm]?.path, + selected: selectedArm, + active: gear[ARMOUR] || undefined, + }; return ( <> {!target.active && } @@ -48,13 +157,11 @@ export const ModifyRobotComponent = (props: { action="add_component" buttonColor="green" buttonIcon="arrows-spin" - celltype={cells[selectedCell]?.path} - selected_cell={selectedCell} - cell={cell.name || undefined} + componentLookup={componentLookup} /> - - + + -
- Current cell:{' '} - {cell.name ? ( - capitalize(cell.name) - ) : ( - - No cell installed! - - )} - toFixed(value, 2)} - disabled={!cell.charge} - minValue={0} - maxValue={100} - value={((cell.charge || 0) / (cell.maxcharge || 1)) * 100} - onChange={(e, value) => - act('adjust_cell_charge', { - charge: (value / 100) * (cell.maxcharge || 0), - }) - } - > - - Current charge - - {cell.charge} - - - - - - Charge State: {cells[selectedCell]?.charge} /{' '} - {cells[selectedCell]?.max_charge} - - - Charge Rate: {cells[selectedCell]?.charge_amount} - - - Self Charge:{' '} - {cells[selectedCell]?.self_charge ? 'Yes' : 'No'} - - -
-
- - {target.components.map((component, i) => { - return ( - - - act('adjust_brute', { - component: component.ref, - damage: value, - }) - } - > - - Brute damage - - {component.brute_damage} - - - - act('adjust_electronics', { - component: component.ref, - damage: value, - }) - } - > - - Electronics damage - - - {component.electronics_damage} - - - - - ); - })} - -
+ + setTab(0)}> + Power Cell + + setTab(1)}> + Components + + setTab(2)}> + Badmin + +
+ {tabs[tab]}
@@ -193,9 +213,7 @@ const ComponentSection = (props: { action: string; buttonColor: string; buttonIcon: string; - celltype?: string; - selected_cell?: string; - cell?: string; + componentLookup?: Lookup[]; }) => { const { act } = useBackend(); const { @@ -206,9 +224,7 @@ const ComponentSection = (props: { action, buttonColor, buttonIcon, - celltype, - selected_cell, - cell, + componentLookup = [], } = props; return (
@@ -229,15 +245,20 @@ const ComponentSection = (props: { tooltip={getComponentTooltip( component, action, - selected_cell, - cell, + componentLookup[component.name]?.selected, + componentLookup[component.name]?.active, )} color={getComponentColor(component, action)} - disabled={checkDisabled(component, action, selected_cell, cell)} + disabled={checkDisabled( + component, + action, + componentLookup[component.name]?.selected, + componentLookup[component.name]?.active, + )} onClick={() => act(action, { component: component.ref, - cell: celltype, + new_part: componentLookup[component.name]?.path, }) } > @@ -259,6 +280,16 @@ const ComponentSection = (props: { + {action === 'add_component' && ( + + Idle Power: {component.idle_usage} + + + Active Power: {component.active_usage} + + + )} + {action === 'add_component' && 'Brute Damage: ' + component.brute_damage} @@ -279,19 +310,14 @@ const ComponentSection = (props: { function checkDisabled( component: Component, action: string, - selected_cell: string | undefined, - cell: string | undefined, + selected: string | undefined, + active: string | undefined, ): boolean { switch (action) { case 'rem_component': return !component.exists; case 'add_component': - if ( - selected_cell && - cell && - component.name === 'power cell' && - selected_cell !== cell - ) { + if (selected && active && selected !== active) { return false; } return ( @@ -307,8 +333,8 @@ function checkDisabled( function getComponentTooltip( component: Component, action: string, - selected_cell: string | undefined, - cell: string | undefined, + selected: string | undefined, + active: string | undefined, ): string { switch (action) { case 'add_component': @@ -322,7 +348,7 @@ function getComponentTooltip( ) { return 'Component destroyed!'; } - if (checkDisabled(component, action, selected_cell, cell)) { + if (checkDisabled(component, action, selected, active)) { return 'Disabled due to fully intact component!'; } return ''; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponentTabs.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponentTabs.tsx new file mode 100644 index 0000000000..a55cbff157 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponentTabs.tsx @@ -0,0 +1,247 @@ +import { toFixed } from 'common/math'; +import { capitalize } from 'common/string'; +import { useBackend } from 'tgui/backend'; +import { + Box, + Collapsible, + Dropdown, + Flex, + Section, + Slider, + Stack, +} from 'tgui/components'; + +import { Cell, Comp, InstalledCell, Target } from '../types'; + +export const CellCommp = (props: { + cell: InstalledCell; + selectedCell: string; + cell_options: string[]; + onSelectedCell: (value: any) => void; + cells: Record; +}) => { + const { act } = useBackend(); + const { cell, selectedCell, cell_options, onSelectedCell, cells } = props; + return ( +
+ Current cell:{' '} + {cell.name ? ( + capitalize(cell.name) + ) : ( + + No cell installed! + + )} + toFixed(value, 2)} + disabled={!cell.charge} + minValue={0} + maxValue={100} + value={((cell.charge || 0) / (cell.maxcharge || 1)) * 100} + onChange={(e, value) => + act('adjust_cell_charge', { + charge: (value / 100) * (cell.maxcharge || 0), + }) + } + > + + Current charge + + {cell.charge} + + + + + Max Damage: {cells[selectedCell]?.max_damage} + + Charge State: {cells[selectedCell]?.charge} /{' '} + {cells[selectedCell]?.max_charge} + + + Charge Rate: {cells[selectedCell]?.charge_amount} + + + Self Charge: {cells[selectedCell]?.self_charge ? 'Yes' : 'No'} + + +
+ ); +}; + +export const CompTab = (props: { + selectedAct: string; + act_options: string[]; + onSelectedAct: (value: any) => void; + acts: Record; + selectedRad: string; + rad_options: string[]; + onSelectedRad: (value: any) => void; + rads: Record; + selectedDiag: string; + diag_options: string[]; + onSelectedDiag: (value: any) => void; + diags: Record; + selectedCam: string; + cam_options: string[]; + onSelectedCam: (value: any) => void; + cams: Record; + selectedComm: string; + comm_options: string[]; + onSelectedComm: (value: any) => void; + comms: Record; + selectedArm: string; + arm_options: string[]; + onSelectedArm: (value: any) => void; + arms: Record; +}) => { + const { + selectedAct, + act_options, + onSelectedAct, + acts, + selectedRad, + rad_options, + onSelectedRad, + rads, + selectedDiag, + diag_options, + onSelectedDiag, + diags, + selectedCam, + cam_options, + onSelectedCam, + cams, + selectedComm, + comm_options, + onSelectedComm, + comms, + selectedArm, + arm_options, + onSelectedArm, + arms, + } = props; + return ( +
+ + + + + + + + + + + + +
+ ); +}; + +export const BadminTab = (props: { target: Target }) => { + const { act } = useBackend(); + const { target } = props; + return ( +
+ + {target.components.map((component, i) => { + return ( + + + act('adjust_brute', { + component: component.ref, + damage: value, + }) + } + > + + Brute damage + + {component.brute_damage} + + + + act('adjust_electronics', { + component: component.ref, + damage: value, + }) + } + > + + Electronics damage + + {component.electronics_damage} + + + + ); + })} + +
+ ); +}; + +const ComponentInfo = (props: { comps: Comp }) => { + const { comps } = props; + return ( + + Max Damage: {comps?.max_damage} + + + Idle Power: {comps?.idle_usage} + + Active Power: {comps?.active_usage} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts b/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts index ab554eb3c3..57d39b74eb 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts @@ -4,3 +4,11 @@ export const install2col = { 1: 'green', 2: 'grey', }; + +export const ACTUATOR = 'actuator'; +export const RADIO = 'radio'; +export const POWERCELL = 'power cell'; +export const DIAGNOSIS = 'self-diagnosis unit'; +export const CAMERA = 'camera'; +export const COMMS = 'binary communication device'; +export const ARMOUR = 'armour plating'; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index 253f599656..212912520f 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -57,6 +57,13 @@ export const ModifyRobot = (props) => { channel, channels, law_sets, + camera_options, + radio_options, + actuator_options, + diagnosis_options, + comms_options, + armour_options, + current_gear, } = data; const [tab, setTab] = useState(0); @@ -82,7 +89,18 @@ export const ModifyRobot = (props) => { tabs[2] = ; tabs[3] = ; tabs[4] = ( - + ); tabs[5] = ( ; + camera_options: Record; + radio_options: Record; + actuator_options: Record; + diagnosis_options: Record; + comms_options: Record; + armour_options: Record; + current_gear: Record; id_icon: string; access_options: Access[] | undefined; ion_law_nr: string; @@ -85,6 +92,8 @@ export type Component = { brute_damage: number; electronics_damage: number; max_damage: number; + idle_usage: number; + active_usage: number; installed: number; exists: BooleanLike; }; @@ -115,10 +124,24 @@ export type Cell = { max_charge: number; charge_amount: number; self_charge: BooleanLike; + max_damage: number; }; +export type Comp = { + path: string; + max_damage: number; + idle_usage: number; + active_usage: number; +} | null; + export type Access = { id: number; name: string }; +export type Lookup = { + path: string; + selected: string | undefined; + active: string | undefined; +}; + type law_pack = { name: string; header: string;