Cyborg Damage, Movement, and Power Overhaul (#25252)

* Adding defines

* More signals for external power

* Gets the reboot working

* renaming a proc

* config stuff

* Working on cyborg movement

* Update code/modules/mob/living/silicon/robot/robot_damage.dm

Co-authored-by: CRUNCH <143041327+Fordoxia@users.noreply.github.com>

* Update code/modules/mob/living/silicon/robot/robot_damage.dm

Co-authored-by: CRUNCH <143041327+Fordoxia@users.noreply.github.com>

* Update code/modules/mob/living/silicon/robot/robot_damage.dm

Co-authored-by: CRUNCH <143041327+Fordoxia@users.noreply.github.com>

* IOSYS where'd you come from

* begon return 0

* VTEC caps slowdown

* Adjusting EMPs

* Funny arm is GONE

* Oh yeah regenerating stamina might be a good thing

* Forgot you could uninstall vtec

* icon machine broke

* Cell-less borgs can enter chargers to stay powered

* oh that was almost bad

* Fixes some logic

* its a surprise tool that will help us later

* Adjusting some numbers

* Adds a sound to go along with the text alarm

* dead things can still charge

* Another logic error

* Xenos too

* sorry linter

* fixes CL

* Slightly more slowdown on stam damage

* neurotoxin won't stun

* SOUNDS!

* 3 flashes to stun instead of 4

* Slightly longer stun

* SPEEDING UP BORGS JUST FOR THE TM SINCE CONFIG DONT WORK

* Keep borgs stunned forever

* Power loss is more dangerous

* Adds a stamina hud to borgs

* Cyborgs now heal up properly

* Removes an outdated comment

* Replacing parts works better now

* EMPs disable components for a brief time

* More missed rebalances

* When you forget to remove debug messages

* WHAT

* Cult magic works + borgs can be silenced

* 2 flashes to stun, flashes confuse now

* Update code/game/objects/items/devices/flash.dm

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* Abductors can stun borgs

* Watcher/cyro rays deal stam to brog

* Fixes a rounding error when healing borgs back to full HP

* Fixed span

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* Fixed whitespace

Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* Guard clausify

* Indents a message

* Update code/modules/mob/living/silicon/robot/robot_damage.dm

Co-authored-by: Charlie <69320440+hal9000PR@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* Update code/modules/mob/living/silicon/robot/component.dm

Co-authored-by: Charlie <69320440+hal9000PR@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* Update code/modules/mob/living/silicon/robot/robot_damage.dm

Co-authored-by: Charlie <69320440+hal9000PR@users.noreply.github.com>
Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>

* that's not what stat does

* No more hardcoded speed, don't TM this branch

---------

Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com>
Co-authored-by: CRUNCH <143041327+Fordoxia@users.noreply.github.com>
Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com>
Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
Co-authored-by: Ryan <80364400+Sirryan2002@users.noreply.github.com>
Co-authored-by: Charlie <69320440+hal9000PR@users.noreply.github.com>
This commit is contained in:
BiancaWilkson
2024-07-09 13:44:50 -04:00
committed by GitHub
parent cd88b3de88
commit ec88636e6c
35 changed files with 279 additions and 136 deletions
+1
View File
@@ -20,6 +20,7 @@
#define MAGIC "magic"
#define STUN "stun"
#define STAM_CRIT "stam_crit"
#define WEAKEN "weaken"
#define KNOCKDOWN "knockdown"
#define PARALYZE "paralize"
+4
View File
@@ -495,6 +495,10 @@
#define COMPONENT_NO_ATTACH (1<<0)
///sent from borg recharge stations: (amount, repairs)
#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge"
///sent when a mob enters a borg charger
#define COMSIG_ENTERED_BORGCHARGER "enter_charger"
///sent when a mob exits a borg charger
#define COMSIG_EXITED_BORGCHARGER "exit_charger"
///sent when a mob/login() finishes: (client)
#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login"
///sent from borg mobs to itself, for tools to catch an upcoming destroy() due to safe decon (rather than detonation)
+2
View File
@@ -176,6 +176,8 @@
//Health
mymob.healths = new /atom/movable/screen/healths/robot()
infodisplay += mymob.healths
mymob.staminas = new /atom/movable/screen/healths/stamina()
infodisplay += mymob.staminas
//Installed Module
mymobR.hands = new /atom/movable/screen/robot/module()
@@ -9,7 +9,7 @@
/// Move delay for humanoids
var/human_delay = 1.5
/// Move delay for cyborgs
var/robot_delay = 2.5
var/robot_delay = 1.5
/// Move delay for xenomorphs
var/alien_delay = 1.5
/// Move delay for slimes (xenobio, not slimepeople)
+2 -3
View File
@@ -239,11 +239,10 @@
/datum/status_effect/cult_stun_mark/on_apply()
. = ..()
if(!ishuman(owner))
if(!isliving(owner))
return
overlay = mutable_appearance('icons/effects/cult_effects.dmi', "cult-mark", ABOVE_MOB_LAYER)
var/mob/living/carbon/human/H = owner
H.add_overlay(overlay)
owner.add_overlay(overlay)
/datum/status_effect/cult_stun_mark/on_remove()
owner.cut_overlay(overlay)
+5 -5
View File
@@ -468,20 +468,20 @@
else
to_chat(user, "<span class='cultitalic'>In a brilliant flash of red, [L] falls to the ground!</span>")
L.KnockDown(10 SECONDS)
L.apply_damage(60, STAMINA)
L.apply_status_effect(STATUS_EFFECT_CULT_STUN)
L.flash_eyes(1, TRUE)
L.Silence(6 SECONDS)
if(issilicon(target))
var/mob/living/silicon/S = L
S.emp_act(EMP_HEAVY)
else if(iscarbon(target))
var/mob/living/carbon/C = L
C.Silence(6 SECONDS)
C.KnockDown(10 SECONDS)
C.apply_damage(60, STAMINA)
C.flash_eyes(1, TRUE)
C.Stuttering(16 SECONDS)
C.CultSlur(20 SECONDS)
C.Jitter(16 SECONDS)
to_chat(user, "<span class='boldnotice'>Stun mark applied! Stab them with a dagger, sword or blood spear to stun them fully!</span>")
to_chat(user, "<span class='boldnotice'>Stun mark applied! Stab them with a dagger, sword or blood spear to stun them fully!</span>")
user.do_attack_animation(target)
uses--
..()
@@ -288,9 +288,6 @@ CONTENTS:
if(!isabductor(user))
return
if(isrobot(target))
..()
return
if(!isliving(target))
return
@@ -299,6 +296,10 @@ CONTENTS:
user.do_attack_animation(L)
if(isrobot(L))
L.apply_damage(120, STAMINA) //Force a reboot instantly
return
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
+5 -10
View File
@@ -165,6 +165,7 @@
/obj/machinery/recharge_station/proc/go_out()
if(!occupant)
return
SEND_SIGNAL(occupant, COMSIG_EXITED_BORGCHARGER)
UnregisterSignal(occupant, COMSIG_MOVABLE_MOVED)
occupant.forceMove(loc)
occupant = null
@@ -200,18 +201,11 @@
var/can_accept_user
if(isrobot(target))
var/mob/living/silicon/robot/R = target
if(R.stat == DEAD)
//Whoever had it so that a borg with a dead cell can't enter this thing should be shot. --NEO
return
if(occupant)
to_chat(R, "<span class='warning'>The cell is already occupied!</span>")
return
if(!R.cell)
to_chat(R, "<span class='warning'>Without a power cell, you can't be recharged.</span>")
//Make sure they actually HAVE a cell, now that they can get in while powerless. --NEO
return
can_accept_user = 1
can_accept_user = TRUE
else if(ishuman(target))
var/mob/living/carbon/human/H = target
@@ -224,7 +218,7 @@
if(!ismodcontrol(H.back))
if(!H.get_int_organ(/obj/item/organ/internal/cell))
return
can_accept_user = 1
can_accept_user = TRUE
if(!can_accept_user)
to_chat(user, "<span class='notice'>Only non-organics may enter the recharger!</span>")
@@ -232,6 +226,7 @@
target.stop_pulling()
QDEL_LIST_CONTENTS(target.grabbed_by)
SEND_SIGNAL(target, COMSIG_ENTERED_BORGCHARGER)
target.forceMove(src)
occupant = target
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(go_out))
+9 -10
View File
@@ -28,8 +28,8 @@
/obj/item/flash/proc/clown_check(mob/user)
if(user && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
flash_carbon(user, user, 30 SECONDS, 0)
return 0
return 1
return FALSE
return TRUE
/obj/item/flash/attackby(obj/item/I, mob/user, params)
if(can_overcharge)
@@ -66,7 +66,7 @@
/obj/item/flash/proc/flash_recharge(mob/user)
if(prob(times_used * 2)) //if you use it 5 times in a minute it has a 10% chance to break!
burn_out()
return 0
return FALSE
var/deciseconds_passed = world.time - last_used
for(var/seconds = deciseconds_passed/10, seconds>=10, seconds-=10) //get 1 charge every 10 seconds
@@ -122,20 +122,19 @@
/obj/item/flash/attack(mob/living/M, mob/user)
if(!try_use_flash(user))
return 0
return FALSE
if(iscarbon(M))
flash_carbon(M, user, 10 SECONDS, 1)
if(overcharged)
M.adjust_fire_stacks(6)
M.IgniteMob()
burn_out()
return 1
return TRUE
else if(issilicon(M))
add_attack_logs(user, M, "Flashed with [src]")
if(M.flash_eyes(affect_silicon = 1))
M.Weaken(rand(8 SECONDS, 12 SECONDS))
if(M.flash_eyes(intensity = 1.25, affect_silicon = TRUE)) // 40 * 1.25 = 50 stamina damage
user.visible_message("<span class='disarm'>[user] overloads [M]'s sensors with [src]!</span>", "<span class='danger'>You overload [M]'s sensors with [src]!</span>")
return 1
return TRUE
user.visible_message("<span class='disarm'>[user] fails to blind [M] with [src]!</span>", "<span class='warning'>You fail to blind [M] with [src]!</span>")
/obj/item/flash/afterattack(atom/target, mob/living/user, proximity, params)
@@ -155,7 +154,7 @@
/obj/item/flash/attack_self(mob/living/carbon/user, flag = 0, emp = 0)
if(!try_use_flash(user))
return 0
return FALSE
user.visible_message("<span class='disarm'>[user]'s [name] emits a blinding light!</span>", "<span class='danger'>Your [name] emits a blinding light!</span>")
for(var/mob/living/carbon/M in oviewers(3, null))
flash_carbon(M, user, 6 SECONDS, 0)
@@ -168,7 +167,7 @@
/obj/item/flash/emp_act(severity)
if(!try_use_flash())
return 0
return FALSE
for(var/mob/living/carbon/M in viewers(3, null))
flash_carbon(M, null, 20 SECONDS, 0)
burn_out()
@@ -117,8 +117,7 @@
var/mob/living/silicon/S = target
//20% chance to actually hit the sensors
if(prob(effectchance * diode.rating))
S.flash_eyes(affect_silicon = 1)
S.Weaken(rand(10 SECONDS, 20 SECONDS))
S.flash_eyes(affect_silicon = TRUE)
to_chat(S, "<span class='warning'>Your sensors were overloaded by a laser!</span>")
outmsg = "<span class='notice'>You overload [S] by shining [src] at [S.p_their()] sensors.</span>"
@@ -380,7 +380,8 @@
if(!M.client)
continue
if(issilicon(M))
M.Weaken(10 SECONDS)
var/mob/living/silicon/robot/R = M
R.flash_eyes(3, affect_silicon = TRUE) //Enough stamina damage to instantly force a reboot
else
M.Confused(45 SECONDS)
M.adjustBrainLoss(10)
+4 -5
View File
@@ -5,6 +5,10 @@
icon = 'icons/mob/robot_items.dmi'
var/powerneeded // Percentage of power remaining required to run item
/*
The old, instant-stun borg arm.
Keeping it in for adminabuse but the malf one is /obj/item/melee/baton/borg_stun_arm
*/
/obj/item/borg/stun
name = "electrically-charged arm"
icon_state = "elecarm"
@@ -136,8 +140,3 @@
#undef CYBORG_HUG
#undef CYBORG_SHOCK
#undef CYBORG_CRUSH
/obj/item/borg/overdrive
name = "Overdrive"
icon = 'icons/obj/decals.dmi'
icon_state = "shock"
@@ -296,7 +296,6 @@
var/datum/robot_component/cell_component = O.components["power cell"]
cell_component.install(chest.cell)
chest.cell.forceMove(O)
chest.cell = null
M.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
@@ -253,7 +253,7 @@
/obj/item/borg/upgrade/vtec
name = "robotic VTEC Module"
desc = "Used to activate a cyborg's VTEC systems, increasing their speed."
desc = "Used to activate a cyborg's VTEC systems, allowing them to retain more speed when damaged. Alternatively speeds up slow vehicles."
icon_state = "cyborg_upgrade2"
require_module = TRUE
origin_tech = "engineering=4;materials=5;programming=4"
@@ -264,7 +264,7 @@
to_chat(usr, "<span class='notice'>There's no room for another VTEC unit!</span>")
return
R.speed -= 1 // Gotta go fast.
R.slowdown_cap = 3.5
return TRUE
/***********************/
@@ -316,3 +316,8 @@
/obj/item/melee/baton/cattleprod/baton_stun(mob/living/L, mob/user, skip_cooldown = FALSE, ignore_shield_check = FALSE)
if(sparkler.activate())
return ..()
/obj/item/melee/baton/loaded/borg_stun_arm
name = "electrically-charged arm"
desc = "A piece of scrap metal wired directly to your power cell."
hitcost = 100
@@ -27,8 +27,10 @@
SEND_SOUND(M, sound('sound/effects/clingscream.ogg'))
if(issilicon(M))
var/mob/living/silicon/robot/R = M
R.disable_component("actuator", 7 SECONDS)
SEND_SOUND(M, sound('sound/weapons/flash.ogg'))
M.Weaken(rand(10 SECONDS, 20 SECONDS))
R.flash_eyes(2, affect_silicon = TRUE) //80 Stamina damage
for(var/obj/machinery/light/L in range(4, user))
L.on = TRUE
+3
View File
@@ -605,6 +605,9 @@
if(!message)
return
if(HAS_TRAIT(speaker, TRAIT_MUTE))
return
var/log_message = "(ROBOT) [message]"
log_say(log_message, speaker)
speaker.create_log(SAY_LOG, log_message)
@@ -12,8 +12,8 @@
stam_regen_start_time = world.time + (STAMINA_REGEN_BLOCK_TIME * stamina_regen_block_modifier)
var/prev = stam_paralyzed
stam_paralyzed = TRUE
ADD_TRAIT(src, TRAIT_IMMOBILIZED, "stam_crit") // make defines later
ADD_TRAIT(src, TRAIT_FLOORED, "stam_crit")
ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, "stam_crit")
ADD_TRAIT(src, TRAIT_IMMOBILIZED, STAM_CRIT)
ADD_TRAIT(src, TRAIT_FLOORED, STAM_CRIT)
ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, STAM_CRIT)
if(!prev && getStaminaLoss() < 120) // Puts you a little further into the initial stamcrit, makes stamcrit harder to outright counter with chems.
adjustStaminaLoss(30, FALSE)
@@ -29,9 +29,9 @@
else if(stam_paralyzed)
SEND_SIGNAL(src, COMSIG_CARBON_EXIT_STAMINACRIT)
stam_paralyzed = FALSE
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, "stam_crit") // make defines later
REMOVE_TRAIT(src, TRAIT_FLOORED, "stam_crit")
REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, "stam_crit")
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, STAM_CRIT)
REMOVE_TRAIT(src, TRAIT_FLOORED, STAM_CRIT)
REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, STAM_CRIT)
/mob/living/carbon/can_hear()
. = FALSE
+1 -1
View File
@@ -86,7 +86,7 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
S.message = cultslur(S.message)
verb = "slurs"
if(!IsVocal())
if(!IsVocal() || HAS_TRAIT(src, TRAIT_MUTE))
S.message = ""
return list("verb" = verb)
+2 -6
View File
@@ -680,12 +680,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
/mob/living/silicon/ai/emp_act(severity)
..()
if(prob(30))
switch(pick(1,2))
if(1)
view_core()
if(2)
ai_call_shuttle()
Stun((12 SECONDS) / severity)
view_core()
/mob/living/silicon/ai/ex_act(severity)
..()
@@ -8,13 +8,21 @@
var/brute_damage = 0
var/electronics_damage = 0
var/max_damage = 30
var/component_disabled = 0
var/component_disabled = FALSE
var/mob/living/silicon/robot/owner
var/external_type = null // The actual device object that has to be installed for this.
var/obj/item/wrapped = null // The wrapped device(e.g. radio), only set if external_type isn't null
///How much a component is contributing to slowdown, set on New to be equal to min_slowdown_factor
var/current_slowdown_factor
///The max amount of slowness a component can contribute, set on New to be 1% of the max damage
var/max_slowdown_factor
///The minimum amount of speed modification a component can contribute. Currently just 0 for all.
var/min_slowdown_factor = 0
/datum/robot_component/New(mob/living/silicon/robot/R)
owner = R
max_slowdown_factor = (max_damage / 100)
current_slowdown_factor = min_slowdown_factor
// Should only ever be destroyed when a borg gets destroyed
/datum/robot_component/Destroy(force, ...)
@@ -25,6 +33,8 @@
/datum/robot_component/proc/install(obj/item/I, update_health = TRUE)
wrapped = I
installed = TRUE
I.forceMove(owner)
current_slowdown_factor = (brute_damage + electronics_damage) / 100
go_online()
if(update_health)
owner.updatehealth("component '[src]' installed")
@@ -35,7 +45,7 @@
go_offline()
owner.updatehealth("component '[src]' removed")
/datum/robot_component/proc/destroy()
/datum/robot_component/proc/break_component()
if(wrapped)
qdel(wrapped)
uninstall()
@@ -50,9 +60,9 @@
brute_damage += brute
electronics_damage += electronics
current_slowdown_factor = clamp((current_slowdown_factor + ((brute + electronics) / 100)), min_slowdown_factor, max_slowdown_factor)
if(brute_damage + electronics_damage >= max_damage)
destroy()
break_component()
SStgui.update_uis(owner.self_diagnosis)
@@ -63,12 +73,19 @@
if(owner && updating_health)
owner.updatehealth("component '[src]' heal damage")
brute_damage = max(0, brute_damage - brute)
electronics_damage = max(0, electronics_damage - electronics)
var/burn_damage_healed = clamp(electronics, 0, electronics_damage)
var/brute_damage_healed = clamp(brute, 0, brute_damage)
current_slowdown_factor = clamp((current_slowdown_factor - ((burn_damage_healed + brute_damage_healed) / 100)), min_slowdown_factor, max_slowdown_factor)
rounding_error_check()
brute_damage -= brute_damage_healed
electronics_damage -= burn_damage_healed
SStgui.update_uis(owner.self_diagnosis)
///There tends to be some desync between slowdown and damage when being healed up slowly like through self-repair or upgraded rechargers.
/datum/robot_component/proc/rounding_error_check()
if(current_slowdown_factor < (min_slowdown_factor) + 0.0001) //Within .0001 of the minimum, just set it to the minimum
current_slowdown_factor = min_slowdown_factor
/datum/robot_component/proc/is_powered()
return installed && (brute_damage + electronics_damage < max_damage) && (powered)
@@ -90,12 +107,12 @@
/datum/robot_component/proc/disable()
if(!component_disabled)
go_offline()
component_disabled++
component_disabled = TRUE
/datum/robot_component/proc/enable()
component_disabled--
if(!component_disabled)
if(component_disabled)
go_online()
component_disabled = FALSE
/datum/robot_component/proc/toggle()
toggled = !toggled
@@ -112,6 +129,13 @@
/datum/robot_component/proc/go_offline()
return
/datum/robot_component/proc/get_movement_delay()
if(is_missing())
return 0
if(is_destroyed())
return max_slowdown_factor
return current_slowdown_factor
/datum/robot_component/armour
name = "armour plating"
external_type = /obj/item/robot_parts/robot_component/armour
@@ -136,16 +160,19 @@
owner.cell = null
/datum/robot_component/cell/is_powered()
return ..() && owner.cell
return ..() && owner.cell?.charge
/datum/robot_component/cell/Destroy(force, ...)
owner.cell = null
return ..()
/datum/robot_component/cell/destroy()
/datum/robot_component/cell/break_component()
..()
owner.cell = null
/datum/robot_component/cell/disable() //This can't be manually disabled, and shouldn't be accidentally disabled
return
/datum/robot_component/radio
name = "radio"
external_type = /obj/item/robot_parts/robot_component/radio
@@ -189,11 +216,19 @@
var/datum/robot_component/C = components[module_name]
return C && C.installed && C.toggled && C.is_powered() && !C.component_disabled
///Disables a random component for the duration, or until manually turned back on.
/mob/living/silicon/robot/proc/disable_random_component(number_disabled, duration)
var/list/random_components = pick_multiple_unique(components, number_disabled)
for(var/component in random_components)
disable_component(component, duration)
/mob/living/silicon/robot/proc/disable_component(module_name, duration)
var/datum/robot_component/D = get_component(module_name)
D.disable()
spawn(duration)
D.enable()
addtimer(CALLBACK(src, PROC_REF(reenable_component), D), duration)
/mob/living/silicon/robot/proc/reenable_component(datum/robot_component/to_enable)
to_enable.enable()
// Returns component by it's string name
/mob/living/silicon/robot/proc/get_component(component_name)
@@ -32,6 +32,21 @@
heal_overall_damage(0, -amount, updating_health)
return STATUS_UPDATE_HEALTH
/mob/living/silicon/robot/update_stamina()
if(rebooting)
return
var/current_stam_damage = getStaminaLoss()
if(current_stam_damage > DAMAGE_PRECISION && (maxHealth - current_stam_damage) <= HEALTH_THRESHOLD_CRIT && stat == CONSCIOUS)
start_emergency_reboot()
/mob/living/silicon/robot/handle_status_effects()
..()
if(stam_regen_start_time <= world.time)
update_stamina()
if(staminaloss && !rebooting)
setStaminaLoss(0, FALSE)
update_stamina_hud()
/mob/living/silicon/robot/proc/get_damaged_components(get_brute, get_burn, get_borked = FALSE, get_missing = FALSE)
var/list/datum/robot_component/parts = list()
for(var/V in components)
@@ -55,14 +70,32 @@
if(C.installed)
rval += C
return rval
///Returns the armour component for a borg, or false if its missing or broken
/mob/living/silicon/robot/proc/get_armour()
if(!LAZYLEN(components))
return 0
return FALSE
var/datum/robot_component/C = components["armour"]
if(C && C.installed)
return C
return 0
return FALSE
///Returns the power cell component for a borg, or false if its missing or broken
/mob/living/silicon/robot/proc/get_cell_component()
if(!LAZYLEN(components))
return FALSE
var/datum/robot_component/C = components["power cell"]
if(C?.installed)
return C
return FALSE
/mob/living/silicon/robot/proc/get_total_component_slowdown()
var/total_slowdown = 0
for(var/V in components)
var/datum/robot_component/C = components[V]
total_slowdown += C.get_movement_delay()
return total_slowdown
/mob/living/silicon/robot/proc/get_stamina_slowdown()
return round((staminaloss / 40), 0.125)
/mob/living/silicon/robot/heal_organ_damage(brute, burn, updating_health = TRUE)
var/list/datum/robot_component/parts = get_damaged_components(brute, burn)
@@ -131,3 +164,45 @@
parts -= picked
updatehealth()
/*
Begins the stamcrit reboot process for borgs. Stuns them, and warns people if the borg has no power source.
*/
/mob/living/silicon/robot/proc/start_emergency_reboot()
rebooting = TRUE
playsound(src, 'sound/machines/shut_down.ogg', 100, FALSE, SOUND_RANGE_SET(10))
if(!has_power_source())
visible_message(
"<span class='warning'>[src]'s system sounds an alarm, \"ERROR: NO POWER SOURCE DETECTED. SYSTEM SHUTDOWN IMMINENT.\"</span>",
"<span class='warning'>EMERGENCY: FULL SYSTEM SHUTDOWN IMMINENT.</span>")
playsound(src, 'sound/machines/buzz-two.ogg' , 50, FALSE, SOUND_RANGE_SET(10))
else
visible_message(
"<span class='notice'>[src]'s lights suddenly go dark and [p_they()] seem to shut down.</span>",
"<span class='notice'>A critical neural connection error has occurred. Beginning emergency reboot...</span>"
)
var/stun_time = rand(13 SECONDS, 18 SECONDS) //Slightly longer than old flash timer
setStaminaLoss(0) //Have you tried turning it off and on again?
Weaken(stun_time)
addtimer(CALLBACK(src, PROC_REF(end_emergency_reboot)), stun_time)
/*
Finishes the stamcrit process. If the borg doesn't have a power source for the reboot, they die.
*/
/mob/living/silicon/robot/proc/end_emergency_reboot()
if(!has_power_source()) //Can't turn itself back on
rebooting = FALSE
death()
return
if(getStaminaLoss()) //If someone has been chain-flashing a borg then the ride never ends
var/restun_time = rand(7 SECONDS, 10 SECONDS)
to_chat(src, "<span class='warning'>Error: Continual sensor overstimulation resulted in faulty reboot. Retrying in [restun_time / 10] seconds.</span>")
setStaminaLoss(0) //Just keep trying to turn it off and on again, surely it'll work eventually
Weaken(restun_time)
addtimer(CALLBACK(src, PROC_REF(end_emergency_reboot)), restun_time)
return
rebooting = FALSE
if(stat != CONSCIOUS)
return
playsound(src, 'sound/machines/reboot_chime.ogg' , 100, FALSE, SOUND_RANGE_SET(10))
update_stamina_hud()
to_chat(src, "<span class='notice'>Reboot complete, neural interface operational.</span>")
@@ -8,7 +8,7 @@
visible_message("<span class='danger'>[M] disarmed [src]!</span>", "<span class='userdanger'>[M] has disabled [src]'s active module!</span>")
add_attack_logs(M, src, "alien disarmed")
else
Stun(4 SECONDS)
adjustStaminaLoss(30) //Same as carbons, I guess?
step(src, get_dir(M,src))
add_attack_logs(M, src, "Alien pushed over")
visible_message("<span class='danger'>[M] forces back [src]!</span>", "<span class='userdanger'>[M] forces back [src]!</span>")
@@ -55,3 +55,12 @@
step_away(src, user, 15)
sleep(3)
step_away(src, user, 15)
/mob/living/silicon/robot/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/stretch/flash/noise)
if(!affect_silicon)
return
Confused(intensity * 4 SECONDS)
var/software_damage = (intensity * 40)
adjustStaminaLoss(software_damage)
to_chat(src, "<span class='warning'>Error: Optical sensors overstimulated.</span>")
..()
@@ -15,33 +15,35 @@
/mob/living/silicon/robot/proc/handle_robot_cell()
if(stat != DEAD)
if(!is_component_functioning("power cell"))
uneq_all()
low_power_mode = TRUE
update_headlamp()
diag_hud_set_borgcell()
return
if(low_power_mode)
if(is_component_functioning("power cell") && cell.charge)
low_power_mode = FALSE
update_headlamp()
else if(stat == CONSCIOUS)
use_power()
if(stat == DEAD)
return
if(externally_powered)
return
if(low_power_mode)
handle_no_power()
else if(!is_component_functioning("power cell")) //This makes it so you'll only get the warnings once per running out of charge
enter_low_power_mode()
else if(stat == CONSCIOUS)
use_power()
/mob/living/silicon/robot/proc/use_power()
// this check is safe because `cell` is guaranteed to be set when the power cell is functioning
if(is_component_functioning("power cell") && cell.charge)
if(cell.charge <= 100)
uneq_all()
var/amt = clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
else
uneq_all()
low_power_mode = TRUE
update_headlamp()
var/amt = clamp((lamp_intensity - 2) * 2, 1, cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
diag_hud_set_borgcell()
/mob/living/silicon/robot/proc/handle_no_power()
diag_hud_set_borgcell()
if(is_component_functioning("power cell"))
low_power_mode = FALSE
return
adjustStaminaLoss(3)
/mob/living/silicon/robot/proc/enter_low_power_mode()
low_power_mode = TRUE
playsound(src, "sound/mecha/lowpower.ogg", 50, FALSE, SOUND_RANGE_SET(10))
to_chat(src, "<span_class='warning'>Alert: Power cell requires immediate charging.</span>")
handle_no_power()
/mob/living/silicon/robot/proc/handle_equipment()
if(camera && !scrambledcodes)
if(stat == DEAD || wires.is_cut(WIRE_BORG_CAMERA))
@@ -75,7 +75,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/brute_mod = 1
/// Incoming burn damage is multiplied by this number.
var/burn_mod = 1
///If the cyborg is rebooting from stamcrit
var/rebooting = FALSE
///If the cyborg is in a charger, or otherwise receiving power from an outside source.
var/externally_powered = FALSE
///What the cyborg's maximum slowdown penalty is, if it has one.
var/slowdown_cap = INFINITY
var/list/force_modules
/// Can a robot rename itself with the Namepick verb?
var/allow_rename = TRUE
@@ -212,7 +217,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
scanner = new(src)
scanner.Grant(src)
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(create_trail))
RegisterSignal(src, COMSIG_ENTERED_BORGCHARGER, PROC_REF(gain_external_power))
RegisterSignal(src, COMSIG_EXITED_BORGCHARGER, PROC_REF(lose_external_power))
robot_module_hat_offset(icon_state)
/mob/living/silicon/robot/get_radio()
@@ -684,7 +690,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
if("lava" in weather_immunities) // Remove the lava-immunity effect given by a printable upgrade
weather_immunities -= "lava"
armor = getArmor(arglist(initial(armor)))
slowdown_cap = INFINITY
status_flags |= CANPUSH
hud_used.update_robot_modules_display()
@@ -881,21 +887,17 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
if(istype(W, /obj/item/robot_parts/robot_component) && opened)
for(var/V in components)
var/datum/robot_component/C = components[V]
if(C.is_missing() && istype(W, C.external_type))
if(!user.drop_item())
to_chat(user, "<span class='warning'>[W] seems to be stuck in your hand!</span>")
return
C.install(W)
W.loc = null
var/obj/item/robot_parts/robot_component/WC = W
if(istype(WC))
C.brute_damage = WC.brute
C.electronics_damage = WC.burn
to_chat(usr, "<span class='notice'>You install [W].</span>")
if(!C.is_missing() || !istype(W, C.external_type))
continue
if(!user.drop_item())
to_chat(user, "<span class='warning'>[W] seems to be stuck in your hand!</span>")
return
var/obj/item/robot_parts/robot_component/WC = W
C.brute_damage = WC.brute
C.electronics_damage = WC.burn
C.install(WC)
to_chat(usr, "<span class='notice'>You install [W].</span>")
return
if(istype(W, /obj/item/stack/cable_coil) && user.a_intent == INTENT_HELP && (wiresexposed || isdrone(src)))
user.changeNext_move(CLICK_CD_MELEE)
@@ -920,12 +922,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
to_chat(user, "There is a power cell already installed.")
else
user.drop_item()
W.loc = src
to_chat(user, "You insert the power cell.")
C.install(W)
//This will mean that removing and replacing a power cell will repair the mount, but I don't care at this point. ~Z
C.brute_damage = 0
C.electronics_damage = 0
var/been_hijacked = FALSE
for(var/mob/living/simple_animal/demon/pulse_demon/demon in cell)
@@ -1092,7 +1090,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
thing.burn = C.electronics_damage
C.uninstall()
thing.loc = loc
thing.forceMove(loc)
@@ -1485,11 +1483,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
if(emp_protection)
return
..()
adjustStaminaLoss((30 / severity)) //They also get flashed for an additional 30
switch(severity)
if(1)
disable_component("comms", 160)
if(2)
disable_component("comms", 60)
if(EMP_HEAVY)
disable_random_component(2, 20 SECONDS)
if(EMP_LIGHT)
disable_random_component(1, 10 SECONDS)
/mob/living/silicon/robot/deathsquad
base_icon = "nano_bloodhound"
@@ -1750,3 +1749,17 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
old_ai.connected_robots -= src
if(connected_ai)
connected_ai.connected_robots |= src
/mob/living/silicon/robot/proc/gain_external_power()
SIGNAL_HANDLER //COMSIG_ENTERED_BORGCHARGER
externally_powered = TRUE
/mob/living/silicon/robot/proc/lose_external_power()
SIGNAL_HANDLER //COMSIG_EXITED_BORGCHARGER
externally_powered = FALSE
/mob/living/silicon/robot/proc/has_power_source()
var/datum/robot_component/cell/cell = get_cell_component()
if(!cell)
return externally_powered
return cell.is_powered() || externally_powered
@@ -472,7 +472,7 @@
/obj/item/inflatable/cyborg,
/obj/item/inflatable/cyborg/door
)
emag_modules = list(/obj/item/borg/stun, /obj/item/restraints/handcuffs/cable/zipties/cyborg, /obj/item/rcd/borg)
emag_modules = list(/obj/item/melee/baton/loaded/borg_stun_arm, /obj/item/restraints/handcuffs/cable/zipties/cyborg, /obj/item/rcd/borg)
override_modules = list(/obj/item/gun/energy/emitter/cyborg/proto)
malf_modules = list(/obj/item/gun/energy/emitter/cyborg)
special_rechargables = list(/obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg, /obj/item/gun/energy/emitter/cyborg)
@@ -5,16 +5,18 @@
return TRUE
return FALSE
//No longer needed, but I'll leave it here incase we plan to re-use it.
/mob/living/silicon/robot/movement_delay()
. = ..()
. += GLOB.configuration.movement.robot_delay
. += speed
. += get_total_component_slowdown()
. += get_stamina_slowdown()
// Counteract magboot slow in 0G.
if(!has_gravity(src) && HAS_TRAIT(src, TRAIT_MAGPULSE))
. -= 2 // The slowdown value on the borg magpulse.
if(module_active && istype(module_active,/obj/item/borg/destroyer/mobility))
. -= 3
. += GLOB.configuration.movement.robot_delay
. = min(., slowdown_cap)
/mob/living/silicon/robot/mob_negates_gravity()
return HAS_TRAIT(src, TRAIT_MAGPULSE)
@@ -14,7 +14,7 @@
death()
create_debug_log("died of damage, trigger reason: [reason]")
return
if(!is_component_functioning("actuator") || !is_component_functioning("power cell") || HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || IsStunned() || IsWeakened() || getOxyLoss() > maxHealth * 0.5) // Borgs need to be able to sleep for adminfreeze
if(HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || IsStunned() || IsWeakened() || getOxyLoss() > maxHealth * 0.5) // Borgs need to be able to sleep for adminfreeze
if(stat == CONSCIOUS)
KnockOut()
create_debug_log("fell unconscious, trigger reason: [reason]")
@@ -23,11 +23,11 @@
WakeUp()
create_debug_log("woke up, trigger reason: [reason]")
else
if(health > 0 && !suiciding)
if(health > 0 && !suiciding && has_power_source())
update_revive()
var/mob/dead/observer/ghost = get_ghost()
if(ghost)
to_chat(ghost, "<span class='ghostalert'>Your cyborg shell has been repaired, re-enter if you want to continue!</span> (Verbs -> Ghost -> Re-enter corpse)")
to_chat(ghost, "<span class='ghostalert'>Your cyborg shell has been repaired and repowered, re-enter if you want to continue!</span> (Verbs -> Ghost -> Re-enter corpse)")
SEND_SOUND(ghost, sound('sound/effects/genetics.ogg'))
create_attack_log("revived, trigger reason: [reason]")
create_log(MISC_LOG, "revived, trigger reason: [reason]")
@@ -230,10 +230,8 @@
switch(severity)
if(EMP_HEAVY)
take_organ_damage(20)
Stun(16 SECONDS)
if(EMP_LIGHT)
take_organ_damage(10)
Stun(6 SECONDS)
flash_eyes(affect_silicon = 1)
to_chat(src, "<span class='danger'>*BZZZT*</span>")
to_chat(src, "<span class='warning'>Warning: Electromagnetic pulse detected.</span>")
@@ -43,6 +43,12 @@
flag = ENERGY
temperature = 50
/obj/item/projectile/temp/basilisk/on_hit(atom/target, blocked)
..()
if(isrobot(target))
var/mob/living/silicon/robot/cyborg = target
cyborg.apply_damage(35, STAMINA)
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(new_target)
if(..()) //we have a target
if(isliving(target) && !target.Adjacent(targets_from) && ranged_cooldown <= world.time)//No more being shot at point blank or spammed with RNG beams
@@ -294,8 +294,6 @@
if(isalien(target))
knockdown = 0
nodamage = TRUE
if(isrobot(target))
stun = 10 SECONDS
. = ..() // Execute the rest of the code.
/obj/item/projectile/bullet/anti_alien_toxin
+1 -1
View File
@@ -594,7 +594,7 @@ crawling_speed_reduction = 4
# Move delay for humanoids
human_delay = 1.5
# Move delay for cyborgs
robot_delay = 2.5
robot_delay = 1.5
# Move delay for xenomorphs
alien_delay = 1.5
# Move delay for slimes (xenobio, not slimepeople)
Binary file not shown.
Binary file not shown.