[MIRROR] Robot upgrades (#9412)

Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2024-11-05 00:28:01 -07:00
committed by GitHub
parent 040cbbe106
commit 302cc08221
13 changed files with 663 additions and 152 deletions

View File

@@ -4,7 +4,7 @@
// Mutable appearances are children of images, just so you know. // Mutable appearances are children of images, just so you know.
/image/mutable_appearance/New(copy_from, ...) /mutable_appearance/New(copy_from, ...)
..() ..()
if(!copy_from) if(!copy_from)
plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE

View File

@@ -89,6 +89,13 @@
.["target"]["components"] = get_components() .["target"]["components"] = get_components()
.["cell"] = list("name" = target.cell?.name, "charge" = target.cell?.charge, "maxcharge" = target.cell?.maxcharge) .["cell"] = list("name" = target.cell?.name, "charge" = target.cell?.charge, "maxcharge" = target.cell?.maxcharge)
.["cell_options"] = get_cells() .["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 // Access
.["id_icon"] = icon2html(target.idcard, user, sourceonly=TRUE) .["id_icon"] = icon2html(target.idcard, user, sourceonly=TRUE)
var/list/active_access = list() var/list/active_access = list()
@@ -198,7 +205,7 @@
target.module.contents.Add(add_item) target.module.contents.Add(add_item)
spawn(0) spawn(0)
SEND_SIGNAL(add_item, COMSIG_OBSERVER_MOVED) 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/)) if(istype(add_item, /obj/item/stack/))
var/obj/item/stack/item_with_synth = add_item var/obj/item/stack/item_with_synth = add_item
for(var/synth in item_with_synth.synths) for(var/synth in item_with_synth.synths)
@@ -243,7 +250,7 @@
if("rem_module") if("rem_module")
var/obj/item/rem_item = locate(params["module"]) var/obj/item/rem_item = locate(params["module"])
target.uneq_all() 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.emag.Remove(rem_item)
target.module.modules.Remove(rem_item) target.module.modules.Remove(rem_item)
target.module.contents.Remove(rem_item) target.module.contents.Remove(rem_item)
@@ -262,14 +269,14 @@
source.emag_items = 1 source.emag_items = 1
// Target // Target
target.uneq_all() target.uneq_all()
target.hud_used.update_robot_modules_display(TRUE) target.hud_used?.update_robot_modules_display(TRUE)
qdel(target.module) qdel(target.module)
target.modtype = mod_type target.modtype = mod_type
module_type = robot_modules[mod_type] module_type = robot_modules[mod_type]
target.transform_with_anim() target.transform_with_anim()
new module_type(target) new module_type(target)
target.hands.icon_state = target.get_hud_module_icon() 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 return TRUE
if("ert_toggle") if("ert_toggle")
target.crisis_override = !target.crisis_override target.crisis_override = !target.crisis_override
@@ -299,7 +306,7 @@
if(!U.action(target)) if(!U.action(target))
return FALSE return FALSE
U.loc = target U.loc = target
target.hud_used.update_robot_modules_display() target.hud_used?.update_robot_modules_display()
return TRUE return TRUE
if("install_modkit") if("install_modkit")
var/new_modkit = text2path(params["modkit"]) var/new_modkit = text2path(params["modkit"])
@@ -348,22 +355,34 @@
var/datum/robot_component/C = locate(params["component"]) var/datum/robot_component/C = locate(params["component"])
if(C.wrapped) if(C.wrapped)
qdel(C.wrapped) qdel(C.wrapped)
var/new_component = text2path(params["new_part"])
if(istype(C, /datum/robot_component/actuator)) 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)) 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)) else if(istype(C, /datum/robot_component/cell))
var/new_cell = text2path(params["cell"]) target.cell = new new_component(target)
target.cell = new new_cell(target)
C.wrapped = target.cell C.wrapped = target.cell
else if(istype(C, /datum/robot_component/diagnosis_unit)) 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)) 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)) 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)) 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.brute_damage = 0
C.electronics_damage = 0 C.electronics_damage = 0
C.install() C.install()
@@ -533,7 +552,7 @@
target.clear_inherent_laws() target.clear_inherent_laws()
target.laws = new global.using_map.default_law_type target.laws = new global.using_map.default_law_type
target.laws.show_laws(target) target.laws.show_laws(target)
target.hud_used.update_robot_modules_display() target.hud_used?.update_robot_modules_display()
else else
target.emagged = 1 target.emagged = 1
target.lawupdate = 0 target.lawupdate = 0
@@ -545,7 +564,7 @@
if(!target.bolt.malfunction) if(!target.bolt.malfunction)
target.bolt.malfunction = MALFUNCTION_PERMANENT target.bolt.malfunction = MALFUNCTION_PERMANENT
target.laws.show_laws(target) target.laws.show_laws(target)
target.hud_used.update_robot_modules_display() target.hud_used?.update_robot_modules_display()
return TRUE return TRUE
/datum/eventkit/modify_robot/proc/get_target_items(var/mob/user) /datum/eventkit/modify_robot/proc/get_target_items(var/mob/user)
@@ -672,14 +691,59 @@
continue continue
if(cell_options[initial(C.name)]) // empty cells are defined after normal cells! if(cell_options[initial(C.name)]) // empty cells are defined after normal cells!
continue 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 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() /datum/eventkit/modify_robot/proc/get_components()
var/list/components = list() var/list/components = list()
for(var/entry in target.components) for(var/entry in target.components)
var/datum/robot_component/C = target.components[entry] 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 return components
/datum/eventkit/modify_robot/proc/package_laws(var/list/data, var/field, var/list/datum/ai_law/laws) /datum/eventkit/modify_robot/proc/package_laws(var/list/data, var/field, var/list/datum/ai_law/laws)

