mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-30 20:13:53 +00:00
Merge pull request #3126 from CIB/bleeding-edge-freeze
Implemented robot components(organs)
This commit is contained in:
145
code/modules/mob/living/silicon/robot/component.dm
Normal file
145
code/modules/mob/living/silicon/robot/component.dm
Normal file
@@ -0,0 +1,145 @@
|
||||
// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system
|
||||
|
||||
/datum/robot_component/var/name
|
||||
/datum/robot_component/var/installed = 0
|
||||
/datum/robot_component/var/powered = 0
|
||||
/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/mob/living/silicon/robot/owner
|
||||
|
||||
// The actual device object that has to be installed for this.
|
||||
/datum/robot_component/var/external_type = null
|
||||
|
||||
// The wrapped device(e.g. radio), only set if external_type isn't null
|
||||
/datum/robot_component/var/obj/item/wrapped = null
|
||||
|
||||
/datum/robot_component/New(mob/living/silicon/robot/R)
|
||||
src.owner = R
|
||||
|
||||
/datum/robot_component/proc/install()
|
||||
/datum/robot_component/proc/uninstall()
|
||||
|
||||
/datum/robot_component/proc/destroy()
|
||||
if(wrapped)
|
||||
del wrapped
|
||||
|
||||
|
||||
wrapped = new/obj/item/broken_device
|
||||
|
||||
// The thing itself isn't there anymore, but some fried remains are.
|
||||
installed = -1
|
||||
uninstall()
|
||||
|
||||
/datum/robot_component/proc/take_damage(brute, electronics, sharp)
|
||||
if(installed != 1) return
|
||||
|
||||
brute_damage += brute
|
||||
electronics_damage += electronics
|
||||
|
||||
if(brute_damage + electronics_damage > max_damage) destroy()
|
||||
|
||||
/datum/robot_component/proc/heal_damage(brute, electronics)
|
||||
if(installed != 1)
|
||||
// If it's not installed, can't repair it.
|
||||
return 0
|
||||
|
||||
brute_damage = max(0, brute_damage - brute)
|
||||
electronics_damage = max(0, electronics_damage - electronics)
|
||||
|
||||
/datum/robot_component/proc/is_powered()
|
||||
return installed == 1 && (!energy_consumption || powered)
|
||||
|
||||
|
||||
/datum/robot_component/proc/consume_power()
|
||||
if(toggled == 0)
|
||||
powered = 0
|
||||
return
|
||||
if(owner.cell.charge >= energy_consumption)
|
||||
owner.cell.use(energy_consumption)
|
||||
powered = 1
|
||||
else
|
||||
powered = 0
|
||||
|
||||
|
||||
/datum/robot_component/actuator
|
||||
name = "actuator"
|
||||
energy_consumption = 2
|
||||
external_type = /obj/item/robot_parts/robot_component/actuator
|
||||
max_damage = 60
|
||||
|
||||
/datum/robot_component/cell
|
||||
name = "power cell"
|
||||
max_damage = 60
|
||||
|
||||
/datum/robot_component/cell/destroy()
|
||||
..()
|
||||
owner.cell = null
|
||||
|
||||
/datum/robot_component/radio
|
||||
name = "radio"
|
||||
external_type = /obj/item/robot_parts/robot_component/radio
|
||||
energy_consumption = 3
|
||||
max_damage = 10
|
||||
|
||||
/datum/robot_component/binary_communication
|
||||
name = "binary communication device"
|
||||
external_type = /obj/item/robot_parts/robot_component/binary_communication_device
|
||||
energy_consumption = 0
|
||||
max_damage = 30
|
||||
|
||||
/datum/robot_component/camera
|
||||
name = "camera"
|
||||
external_type = /obj/item/robot_parts/robot_component/camera
|
||||
energy_consumption = 2
|
||||
max_damage = 20
|
||||
|
||||
/datum/robot_component/diagnosis_unit
|
||||
name = "self-diagnosis unit"
|
||||
energy_consumption = 1
|
||||
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.
|
||||
|
||||
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)
|
||||
components["diagnosis unit"] = new/datum/robot_component/diagnosis_unit(src)
|
||||
components["camera"] = new/datum/robot_component/camera(src)
|
||||
components["comms"] = new/datum/robot_component/binary_communication(src)
|
||||
|
||||
/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()
|
||||
|
||||
/obj/item/broken_device
|
||||
name = "broken component"
|
||||
icon = 'robot_component.dmi'
|
||||
icon_state = "broken"
|
||||
|
||||
/obj/item/robot_parts/robot_component
|
||||
icon = 'robot_component.dmi'
|
||||
icon_state = "working"
|
||||
construction_time = 200
|
||||
construction_cost = list("metal"=5000)
|
||||
|
||||
|
||||
// TODO: actual icons ;)
|
||||
/obj/item/robot_parts/robot_component/binary_communication_device
|
||||
name = "binary communication device"
|
||||
|
||||
/obj/item/robot_parts/robot_component/actuator
|
||||
name = "actuator"
|
||||
|
||||
/obj/item/robot_parts/robot_component/camera
|
||||
name = "camera"
|
||||
|
||||
/obj/item/robot_parts/robot_component/diagnosis_unit
|
||||
name = "diagnosis unit"
|
||||
|
||||
/obj/item/robot_parts/robot_component/radio
|
||||
name = "radio"
|
||||
@@ -37,23 +37,25 @@
|
||||
|
||||
/mob/living/silicon/robot/proc/use_power()
|
||||
|
||||
if (src.cell)
|
||||
if (is_component_functioning("power cell"))
|
||||
if(src.cell.charge <= 0)
|
||||
uneq_all()
|
||||
src.stat = 1
|
||||
else if (src.cell.charge <= 100)
|
||||
uneq_all()
|
||||
src.sight_mode = 0
|
||||
src.cell.use(1)
|
||||
else
|
||||
if(src.module_state_1)
|
||||
src.cell.use(5)
|
||||
src.cell.use(3)
|
||||
if(src.module_state_2)
|
||||
src.cell.use(5)
|
||||
src.cell.use(3)
|
||||
if(src.module_state_3)
|
||||
src.cell.use(5)
|
||||
src.cell.use(1)
|
||||
src.blinded = 0
|
||||
src.cell.use(3)
|
||||
|
||||
for(var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
C.consume_power()
|
||||
|
||||
if(!is_component_functioning("actuator"))
|
||||
Paralyse(3)
|
||||
|
||||
src.stat = 0
|
||||
else
|
||||
uneq_all()
|
||||
@@ -128,6 +130,17 @@
|
||||
src.druggy--
|
||||
src.druggy = max(0, src.druggy)
|
||||
|
||||
if(!is_component_functioning("radio"))
|
||||
radio.on = 0
|
||||
else
|
||||
radio.on = 1
|
||||
|
||||
if(is_component_functioning("camera"))
|
||||
src.blinded = 0
|
||||
else
|
||||
src.blinded = 1
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/robot/proc/handle_regular_hud_updates()
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
var/obj/item/weapon/cell/cell = null
|
||||
var/obj/machinery/camera/camera = null
|
||||
|
||||
// Components are basically robot organs.
|
||||
var/list/components = list()
|
||||
|
||||
var/obj/item/device/mmi/mmi = null
|
||||
|
||||
var/obj/item/device/pda/ai/rbPDA = null
|
||||
@@ -58,7 +61,7 @@
|
||||
var/braintype = "Cyborg"
|
||||
var/pose
|
||||
|
||||
/mob/living/silicon/robot/New(loc,var/syndie = 0)
|
||||
/mob/living/silicon/robot/New(loc,var/syndie = 0,var/unfinished = 0)
|
||||
spark_system = new /datum/effect/effect/system/spark_spread()
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
@@ -67,12 +70,10 @@
|
||||
updatename("Default")
|
||||
updateicon()
|
||||
|
||||
if(!cell)
|
||||
cell = new /obj/item/weapon/cell(src)
|
||||
cell.maxcharge = 7500
|
||||
cell.charge = 7500
|
||||
|
||||
if(syndie)
|
||||
if(!cell)
|
||||
cell = new /obj/item/weapon/cell(src)
|
||||
|
||||
laws = new /datum/ai_laws/antimov()
|
||||
lawupdate = 0
|
||||
scrambledcodes = 1
|
||||
@@ -99,6 +100,25 @@
|
||||
camera.network = list("SS13")
|
||||
if(isWireCut(5)) // 5 = BORG CAMERA
|
||||
camera.status = 0
|
||||
|
||||
initialize_components()
|
||||
if(!unfinished)
|
||||
// Create all the robot parts.
|
||||
for(var/V in components) if(V != "power cell")
|
||||
var/datum/robot_component/C = components[V]
|
||||
C.installed = 1
|
||||
C.wrapped = new C.external_type
|
||||
|
||||
if(!cell)
|
||||
cell = new /obj/item/weapon/cell(src)
|
||||
cell.maxcharge = 7500
|
||||
cell.charge = 7500
|
||||
|
||||
if(cell)
|
||||
var/datum/robot_component/cell_component = components["power cell"]
|
||||
cell_component.wrapped = cell
|
||||
cell_component.installed = 1
|
||||
|
||||
..()
|
||||
|
||||
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
|
||||
@@ -381,6 +401,53 @@
|
||||
viewalerts = 1
|
||||
src << browse(dat, "window=robotalerts&can_close=0")
|
||||
|
||||
/mob/living/silicon/robot/proc/self_diagnosis()
|
||||
if(!is_component_functioning("diagnosis unit"))
|
||||
return null
|
||||
|
||||
var/dat = "<HEAD><TITLE>[src.name] Self-Diagnosis Report</TITLE></HEAD><BODY>\n"
|
||||
for (var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
dat += "<b>[C.name]</b><br><table><tr><td>Power consumption</td><td>[C.energy_consumption]</td></tr><tr><td>Brute Damage:</td><td>[C.brute_damage]</td></tr><tr><td>Electronics Damage:</td><td>[C.electronics_damage]</td></tr><tr><td>Powered:</td><td>[(!C.energy_consumption || C.is_powered()) ? "Yes" : "No"]</td></tr><tr><td>Toggled:</td><td>[ C.toggled ? "Yes" : "No"]</td></table><br>"
|
||||
|
||||
return dat
|
||||
|
||||
|
||||
/mob/living/silicon/robot/verb/self_diagnosis_verb()
|
||||
set category = "Robot Commands"
|
||||
set name = "Self Diagnosis"
|
||||
|
||||
if(!is_component_functioning("diagnosis unit"))
|
||||
src << "\red Your self-diagnosis component isn't functioning."
|
||||
|
||||
var/dat = self_diagnosis()
|
||||
src << browse(dat, "window=robotdiagnosis")
|
||||
|
||||
|
||||
/mob/living/silicon/robot/verb/toggle_component()
|
||||
set category = "Robot Commands"
|
||||
set name = "Toggle Component"
|
||||
set desc = "Toggle a component, conserving power."
|
||||
|
||||
var/list/installed_components = list()
|
||||
for(var/V in components)
|
||||
if(V == "power cell") continue
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(C.installed)
|
||||
installed_components += V
|
||||
|
||||
var/toggle = input(src, "Which component do you want to toggle?", "Toggle Component") as null|anything in installed_components
|
||||
if(!toggle)
|
||||
return
|
||||
|
||||
var/datum/robot_component/C = components[toggle]
|
||||
if(C.toggled)
|
||||
C.toggled = 0
|
||||
src << "\red You disable [C.name]."
|
||||
else
|
||||
C.toggled = 1
|
||||
src << "\red You enable [C.name]."
|
||||
|
||||
/mob/living/silicon/robot/blob_act()
|
||||
if (stat != 2)
|
||||
adjustBruteLoss(60)
|
||||
@@ -564,6 +631,20 @@
|
||||
if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
|
||||
return
|
||||
|
||||
if(opened) // Are they trying to insert something?
|
||||
for(var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(!C.installed && istype(W, C.external_type))
|
||||
C.installed = 1
|
||||
C.wrapped = W
|
||||
C.install()
|
||||
user.drop_item()
|
||||
W.loc = null
|
||||
|
||||
usr << "\blue You install the [W.name]."
|
||||
|
||||
return
|
||||
|
||||
if (istype(W, /obj/item/weapon/weldingtool))
|
||||
if (!getBruteLoss())
|
||||
user << "Nothing to fix here!"
|
||||
@@ -609,6 +690,27 @@
|
||||
C.updateicon()
|
||||
new/obj/item/robot_parts/chest(loc)
|
||||
src.Del()
|
||||
else
|
||||
// Okay we're not removing the cell or an MMI, but maybe something else?
|
||||
var/list/removable_components = list()
|
||||
for(var/V in components)
|
||||
if(V == "power cell") continue
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(C.installed == 1)
|
||||
removable_components += V
|
||||
|
||||
var/remove = input(user, "Which component do you want to pry out?", "Remove Component") as null|anything in removable_components
|
||||
if(!remove)
|
||||
return
|
||||
var/datum/robot_component/C = components[remove]
|
||||
var/obj/item/I = C.wrapped
|
||||
user << "You remove \the [I]."
|
||||
I.loc = src.loc
|
||||
|
||||
if(C.installed == 1)
|
||||
C.uninstall()
|
||||
C.installed = 0
|
||||
|
||||
else
|
||||
if(locked)
|
||||
user << "The cover is locked and cannot be opened."
|
||||
@@ -618,17 +720,20 @@
|
||||
updateicon()
|
||||
|
||||
else if (istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside
|
||||
var/datum/robot_component/C = components["power cell"]
|
||||
if(wiresexposed)
|
||||
user << "Close the panel first."
|
||||
else if(cell)
|
||||
else if(cell || C.installed)
|
||||
user << "There is a power cell already installed."
|
||||
else
|
||||
user.drop_item()
|
||||
W.loc = src
|
||||
cell = W
|
||||
user << "You insert the power cell."
|
||||
// chargecount = 0
|
||||
updateicon()
|
||||
|
||||
C.installed = 1
|
||||
C.wrapped = W
|
||||
C.install()
|
||||
|
||||
else if (istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool))
|
||||
if (wiresexposed)
|
||||
@@ -901,6 +1006,7 @@
|
||||
add_fingerprint(user)
|
||||
|
||||
if(opened && !wiresexposed && (!istype(user, /mob/living/silicon)))
|
||||
var/datum/robot_component/cell_component = components["power cell"]
|
||||
if(cell)
|
||||
cell.updateicon()
|
||||
cell.add_fingerprint(user)
|
||||
@@ -908,6 +1014,11 @@
|
||||
user << "You remove \the [cell]."
|
||||
cell = null
|
||||
updateicon()
|
||||
else if(cell_component.installed == -1)
|
||||
cell_component.installed = 0
|
||||
var/obj/item/broken_device = cell_component.wrapped
|
||||
user << "You remove \the [broken_device]."
|
||||
user.put_in_active_hand(broken_device)
|
||||
|
||||
if(ishuman(user))
|
||||
if(istype(user:gloves, /obj/item/clothing/gloves/space_ninja)&&user:gloves:candrain&&!user:gloves:draining)
|
||||
|
||||
83
code/modules/mob/living/silicon/robot/robot_damage.dm
Normal file
83
code/modules/mob/living/silicon/robot/robot_damage.dm
Normal file
@@ -0,0 +1,83 @@
|
||||
/mob/living/silicon/robot/getBruteLoss()
|
||||
var/amount = 0
|
||||
for(var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(C.installed == 1) amount += C.brute_damage
|
||||
return amount
|
||||
|
||||
/mob/living/silicon/robot/getFireLoss()
|
||||
var/amount = 0
|
||||
for(var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(C.installed == 1) amount += C.electronics_damage
|
||||
return amount
|
||||
|
||||
|
||||
/mob/living/silicon/robot/adjustBruteLoss(var/amount)
|
||||
if(amount > 0)
|
||||
take_overall_damage(amount, 0)
|
||||
else
|
||||
heal_overall_damage(-amount, 0)
|
||||
|
||||
/mob/living/silicon/robot/adjustFireLoss(var/amount)
|
||||
if(amount > 0)
|
||||
take_overall_damage(0, amount)
|
||||
else
|
||||
heal_overall_damage(0, -amount)
|
||||
|
||||
/mob/living/silicon/robot/proc/get_damaged_components(var/brute, var/burn)
|
||||
var/list/datum/robot_component/parts = list()
|
||||
for(var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(C.installed == 1) if((brute && C.brute_damage) || (burn && C.electronics_damage))
|
||||
parts += C
|
||||
return parts
|
||||
|
||||
/mob/living/silicon/robot/proc/get_damageable_components()
|
||||
var/list/rval = new
|
||||
for(var/V in components)
|
||||
var/datum/robot_component/C = components[V]
|
||||
if(C.installed == 1) rval += C
|
||||
return rval
|
||||
|
||||
/mob/living/silicon/robot/heal_organ_damage(var/brute, var/burn)
|
||||
var/list/datum/robot_component/parts = get_damaged_components(brute,burn)
|
||||
if(!parts.len) return
|
||||
var/datum/robot_component/picked = pick(parts)
|
||||
picked.heal_damage(brute,burn)
|
||||
|
||||
/mob/living/silicon/robot/take_organ_damage(var/brute, var/burn, var/sharp = 0)
|
||||
var/datum/robot_component/C = pick(get_damageable_components())
|
||||
C.take_damage(brute,burn,sharp)
|
||||
|
||||
/mob/living/silicon/robot/heal_overall_damage(var/brute, var/burn)
|
||||
var/list/datum/robot_component/parts = get_damaged_components(brute,burn)
|
||||
|
||||
while(parts.len && (brute>0 || burn>0) )
|
||||
var/datum/robot_component/picked = pick(parts)
|
||||
|
||||
var/brute_was = picked.brute_damage
|
||||
var/burn_was = picked.electronics_damage
|
||||
|
||||
picked.heal_damage(brute,burn)
|
||||
|
||||
brute -= (brute_was-picked.brute_damage)
|
||||
burn -= (burn_was-picked.electronics_damage)
|
||||
|
||||
parts -= picked
|
||||
|
||||
/mob/living/silicon/robot/take_overall_damage(var/brute, var/burn, var/sharp = 0, var/used_weapon = null)
|
||||
if(status_flags & GODMODE) return //godmode
|
||||
var/list/datum/robot_component/parts = get_damageable_components()
|
||||
while(parts.len && (brute>0 || burn>0) )
|
||||
var/datum/robot_component/picked = pick(parts)
|
||||
|
||||
var/brute_was = picked.brute_damage
|
||||
var/burn_was = picked.electronics_damage
|
||||
|
||||
picked.take_damage(brute,burn)
|
||||
|
||||
brute -= (picked.brute_damage - brute_was)
|
||||
burn -= (picked.electronics_damage - burn_was)
|
||||
|
||||
parts -= picked
|
||||
@@ -24,6 +24,14 @@
|
||||
return ..(message)
|
||||
message = copytext(message, 3)
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
|
||||
// TODO: move the component system up to silicon so we don't have to use this ugly hack..
|
||||
if(istype(src, /mob/living/silicon/robot))
|
||||
var/mob/living/silicon/robot/R = src
|
||||
if(!R.is_component_functioning("comms"))
|
||||
src << "\red Your binary communications component isn't functional."
|
||||
return
|
||||
|
||||
robot_talk(message)
|
||||
else if (department_radio_keys[prefix] == "department")
|
||||
if(isAI(src)&&client)//For patching directly into AI holopads.
|
||||
|
||||
Reference in New Issue
Block a user