diff --git a/baystation12.dme b/baystation12.dme index 1d8b91b8bd..d09a530659 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1036,6 +1036,7 @@ #include "code\modules\mob\living\silicon\pai\recruit.dm" #include "code\modules\mob\living\silicon\pai\say.dm" #include "code\modules\mob\living\silicon\pai\software.dm" +#include "code\modules\mob\living\silicon\robot\analyzer.dm" #include "code\modules\mob\living\silicon\robot\component.dm" #include "code\modules\mob\living\silicon\robot\death.dm" #include "code\modules\mob\living\silicon\robot\emote.dm" diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 8c6befa38f..a9056ef837 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -194,9 +194,18 @@ . = list() // Returns a list of mobs who can hear any of the radios given in @radios var/list/speaker_coverage = list() - for(var/i = 1; i <= radios.len; i++) - var/obj/item/device/radio/R = radios[i] + for(var/obj/item/device/radio/R in radios) if(R) + //Cyborg checks. Receiving message uses a bit of cyborg's charge. + var/obj/item/device/radio/borg/BR = R + if(istype(BR) && BR.myborg) + var/mob/living/silicon/robot/borg = BR.myborg + var/datum/robot_component/CO = borg.get_component("radio") + if(!CO) + continue //No radio component (Shouldn't happen) + if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage)) + continue //No power. + var/turf/speaker = get_turf(R) if(speaker) for(var/turf/T in hear(R.canhear_range,speaker)) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index cc2c770a7f..7f48ca8bcf 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -159,8 +159,8 @@ Class Procs: del(src) //sets the use_power var and then forces an area power update -/obj/machinery/proc/update_use_power(var/new_use_power) - if (new_use_power == use_power) +/obj/machinery/proc/update_use_power(var/new_use_power, var/force_update = 0) + if ((new_use_power == use_power) && !force_update) return //don't need to do anything use_power = new_use_power diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index ddee1405a4..d4b5f90d68 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -5,28 +5,76 @@ density = 1 anchored = 1.0 use_power = 1 - idle_power_usage = 5 //internal circuitry - active_power_usage = 75000 //75 kW charging station + idle_power_usage = 50 + active_power_usage = 50 var/mob/occupant = null + var/max_internal_charge = 15000 // Two charged borgs in a row with default cell + var/current_internal_charge = 15000 // Starts charged, to prevent power surges on round start + var/charging_cap_active = 25000 // Active Cap - When cyborg is inside + var/charging_cap_passive = 2500 // Passive Cap - Recharging internal capacitor when no cyborg is inside + var/icon_update_tick = 0 // Used to update icon only once every 10 ticks New() ..() build_icon() + update_icon() process() - if(!(NOPOWER|BROKEN)) + if(stat & (BROKEN)) return + if((stat & (NOPOWER)) && !current_internal_charge) // No Power. + return + + var/chargemode = 0 if(src.occupant) process_occupant() + chargemode = 1 + // Power Stuff + + if(stat & NOPOWER) + current_internal_charge = max(0, (current_internal_charge - (50 * CELLRATE))) // Internal Circuitry, 50W load. No power - Runs from internal cell + return // No external power = No charging + + + + if(max_internal_charge < current_internal_charge) + current_internal_charge = max_internal_charge// Safety check if varedit adminbus or something screws up + // Calculating amount of power to draw + var/charge_diff = max_internal_charge - current_internal_charge // OK we have charge differences + charge_diff = charge_diff / CELLRATE // Deconvert from Charge to Joules + if(chargemode) // Decide if use passive or active power + charge_diff = between(0, charge_diff, charging_cap_active) // Trim the values to limits + else // We should have load for this tick in Watts + charge_diff = between(0, charge_diff, charging_cap_passive) + + charge_diff += 50 // 50W for circuitry + + if(idle_power_usage != charge_diff) // Force update, but only when our power usage changed this tick. + idle_power_usage = charge_diff + update_use_power(1,1) + + current_internal_charge = min((current_internal_charge + ((charge_diff - 50) * CELLRATE)), max_internal_charge) + + if(icon_update_tick >= 10) + update_icon() + icon_update_tick = 0 + else + icon_update_tick++ + return 1 allow_drop() return 0 + examine() + usr << "The charge meter reads: [round(chargepercentage())]%" + + proc/chargepercentage() + return ((current_internal_charge / max_internal_charge) * 100) relaymove(mob/user as mob) if(user.stat) @@ -43,6 +91,23 @@ go_out() ..(severity) + update_icon() + ..() + overlays.Cut() + switch(round(chargepercentage())) + if(1 to 20) + overlays += image('icons/obj/objects.dmi', "statn_c0") + if(21 to 40) + overlays += image('icons/obj/objects.dmi', "statn_c20") + if(41 to 60) + overlays += image('icons/obj/objects.dmi', "statn_c40") + if(61 to 80) + overlays += image('icons/obj/objects.dmi', "statn_c60") + if(81 to 98) + overlays += image('icons/obj/objects.dmi', "statn_c80") + if(99 to 110) + overlays += image('icons/obj/objects.dmi', "statn_c100") + proc build_icon() if(NOPOWER|BROKEN) @@ -62,7 +127,10 @@ if(!R.cell) return if(!R.cell.fully_charged()) - R.cell.give(active_power_usage*CELLRATE) + var/diff = min(R.cell.maxcharge - R.cell.charge, 250) // Capped at 250 charge / tick + diff = min(diff, current_internal_charge) // No over-discharging + R.cell.give(diff) + current_internal_charge -= diff else update_use_power(1) go_out() @@ -116,5 +184,5 @@ O.loc = src.loc*/ src.add_fingerprint(usr) build_icon() - update_use_power(2) + update_use_power(1) return \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 5a927e38ab..843ce25b29 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -682,9 +682,12 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use //Giving borgs their own radio to have some more room to work with -Sieve /obj/item/device/radio/borg + var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks var/obj/item/device/encryptionkey/keyslot = null//Borg radios can handle a single encryption key + var/shut_up = 0 icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. icon_state = "radio" + canhear_range = 3 /obj/item/device/radio/borg/attackby(obj/item/weapon/W as obj, mob/user as mob) // ..() @@ -774,6 +777,13 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use channels = list() else recalculateChannels() + if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. + shut_up = !shut_up + if(shut_up) + canhear_range = 0 + else + canhear_range = 3 + ..() /obj/item/device/radio/borg/interact(mob/user as mob) @@ -790,6 +800,7 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use + +
Toggle Broadcast Mode
+ Toggle Loudspeaker
"} if(!subspace_transmission)//Don't even bother if subspace isn't turned on diff --git a/code/modules/mob/living/silicon/robot/analyzer.dm b/code/modules/mob/living/silicon/robot/analyzer.dm new file mode 100644 index 0000000000..98d7da00ea --- /dev/null +++ b/code/modules/mob/living/silicon/robot/analyzer.dm @@ -0,0 +1,79 @@ +// +//Robotic Component Analyser, basically a health analyser for robots +// +/obj/item/device/robotanalyzer + name = "cyborg analyzer" + icon_state = "robotanalyzer" + item_state = "analyzer" + desc = "A hand-held scanner able to diagnose robotic injuries." + flags = FPRINT | TABLEPASS | CONDUCT + slot_flags = SLOT_BELT + throwforce = 3 + w_class = 2.0 + throw_speed = 5 + throw_range = 10 + matter = list("metal" = 200) + origin_tech = "magnets=1;biotech=1" + var/mode = 1; + +/obj/item/device/robotanalyzer/attack(mob/living/M as mob, mob/living/user as mob) + if(( (CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) + user << text("\red You try to analyze the floor's vitals!") + for(var/mob/O in viewers(M, null)) + O.show_message(text("\red [user] has analyzed the floor's vitals!"), 1) + user.show_message(text("\blue Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) + user.show_message(text("\blue \t Damage Specifics: [0]-[0]-[0]-[0]"), 1) + user.show_message("\blue Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message("\blue Body Temperature: ???", 1) + return + if(!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") + user << "\red You don't have the dexterity to do this!" + return + if(!istype(M, /mob/living/silicon/robot) && !(ishuman(M) && (M:species.flags & IS_SYNTHETIC))) + user << "\red You can't analyze non-robotic things!" + return + + user.visible_message(" [user] has analyzed [M]'s components."," You have analyzed [M]'s components.") + var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() + var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() + user.show_message("\blue Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.halloss]% functional"]") + user.show_message("\t Key: Electronics/Brute", 1) + user.show_message("\t Damage Specifics: [BU] - [BR]") + if(M.tod && M.stat == DEAD) + user.show_message("\blue Time of Disable: [M.tod]") + + if (istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/H = M + var/list/damaged = H.get_damaged_components(1,1,1) + user.show_message("\blue Localized Damage:",1) + if(length(damaged)>0) + for(var/datum/robot_component/org in damaged) + user.show_message(text("\blue \t []: [][] - [] - [] - []", \ + capitalize(org.name), \ + (org.installed == -1) ? "DESTROYED " :"",\ + (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ + (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ + (org.toggled) ? "Toggled ON" : "Toggled OFF",\ + (org.powered) ? "Power ON" : "Power OFF"),1) + else + user.show_message("\blue \t Components are OK.",1) + if(H.emagged && prob(5)) + user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1) + + if (ishuman(M) && (M:species.flags & IS_SYNTHETIC)) + var/mob/living/carbon/human/H = M + var/list/damaged = H.get_damaged_organs(1,1) + user.show_message("\blue Localized Damage, Brute/Electronics:",1) + if(length(damaged)>0) + for(var/datum/organ/external/org in damaged) + user.show_message(text("\blue \t []: [] - []", \ + capitalize(org.display_name), \ + (org.brute_dam > 0) ? "\red [org.brute_dam]" :0, \ + (org.burn_dam > 0) ? "[org.burn_dam]" :0),1) + else + user.show_message("\blue \t Components are OK.",1) + + user.show_message("\blue Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) + + src.add_fingerprint(user) + return diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 774f5dc420..b3f0ac7837 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -6,8 +6,9 @@ /datum/robot_component/var/toggled = 1 /datum/robot_component/var/brute_damage = 0 /datum/robot_component/var/electronics_damage = 0 -/datum/robot_component/var/energy_consumption = 0 -/datum/robot_component/var/max_damage = 30 +/datum/robot_component/var/idle_usage = 0 // Amount of power used every MC tick. In joules. +/datum/robot_component/var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc. +/datum/robot_component/var/max_damage = 30 // HP of this component. /datum/robot_component/var/mob/living/silicon/robot/owner // The actual device object that has to be installed for this. @@ -55,34 +56,47 @@ electronics_damage = max(0, electronics_damage - electronics) /datum/robot_component/proc/is_powered() - return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (!energy_consumption || powered) + return (installed == 1) && (brute_damage + electronics_damage < max_damage) && (!idle_usage || powered) /datum/robot_component/proc/update_power_state() if(toggled == 0) powered = 0 return - if(owner.cell && owner.cell.charge >= energy_consumption) - owner.cell.use(energy_consumption) + if(owner.cell && owner.cell.charge >= idle_usage) + owner.cell_use_power(idle_usage) powered = 1 else powered = 0 + +// ARMOUR +// Protects the cyborg from damage. Usually first module to be hit +// No power usage /datum/robot_component/armour name = "armour plating" - energy_consumption = 0 external_type = /obj/item/robot_parts/robot_component/armour max_damage = 60 + +// ACTUATOR +// Enables movement. +// Uses no power when idle. Uses 200J for each tile the cyborg moves. /datum/robot_component/actuator name = "actuator" - energy_consumption = 2 + idle_usage = 0 + active_usage = 200 external_type = /obj/item/robot_parts/robot_component/actuator max_damage = 50 + //A fixed and much cleaner implementation of /tg/'s special snowflake code. /datum/robot_component/actuator/is_powered() return (installed == 1) && (brute_damage + electronics_damage < max_damage) + +// POWER CELL +// Stores power (how unexpected..) +// No power usage /datum/robot_component/cell name = "power cell" max_damage = 50 @@ -91,33 +105,55 @@ ..() owner.cell = null + +// RADIO +// Enables radio communications +// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message. /datum/robot_component/radio name = "radio" external_type = /obj/item/robot_parts/robot_component/radio - energy_consumption = 1 + active_usage = 10 max_damage = 40 + +// BINARY RADIO +// Enables binary communications with other cyborgs/AIs +// Uses no power when idle. Uses 10J for each received radio message, 50 for each transmitted message /datum/robot_component/binary_communication name = "binary communication device" external_type = /obj/item/robot_parts/robot_component/binary_communication_device - energy_consumption = 0 + active_usage = 10 max_damage = 30 + +// CAMERA +// Enables cyborg vision. Can also be remotely accessed via consoles. +// Uses 10J constantly /datum/robot_component/camera name = "camera" external_type = /obj/item/robot_parts/robot_component/camera - energy_consumption = 1 + idle_usage = 10 max_damage = 40 + +// SELF DIAGNOSIS MODULE +// Analyses cyborg's modules, providing damage readouts and basic information +// Uses 1kJ burst when analysis is done /datum/robot_component/diagnosis_unit name = "self-diagnosis unit" - energy_consumption = 1 + active_usage = 1000 external_type = /obj/item/robot_parts/robot_component/diagnosis_unit max_damage = 30 -/mob/living/silicon/robot/proc/initialize_components() - // This only initializes the components, it doesn't set them to installed. + + +// HELPER STUFF + + + +// Initializes cyborg's components. Technically, adds default set of components to new borgs +/mob/living/silicon/robot/proc/initialize_components() components["actuator"] = new/datum/robot_component/actuator(src) components["radio"] = new/datum/robot_component/radio(src) components["power cell"] = new/datum/robot_component/cell(src) @@ -126,10 +162,25 @@ components["comms"] = new/datum/robot_component/binary_communication(src) components["armour"] = new/datum/robot_component/armour(src) +// Checks if component is functioning /mob/living/silicon/robot/proc/is_component_functioning(module_name) var/datum/robot_component/C = components[module_name] return C && C.installed == 1 && C.toggled && C.is_powered() +// Returns component by it's string name +/mob/living/silicon/robot/proc/get_component(var/component_name) + var/datum/robot_component/C = components[component_name] + return C + + + +// COMPONENT OBJECTS + + + +// Component Objects +// These objects are visual representation of modules + /obj/item/broken_device name = "broken component" icon = 'icons/obj/robot_component.dmi' @@ -144,7 +195,6 @@ var/burn = 0 var/icon_state_broken = "broken" -// TODO: actual icons ;) /obj/item/robot_parts/robot_component/binary_communication_device name = "binary communication device" icon_state = "binradio" @@ -173,84 +223,4 @@ /obj/item/robot_parts/robot_component/radio name = "radio" icon_state = "radio" - icon_state_broken = "radio_broken" - -// -//Robotic Component Analyser, basically a health analyser for robots -// -/obj/item/device/robotanalyzer - name = "cyborg analyzer" - icon_state = "robotanalyzer" - item_state = "analyzer" - desc = "A hand-held scanner able to diagnose robotic injuries." - flags = FPRINT | TABLEPASS | CONDUCT - slot_flags = SLOT_BELT - throwforce = 3 - w_class = 2.0 - throw_speed = 5 - throw_range = 10 - matter = list("metal" = 200) - origin_tech = "magnets=1;biotech=1" - var/mode = 1; - -/obj/item/device/robotanalyzer/attack(mob/living/M as mob, mob/living/user as mob) - if(( (CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) - user << text("\red You try to analyze the floor's vitals!") - for(var/mob/O in viewers(M, null)) - O.show_message(text("\red [user] has analyzed the floor's vitals!"), 1) - user.show_message(text("\blue Analyzing Results for The floor:\n\t Overall Status: Healthy"), 1) - user.show_message(text("\blue \t Damage Specifics: [0]-[0]-[0]-[0]"), 1) - user.show_message("\blue Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\blue Body Temperature: ???", 1) - return - if(!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - user << "\red You don't have the dexterity to do this!" - return - if(!istype(M, /mob/living/silicon/robot) && !(ishuman(M) && (M:species.flags & IS_SYNTHETIC))) - user << "\red You can't analyze non-robotic things!" - return - - user.visible_message(" [user] has analyzed [M]'s components."," You have analyzed [M]'s components.") - var/BU = M.getFireLoss() > 50 ? "[M.getFireLoss()]" : M.getFireLoss() - var/BR = M.getBruteLoss() > 50 ? "[M.getBruteLoss()]" : M.getBruteLoss() - user.show_message("\blue Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.halloss]% functional"]") - user.show_message("\t Key: Electronics/Brute", 1) - user.show_message("\t Damage Specifics: [BU] - [BR]") - if(M.tod && M.stat == DEAD) - user.show_message("\blue Time of Disable: [M.tod]") - - if (istype(M, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/H = M - var/list/damaged = H.get_damaged_components(1,1,1) - user.show_message("\blue Localized Damage:",1) - if(length(damaged)>0) - for(var/datum/robot_component/org in damaged) - user.show_message(text("\blue \t []: [][] - [] - [] - []", \ - capitalize(org.name), \ - (org.installed == -1) ? "DESTROYED " :"",\ - (org.electronics_damage > 0) ? "[org.electronics_damage]" :0, \ - (org.brute_damage > 0) ? "[org.brute_damage]" :0, \ - (org.toggled) ? "Toggled ON" : "Toggled OFF",\ - (org.powered) ? "Power ON" : "Power OFF"),1) - else - user.show_message("\blue \t Components are OK.",1) - if(H.emagged && prob(5)) - user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1) - - if (ishuman(M) && (M:species.flags & IS_SYNTHETIC)) - var/mob/living/carbon/human/H = M - var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("\blue Localized Damage, Brute/Electronics:",1) - if(length(damaged)>0) - for(var/datum/organ/external/org in damaged) - user.show_message(text("\blue \t []: [] - []", \ - capitalize(org.display_name), \ - (org.brute_dam > 0) ? "\red [org.brute_dam]" :0, \ - (org.burn_dam > 0) ? "[org.burn_dam]" :0),1) - else - user.show_message("\blue \t Components are OK.",1) - - user.show_message("\blue Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1) - - src.add_fingerprint(user) - return + icon_state_broken = "radio_broken" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 1b547df49c..58ad85e2a0 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -32,25 +32,32 @@ adjustFireLoss(0) /mob/living/silicon/robot/proc/use_power() - + // Debug only + // world << "DEBUG: life.dm line 35: cyborg use_power() called at tick [controller_iteration]" + used_power_this_tick = 0 for(var/V in components) var/datum/robot_component/C = components[V] C.update_power_state() if ( cell && is_component_functioning("power cell") && src.cell.charge > 0 ) if(src.module_state_1) - src.cell.use(3) + cell_use_power(50) // 50W load for every enabled tool TODO: tool-specific loads if(src.module_state_2) - src.cell.use(3) + cell_use_power(50) if(src.module_state_3) - src.cell.use(3) + cell_use_power(50) + + if(lights_on) + cell_use_power(30) // 30W light. Normal lights would use ~15W, but increased for balance reasons. src.has_power = 1 else if (src.has_power) src << "\red You are now running on emergency backup power." src.has_power = 0 - + if(lights_on) // Light is on but there is no power! + lights_on = 0 + SetLuminosity(0) /mob/living/silicon/robot/proc/handle_regular_status_updates() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 254e541117..da1a15dcc1 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -2,6 +2,8 @@ var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/sensor_mode ) +#define CYBORG_POWER_USAGE_MULTIPLIER 2.5 // Multiplier for amount of power cyborgs use. + /mob/living/silicon/robot name = "Cyborg" real_name = "Cyborg" @@ -10,6 +12,8 @@ var/list/robot_verbs_default = list( maxHealth = 200 health = 200 + var/lights_on = 0 // Is our integrated light on? + var/used_power_this_tick = 0 var/sight_mode = 0 var/custom_name = "" var/custom_sprite = 0 //Due to all the sprites involved, a var for our custom borgs may be best @@ -384,10 +388,20 @@ var/list/robot_verbs_default = list( var/dat = "[src.name] Self-Diagnosis Report\n" for (var/V in components) var/datum/robot_component/C = components[V] - dat += "[C.name]
Power consumption[C.energy_consumption]
Brute Damage:[C.brute_damage]
Electronics Damage:[C.electronics_damage]
Powered:[(!C.energy_consumption || C.is_powered()) ? "Yes" : "No"]
Toggled:[ C.toggled ? "Yes" : "No"]