View File

@@ -21,7 +21,20 @@
src.owner = R src.owner = R
/datum/robot_component/proc/install() /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() /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() /datum/robot_component/proc/destroy()
var/brokenstate = "broken" // Generic icon var/brokenstate = "broken" // Generic icon
@@ -231,24 +244,34 @@
var/brute = 0 var/brute = 0
var/burn = 0 var/burn = 0
var/icon_state_broken = "broken" 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 /obj/item/robot_parts/robot_component/binary_communication_device
name = "binary communication device" name = "binary communication device"
desc = "A module used for binary communications over encrypted frequencies, commonly used by synthetic robots." desc = "A module used for binary communications over encrypted frequencies, commonly used by synthetic robots."
icon_state = "binradio" icon_state = "binradio"
icon_state_broken = "binradio_broken" icon_state_broken = "binradio_broken"
idle_usage = 5
active_usage = 25
max_damage = 30
/obj/item/robot_parts/robot_component/actuator /obj/item/robot_parts/robot_component/actuator
name = "actuator" name = "actuator"
desc = "A modular, hydraulic actuator used by exosuits and robots alike for movement and manipulation." desc = "A modular, hydraulic actuator used by exosuits and robots alike for movement and manipulation."
icon_state = "motor" icon_state = "motor"
icon_state_broken = "motor_broken" icon_state_broken = "motor_broken"
idle_usage = 0
active_usage = 200
max_damage = 50
/obj/item/robot_parts/robot_component/armour /obj/item/robot_parts/robot_component/armour
name = "armour plating" name = "armour plating"
desc = "A pair of flexible, adaptable armor plates, used to protect the internals of robots." desc = "A pair of flexible, adaptable armor plates, used to protect the internals of robots."
icon_state = "armor" icon_state = "armor"
icon_state_broken = "armor_broken" icon_state_broken = "armor_broken"
max_damage = 90
/obj/item/robot_parts/robot_component/armour_platform /obj/item/robot_parts/robot_component/armour_platform
name = "platform armour plating" name = "platform armour plating"
@@ -256,21 +279,64 @@
icon_state = "armor" icon_state = "armor"
icon_state_broken = "armor_broken" icon_state_broken = "armor_broken"
color = COLOR_GRAY80 color = COLOR_GRAY80
max_damage = 140
/obj/item/robot_parts/robot_component/camera /obj/item/robot_parts/robot_component/camera
name = "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." 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 = "camera"
icon_state_broken = "camera_broken" icon_state_broken = "camera_broken"
idle_usage = 10
max_damage = 40
/obj/item/robot_parts/robot_component/diagnosis_unit /obj/item/robot_parts/robot_component/diagnosis_unit
name = "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." 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 = "analyser"
icon_state_broken = "analyser_broken" icon_state_broken = "analyser_broken"
active_usage = 1000
max_damage = 30
/obj/item/robot_parts/robot_component/radio /obj/item/robot_parts/robot_component/radio
name = "radio" name = "radio"
desc = "A modular, multi-frequency radio used by robots and exosuits to enable communication systems. Comes with built-in subspace receivers." 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 = "radio"
icon_state_broken = "radio_broken" 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

View File

@@ -6,6 +6,12 @@
health = getMaxHealth() - (getBruteLoss() + getFireLoss()) health = getMaxHealth() - (getBruteLoss() + getFireLoss())
return 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() /mob/living/silicon/robot/getBruteLoss()
var/amount = 0 var/amount = 0
for(var/V in components) for(var/V in components)

View File

@@ -27,6 +27,7 @@
var/last_use = 0 // A tracker for use in self-charging 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/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/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) matter = list(MAT_STEEL = 700, MAT_GLASS = 50)
drop_sound = 'sound/items/drop/component.ogg' drop_sound = 'sound/items/drop/component.ogg'
pickup_sound = 'sound/items/pickup/component.ogg' pickup_sound = 'sound/items/pickup/component.ogg'

View File

@@ -29,6 +29,7 @@
matter = null matter = null
standard_overlays = FALSE standard_overlays = FALSE
var/swaps_to = /obj/item/cell/device/weapon/recharge/alien var/swaps_to = /obj/item/cell/device/weapon/recharge/alien
robot_durability = 100
/obj/item/cell/void/attack_self(var/mob/user) /obj/item/cell/void/attack_self(var/mob/user)
user.remove_from_mob(src) user.remove_from_mob(src)

View File

@@ -17,6 +17,7 @@
icon_state = "crap" icon_state = "crap"
maxcharge = 500 maxcharge = 500
matter = list(MAT_STEEL = 700, MAT_GLASS = 40) matter = list(MAT_STEEL = 700, MAT_GLASS = 40)
robot_durability = 20
/obj/item/cell/crap/update_icon() //No visible charge indicator /obj/item/cell/crap/update_icon() //No visible charge indicator
return return
@@ -51,6 +52,7 @@
icon_state = "high" icon_state = "high"
maxcharge = 10000 maxcharge = 10000
matter = list(MAT_STEEL = 700, MAT_GLASS = 60) matter = list(MAT_STEEL = 700, MAT_GLASS = 60)
robot_durability = 55
/obj/item/cell/high/empty/Initialize() //ChompEDIT New --> Initialize /obj/item/cell/high/empty/Initialize() //ChompEDIT New --> Initialize
..() ..()
@@ -66,6 +68,7 @@
icon_state = "super" icon_state = "super"
maxcharge = 20000 maxcharge = 20000
matter = list(MAT_STEEL = 700, MAT_GLASS = 70) matter = list(MAT_STEEL = 700, MAT_GLASS = 70)
robot_durability = 60
/obj/item/cell/super/empty/Initialize() //ChompEDIT New --> Initialize /obj/item/cell/super/empty/Initialize() //ChompEDIT New --> Initialize
..() ..()
@@ -80,6 +83,7 @@
description_fluff = "Almost as good as a hyper." description_fluff = "Almost as good as a hyper."
icon_state = "super" //We don't want roboticists confuse it with a low standard cell icon_state = "super" //We don't want roboticists confuse it with a low standard cell
maxcharge = 25000 maxcharge = 25000
robot_durability = 65
/* /*
* Hyper * Hyper
@@ -90,6 +94,7 @@
icon_state = "hyper" icon_state = "hyper"
maxcharge = 30000 maxcharge = 30000
matter = list(MAT_STEEL = 700, MAT_GLASS = 80) matter = list(MAT_STEEL = 700, MAT_GLASS = 80)
robot_durability = 70
/obj/item/cell/hyper/empty/Initialize() //ChompEDIT New --> Initialize /obj/item/cell/hyper/empty/Initialize() //ChompEDIT New --> Initialize
..() ..()
@@ -144,6 +149,7 @@
origin_tech = null origin_tech = null
maxcharge = 30000 //determines how badly mobs get shocked maxcharge = 30000 //determines how badly mobs get shocked
matter = list(MAT_STEEL = 700, MAT_GLASS = 80) matter = list(MAT_STEEL = 700, MAT_GLASS = 80)
robot_durability = 200
/obj/item/cell/infinite/check_charge() /obj/item/cell/infinite/check_charge()
return 1 return 1
@@ -162,6 +168,7 @@
charge = 100 charge = 100
maxcharge = 300 maxcharge = 300
minor_fault = 1 minor_fault = 1
robot_durability = 30
/* /*
* Slime * Slime

View File

@@ -378,6 +378,50 @@
id = "mmi_ai_shell" id = "mmi_ai_shell"
build_path = /obj/item/mmi/inert/ai_remote 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 //////////////////// //////////////////// Cyborg Modules ////////////////////
/datum/design/item/prosfab/robot_upgrade /datum/design/item/prosfab/robot_upgrade
category = list("Cyborg Modules") category = list("Cyborg Modules")

View File

@@ -1,40 +1,149 @@
import { toFixed } from 'common/math';
import { capitalize } from 'common/string'; import { capitalize } from 'common/string';
import { useState } from 'react'; import { useState } from 'react';
import { useBackend } from 'tgui/backend'; import { useBackend } from 'tgui/backend';
import { import {
Box,
Button, Button,
Collapsible,
Divider, Divider,
Dropdown,
Flex, Flex,
Icon, Icon,
Image, Image,
Input, Input,
Section, Section,
Slider,
Stack, Stack,
Tabs,
} from 'tgui/components'; } from 'tgui/components';
import { NoSpriteWarning } from '../components'; import { NoSpriteWarning } from '../components';
import {
ACTUATOR,
ARMOUR,
CAMERA,
COMMS,
DIAGNOSIS,
POWERCELL,
RADIO,
} from '../constants';
import { prepareSearch } from '../functions'; 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: { export const ModifyRobotComponent = (props: {
target: Target; target: Target;
cell: InstalledCell; cell: InstalledCell;
cells: Record<string, Cell>; cells: Record<string, Cell>;
cams: Record<string, Comp>;
rads: Record<string, Comp>;
acts: Record<string, Comp>;
diags: Record<string, Comp>;
comms: Record<string, Comp>;
arms: Record<string, Comp>;
gear: Record<string, string>;
}) => { }) => {
const { act } = useBackend(); const { target, cell, cells, cams, rads, acts, diags, comms, arms, gear } =
const { target, cell, cells } = props; props;
const [searchComponentReplaceText, setSearchComponentReplaceText] = const [searchComponentReplaceText, setSearchComponentReplaceText] =
useState<string>(''); useState<string>('');
const [searchComponentRemoveText, setSearchComponentRemoveText] = const [searchComponentRemoveText, setSearchComponentRemoveText] =
useState<string>(''); useState<string>('');
const [selectedCell, setSelectedCell] = useState<string>(cell.name || ''); const [selectedCell, setSelectedCell] = useState<string>(cell.name || '');
const [selectedCam, setSelectedCam] = useState<string>(gear[CAMERA] || '');
const [selectedRad, setSelectedRad] = useState<string>(gear[RADIO] || '');
const [selectedAct, setSelectedAct] = useState<string>(gear[ACTUATOR] || '');
const [selectedDiag, setSelectedDiag] = useState<string>(
gear[DIAGNOSIS] || '',
);
const [selectedComm, setSelectedComm] = useState<string>(gear[COMMS] || '');
const [selectedArm, setSelectedArm] = useState<string>(gear[ARMOUR] || '');
const [tab, setTab] = useState<number>(0);
const cell_options = Object.keys(cells) as Array<string>; const cell_options = Object.keys(cells) as Array<string>;
const cam_options = Object.keys(cams) as Array<string>;
const rad_options = Object.keys(rads) as Array<string>;
const act_options = Object.keys(acts) as Array<string>;
const diag_options = Object.keys(diags) as Array<string>;
const comm_options = Object.keys(comms) as Array<string>;
const arm_options = Object.keys(arms) as Array<string>;
const tabs: React.JSX.Element[] = [];
tabs[0] = (
<CellCommp
cell={cell}
selectedCell={selectedCell}
cell_options={cell_options}
onSelectedCell={setSelectedCell}
cells={cells}
/>
);
tabs[1] = (
<CompTab
selectedAct={selectedAct}
act_options={act_options}
onSelectedAct={setSelectedAct}
acts={acts}
selectedRad={selectedRad}
rad_options={rad_options}
onSelectedRad={setSelectedRad}
rads={rads}
selectedDiag={selectedDiag}
diag_options={diag_options}
onSelectedDiag={setSelectedDiag}
diags={diags}
selectedCam={selectedCam}
cam_options={cam_options}
onSelectedCam={setSelectedCam}
cams={cams}
selectedComm={selectedComm}
comm_options={comm_options}
onSelectedComm={setSelectedComm}
comms={comms}
selectedArm={selectedArm}
arm_options={arm_options}
onSelectedArm={setSelectedArm}
arms={arms}
/>
);
tabs[2] = <BadminTab target={target} />;
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 ( return (
<> <>
{!target.active && <NoSpriteWarning name={target.name} />} {!target.active && <NoSpriteWarning name={target.name} />}
@@ -48,13 +157,11 @@ export const ModifyRobotComponent = (props: {
action="add_component" action="add_component"
buttonColor="green" buttonColor="green"
buttonIcon="arrows-spin" buttonIcon="arrows-spin"
celltype={cells[selectedCell]?.path} componentLookup={componentLookup}
selected_cell={selectedCell}
cell={cell.name || undefined}
/> />
</Flex.Item> </Flex.Item>
<Flex.Item width="30%"> <Flex.Item width="30%" fill>
<Stack vertical> <Stack vertical fill>
<Stack.Item> <Stack.Item>
<Image <Image
src={'data:image/jpeg;base64, ' + target.side_alt} src={'data:image/jpeg;base64, ' + target.side_alt}
@@ -67,106 +174,19 @@ export const ModifyRobotComponent = (props: {
/> />
</Stack.Item> </Stack.Item>
<Stack.Item> <Stack.Item>
<Section title="Power cell"> <Tabs>
Current cell:{' '} <Tabs.Tab selected={tab === 0} onClick={() => setTab(0)}>
{cell.name ? ( Power Cell
capitalize(cell.name) </Tabs.Tab>
) : ( <Tabs.Tab selected={tab === 1} onClick={() => setTab(1)}>
<Box inline color="red"> Components
No cell installed! </Tabs.Tab>
</Box> <Tabs.Tab selected={tab === 2} onClick={() => setTab(2)}>
)} Badmin
<Slider </Tabs.Tab>
stepPixelSize={5} </Tabs>
format={(value) => 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),
})
}
>
<Flex>
<Flex.Item>Current charge</Flex.Item>
<Flex.Item grow />
<Flex.Item>{cell.charge}</Flex.Item>
</Flex>
</Slider>
<Dropdown
width="100%"
selected={selectedCell}
options={cell_options}
onSelected={setSelectedCell}
/>
<Stack vertical>
<Stack.Item>
Charge State: {cells[selectedCell]?.charge} /{' '}
{cells[selectedCell]?.max_charge}
</Stack.Item>
<Stack.Item>
Charge Rate: {cells[selectedCell]?.charge_amount}
</Stack.Item>
<Stack.Item>
Self Charge:{' '}
{cells[selectedCell]?.self_charge ? 'Yes' : 'No'}
</Stack.Item>
</Stack>
</Section>
<Section scrollable fill>
<Collapsible title="Badmin">
{target.components.map((component, i) => {
return (
<Collapsible title={capitalize(component.name)} key={i}>
<Slider
color="red"
disabled={component.installed !== 1}
minValue={0}
maxValue={component.max_damage * 5 || 0}
value={component.brute_damage || 0}
onChange={(e, value) =>
act('adjust_brute', {
component: component.ref,
damage: value,
})
}
>
<Flex>
<Flex.Item>Brute damage</Flex.Item>
<Flex.Item grow />
<Flex.Item>{component.brute_damage}</Flex.Item>
</Flex>
</Slider>
<Slider
color="orange"
key={i}
disabled={component.installed !== 1}
minValue={0}
maxValue={component.max_damage * 5 || 0}
value={component.electronics_damage || 0}
onChange={(e, value) =>
act('adjust_electronics', {
component: component.ref,
damage: value,
})
}
>
<Flex>
<Flex.Item>Electronics damage</Flex.Item>
<Flex.Item grow />
<Flex.Item>
{component.electronics_damage}
</Flex.Item>
</Flex>
</Slider>
</Collapsible>
);
})}
</Collapsible>
</Section>
</Stack.Item> </Stack.Item>
{tabs[tab]}
</Stack> </Stack>
</Flex.Item> </Flex.Item>
<Flex.Item width="35%" fill> <Flex.Item width="35%" fill>
@@ -193,9 +213,7 @@ const ComponentSection = (props: {
action: string; action: string;
buttonColor: string; buttonColor: string;
buttonIcon: string; buttonIcon: string;
celltype?: string; componentLookup?: Lookup[];
selected_cell?: string;
cell?: string;
}) => { }) => {
const { act } = useBackend(); const { act } = useBackend();
const { const {
@@ -206,9 +224,7 @@ const ComponentSection = (props: {
action, action,
buttonColor, buttonColor,
buttonIcon, buttonIcon,
celltype, componentLookup = [],
selected_cell,
cell,
} = props; } = props;
return ( return (
<Section title={title} fill scrollable> <Section title={title} fill scrollable>
@@ -229,15 +245,20 @@ const ComponentSection = (props: {
tooltip={getComponentTooltip( tooltip={getComponentTooltip(
component, component,
action, action,
selected_cell, componentLookup[component.name]?.selected,
cell, componentLookup[component.name]?.active,
)} )}
color={getComponentColor(component, action)} color={getComponentColor(component, action)}
disabled={checkDisabled(component, action, selected_cell, cell)} disabled={checkDisabled(
component,
action,
componentLookup[component.name]?.selected,
componentLookup[component.name]?.active,
)}
onClick={() => onClick={() =>
act(action, { act(action, {
component: component.ref, component: component.ref,
cell: celltype, new_part: componentLookup[component.name]?.path,
}) })
} }
> >
@@ -259,6 +280,16 @@ const ComponentSection = (props: {
</Flex.Item> </Flex.Item>
</Flex> </Flex>
</Stack.Item> </Stack.Item>
{action === 'add_component' && (
<Flex>
<Flex.Item>Idle Power: {component.idle_usage}</Flex.Item>
<Flex.Item grow />
<Flex.Item>
Active Power: {component.active_usage}
</Flex.Item>
</Flex>
)}
<Stack.Item />
<Stack.Item> <Stack.Item>
{action === 'add_component' && {action === 'add_component' &&
'Brute Damage: ' + component.brute_damage} 'Brute Damage: ' + component.brute_damage}
@@ -279,19 +310,14 @@ const ComponentSection = (props: {
function checkDisabled( function checkDisabled(
component: Component, component: Component,
action: string, action: string,
selected_cell: string | undefined, selected: string | undefined,
cell: string | undefined, active: string | undefined,
): boolean { ): boolean {
switch (action) { switch (action) {
case 'rem_component': case 'rem_component':
return !component.exists; return !component.exists;
case 'add_component': case 'add_component':
if ( if (selected && active && selected !== active) {
selected_cell &&
cell &&
component.name === 'power cell' &&
selected_cell !== cell
) {
return false; return false;
} }
return ( return (
@@ -307,8 +333,8 @@ function checkDisabled(
function getComponentTooltip( function getComponentTooltip(
component: Component, component: Component,
action: string, action: string,
selected_cell: string | undefined, selected: string | undefined,
cell: string | undefined, active: string | undefined,
): string { ): string {
switch (action) { switch (action) {
case 'add_component': case 'add_component':
@@ -322,7 +348,7 @@ function getComponentTooltip(
) { ) {
return 'Component destroyed!'; return 'Component destroyed!';
} }
if (checkDisabled(component, action, selected_cell, cell)) { if (checkDisabled(component, action, selected, active)) {
return 'Disabled due to fully intact component!'; return 'Disabled due to fully intact component!';
} }
return ''; return '';

View File

@@ -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<string, Cell>;
}) => {
const { act } = useBackend();
const { cell, selectedCell, cell_options, onSelectedCell, cells } = props;
return (
<Section>
Current cell:{' '}
{cell.name ? (
capitalize(cell.name)
) : (
<Box inline color="red">
No cell installed!
</Box>
)}
<Slider
stepPixelSize={5}
format={(value) => 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),
})
}
>
<Flex>
<Flex.Item>Current charge</Flex.Item>
<Flex.Item grow />
<Flex.Item>{cell.charge}</Flex.Item>
</Flex>
</Slider>
<Dropdown
width="100%"
selected={selectedCell}
options={cell_options}
onSelected={onSelectedCell}
/>
<Stack vertical>
<Stack.Item>Max Damage: {cells[selectedCell]?.max_damage}</Stack.Item>
<Stack.Item>
Charge State: {cells[selectedCell]?.charge} /{' '}
{cells[selectedCell]?.max_charge}
</Stack.Item>
<Stack.Item>
Charge Rate: {cells[selectedCell]?.charge_amount}
</Stack.Item>
<Stack.Item>
Self Charge: {cells[selectedCell]?.self_charge ? 'Yes' : 'No'}
</Stack.Item>
</Stack>
</Section>
);
};
export const CompTab = (props: {
selectedAct: string;
act_options: string[];
onSelectedAct: (value: any) => void;
acts: Record<string, Comp>;
selectedRad: string;
rad_options: string[];
onSelectedRad: (value: any) => void;
rads: Record<string, Comp>;
selectedDiag: string;
diag_options: string[];
onSelectedDiag: (value: any) => void;
diags: Record<string, Comp>;
selectedCam: string;
cam_options: string[];
onSelectedCam: (value: any) => void;
cams: Record<string, Comp>;
selectedComm: string;
comm_options: string[];
onSelectedComm: (value: any) => void;
comms: Record<string, Comp>;
selectedArm: string;
arm_options: string[];
onSelectedArm: (value: any) => void;
arms: Record<string, Comp>;
}) => {
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 (
<Section scrollable fill>
<Dropdown
width="100%"
selected={selectedAct}
options={act_options}
onSelected={onSelectedAct}
/>
<ComponentInfo comps={acts[selectedAct]} />
<Dropdown
width="100%"
selected={selectedRad}
options={rad_options}
onSelected={onSelectedRad}
/>
<ComponentInfo comps={rads[selectedRad]} />
<Dropdown
width="100%"
selected={selectedDiag}
options={diag_options}
onSelected={onSelectedDiag}
/>
<ComponentInfo comps={diags[selectedDiag]} />
<Dropdown
width="100%"
selected={selectedCam}
options={cam_options}
onSelected={onSelectedCam}
/>
<ComponentInfo comps={cams[selectedCam]} />
<Dropdown
width="100%"
selected={selectedComm}
options={comm_options}
onSelected={onSelectedComm}
/>
<ComponentInfo comps={comms[selectedComm]} />
<Dropdown
width="100%"
selected={selectedArm}
options={arm_options}
onSelected={onSelectedArm}
/>
<ComponentInfo comps={arms[selectedArm]} />
</Section>
);
};
export const BadminTab = (props: { target: Target }) => {
const { act } = useBackend();
const { target } = props;
return (
<Section scrollable fill>
<Collapsible title="Badmin">
{target.components.map((component, i) => {
return (
<Collapsible title={capitalize(component.name)} key={i}>
<Slider
color="red"
disabled={component.installed !== 1}
minValue={0}
maxValue={component.max_damage * 5 || 0}
value={component.brute_damage || 0}
onChange={(e, value) =>
act('adjust_brute', {
component: component.ref,
damage: value,
})
}
>
<Flex>
<Flex.Item>Brute damage</Flex.Item>
<Flex.Item grow />
<Flex.Item>{component.brute_damage}</Flex.Item>
</Flex>
</Slider>
<Slider
color="orange"
key={i}
disabled={component.installed !== 1}
minValue={0}
maxValue={component.max_damage * 5 || 0}
value={component.electronics_damage || 0}
onChange={(e, value) =>
act('adjust_electronics', {
component: component.ref,
damage: value,
})
}
>
<Flex>
<Flex.Item>Electronics damage</Flex.Item>
<Flex.Item grow />
<Flex.Item>{component.electronics_damage}</Flex.Item>
</Flex>
</Slider>
</Collapsible>
);
})}
</Collapsible>
</Section>
);
};
const ComponentInfo = (props: { comps: Comp }) => {
const { comps } = props;
return (
<Stack vertical>
<Stack.Item>Max Damage: {comps?.max_damage}</Stack.Item>
<Stack.Item>
<Flex>
<Flex.Item>Idle Power: {comps?.idle_usage}</Flex.Item>
<Flex.Item grow />
<Flex.Item>Active Power: {comps?.active_usage}</Flex.Item>
</Flex>
</Stack.Item>
</Stack>
);
};

View File

@@ -4,3 +4,11 @@ export const install2col = {
1: 'green', 1: 'green',
2: 'grey', 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';

View File

@@ -57,6 +57,13 @@ export const ModifyRobot = (props) => {
channel, channel,
channels, channels,
law_sets, law_sets,
camera_options,
radio_options,
actuator_options,
diagnosis_options,
comms_options,
armour_options,
current_gear,
} = data; } = data;
const [tab, setTab] = useState<number>(0); const [tab, setTab] = useState<number>(0);
@@ -82,7 +89,18 @@ export const ModifyRobot = (props) => {
tabs[2] = <ModifyRobotPKA target={target!} />; tabs[2] = <ModifyRobotPKA target={target!} />;
tabs[3] = <ModifyRobotRadio target={target!} />; tabs[3] = <ModifyRobotRadio target={target!} />;
tabs[4] = ( tabs[4] = (
<ModifyRobotComponent target={target!} cell={cell} cells={cell_options} /> <ModifyRobotComponent
target={target!}
cell={cell}
cells={cell_options}
cams={camera_options}
rads={radio_options}
acts={actuator_options}
diags={diagnosis_options}
comms={comms_options}
arms={armour_options}
gear={current_gear}
/>
); );
tabs[5] = ( tabs[5] = (
<ModifyRobotAccess <ModifyRobotAccess

View File

@@ -7,6 +7,13 @@ export type Data = {
model_options: string[] | null; model_options: string[] | null;
cell: InstalledCell; cell: InstalledCell;
cell_options: Record<string, Cell>; cell_options: Record<string, Cell>;
camera_options: Record<string, Comp>;
radio_options: Record<string, Comp>;
actuator_options: Record<string, Comp>;
diagnosis_options: Record<string, Comp>;
comms_options: Record<string, Comp>;
armour_options: Record<string, Comp>;
current_gear: Record<string, string>;
id_icon: string; id_icon: string;
access_options: Access[] | undefined; access_options: Access[] | undefined;
ion_law_nr: string; ion_law_nr: string;
@@ -85,6 +92,8 @@ export type Component = {
brute_damage: number; brute_damage: number;
electronics_damage: number; electronics_damage: number;
max_damage: number; max_damage: number;
idle_usage: number;
active_usage: number;
installed: number; installed: number;
exists: BooleanLike; exists: BooleanLike;
}; };
@@ -115,10 +124,24 @@ export type Cell = {
max_charge: number; max_charge: number;
charge_amount: number; charge_amount: number;
self_charge: BooleanLike; 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 Access = { id: number; name: string };
export type Lookup = {
path: string;
selected: string | undefined;
active: string | undefined;
};
type law_pack = { type law_pack = {
name: string; name: string;
header: string; header: string;