" + dat += "[C.name]
Brute Damage:[C.brute_damage]
Electronics Damage:[C.electronics_damage]
Powered:[(!C.idle_usage || C.is_powered()) ? "Yes" : "No"]
Toggled:[ C.toggled ? "Yes" : "No"]

" return dat +/mob/living/silicon/robot/verb/toggle_lights() + set category = "Robot Commands" + set name = "Toggle Lights" + + lights_on = !lights_on + usr << "You [lights_on ? "enable" : "disable"] your integrated light." + if(lights_on) + SetLuminosity(6) // 1.5x luminosity of flashlight + else + SetLuminosity(0) /mob/living/silicon/robot/verb/self_diagnosis_verb() set category = "Robot Commands" @@ -396,6 +410,9 @@ var/list/robot_verbs_default = list( if(!is_component_functioning("diagnosis unit")) src << "\red Your self-diagnosis component isn't functioning." + var/datum/robot_component/CO = get_component("diagnosis unit") + if (!cell_use_power(CO.active_usage)) + src << "\red Low Power." var/dat = self_diagnosis() src << browse(dat, "window=robotdiagnosis") @@ -465,7 +482,9 @@ var/list/robot_verbs_default = list( // this function displays the cyborgs current cell charge in the stat panel /mob/living/silicon/robot/proc/show_cell_power() if(cell) - stat(null, text("Charge Left: [cell.charge]/[cell.maxcharge]")) + stat(null, text("Charge Left: [round(cell.percent())]%")) + stat(null, text("Cell Rating: [round(cell.maxcharge)]")) // Round just in case we somehow get crazy values + stat(null, text("Power Cell Load: [round(used_power_this_tick)]W")) else stat(null, text("No Cell Inserted!")) @@ -477,6 +496,7 @@ var/list/robot_verbs_default = list( if (client.statpanel == "Status") show_cell_power() show_jetpack_pressure() + stat(null, text("Lights: [lights_on ? "ON" : "OFF"]")) /mob/living/silicon/robot/restrained() return 0 @@ -1331,3 +1351,20 @@ var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/remove_robot_verbs() src.verbs -= robot_verbs_default + + +// Uses power from cyborg's cell. Returns 1 on success or 0 on failure. +// Properly converts using CELLRATE now! Amount is in Joules. +/mob/living/silicon/robot/proc/cell_use_power(var/amount = 0) + // No cell inserted + if(!cell) + return 0 + + // Power cell is empty. + if(cell.charge == 0) + return 0 + + if(cell.use(amount * CELLRATE * CYBORG_POWER_USAGE_MULTIPLIER)) + used_power_this_tick += amount * CYBORG_POWER_USAGE_MULTIPLIER + return 1 + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index dda6212715..eeb6ed03b5 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -22,7 +22,7 @@ New() - src.modules += new /obj/item/device/flashlight(src) +// src.modules += new /obj/item/device/flashlight(src) // Replaced by verb and integrated light which uses power. src.modules += new /obj/item/device/flash(src) src.emag = new /obj/item/toy/sword(src) src.emag.name = "Placeholder Emag Item" diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index c3b7d43c05..8cf0eae0c0 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -22,5 +22,11 @@ return tally+config.robot_delay +// NEW: Use power while moving. /mob/living/silicon/robot/Move() - ..() \ No newline at end of file + if (!is_component_functioning("actuator")) + return + + var/datum/robot_component/actuator/A = get_component("actuator") + if (cell_use_power(A.active_usage)) + ..() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 0b971cfab1..c979eec0dc 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -72,7 +72,11 @@ if(message_mode && bot_type == IS_ROBOT && message_mode != "binary" && !R.is_component_functioning("radio")) src << "\red Your radio isn't functional at this time." return - + if(bot_type == IS_ROBOT && message_mode != "binary") + var/datum/robot_component/radio/RA = R.get_component("radio") + if (!R.cell_use_power(RA.active_usage)) + usr << "\red Not enough power to transmit message." + return //parse language key and consume it var/datum/language/speaking = parse_language(message) @@ -100,6 +104,10 @@ if(!R.is_component_functioning("comms")) src << "\red Your binary communications component isn't functional." return + var/datum/robot_component/binary_communication/B = R.get_component("comms") + if(!R.cell_use_power(B.active_usage)) + src << "\red Not enough power to transmit message." + return if(IS_PAI) src << "You do not appear to have that function" return @@ -197,6 +205,11 @@ var/renderedAI = "Robotic Talk, [name] [verb], \"[message]\"" S.show_message(renderedAI, 2) else + var/mob/living/silicon/robot/borg = S + if(istype(borg) && borg.is_component_functioning("comms")) + var/datum/robot_component/RC = borg.get_component("comms") + if(!borg.use_power(RC.active_usage)) + continue // No power. S.show_message(rendered, 2) diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index c40f96c62e..e6b49ec298 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -67,6 +67,7 @@ if(!autocalled) log_power_update_request(A.master, src) A.master.powerupdate = 2 // Decremented by 2 each GC tick, since it's not auto power change we're going to update power twice. + return 1 //The master_area optional argument can be used to save on a lot of processing if the master area is already known. This is mainly intended for when this proc is called by the master controller. /obj/machinery/proc/power_change(var/area/master_area = null) // called whenever the power settings of the containing area change diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index 82d2dee3bd..e50759742c 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