mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-24 21:40:55 +01:00
Fixes many mech bugs (#22983)
Four major fixes. These are all pretty clearly bugs, but the result is a substantial mech nerf (except EMPs against EM armor.) First, EMP armour. EMP armour did nothing, it was partially ported to use TG's Element flag system, this finishes that. Rather than make the EMP armour immune to EMP, it spends power to negate it. The cost is 1000 / severity. Heavy EMP is 1, Light EMP is 2. This is 5% of a basic mech cell for light, 10% for heavy. Also fixes the pilot getting EMP'd twice for every EMP act on the mech. Second, open hatches let attacks hit the pilot. Chance is 80% from the front, 20% from the sides. The chance is mostly so that turrets that always aim torso don't shoot mechs forever, always hitting the pilot inside. Third, cockpit damage actually matters now. Previously shooting the mech in the chest was nearly worthless, no important components were there and destroying it did not destroy the mech. Now if the cockpit is completely destroyed, attacks against it penetrate through to hit the pilot. These attacks still account for the mech's armour. Combined with the hatch getting stuck closed, you can have tense rescues of pilots bleeding out inside their suits. Fourth, the mech running out of power actually stops it doing things. Uranium and Phoron power cores allowed mechs to keep running forever, even at fractional power, because they recharged slightly every tick. Now if the mech ever cannot afford the power cost of an action it shuts down. It can be powered back up immediately if the power core recharges it, but it cannot now do costly actions at single digit power. I fixed mech combat shields. They suck, they use the auras system which does not play nicely with the new projectile code. Recursive calls and spaghetti mess. Works for now but could use a complete rewrite. --------- Signed-off-by: FenodyreeAv <fenodyree.av@gmail.com>
This commit is contained in:
@@ -15,6 +15,15 @@ They should also be used for when you want to effect the ENTIRE mob, like having
|
||||
|
||||
return COMPONENT_BULLET_BLOCKED
|
||||
|
||||
/obj/aura/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
var/result = ..()
|
||||
if(result == BULLET_ACT_BLOCK) //The bullet was blocked, don't check the remaining auras.
|
||||
return AURA_FALSE|AURA_CANCEL
|
||||
else if(result == BULLET_ACT_FORCE_PIERCE) //The bullet was forced to pierce, check the remaining auras to see if they block.
|
||||
return AURA_FALSE
|
||||
else
|
||||
return
|
||||
|
||||
/obj/aura/Destroy()
|
||||
if(user)
|
||||
user.remove_aura(src)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
RAD = ARMOR_RAD_MINOR
|
||||
)
|
||||
origin_tech = list(TECH_MATERIAL = 1)
|
||||
var/emp_protection = 0
|
||||
|
||||
/obj/item/robot_parts/robot_component/armor/mech/Initialize()
|
||||
. = ..()
|
||||
@@ -33,8 +34,8 @@
|
||||
origin_tech = list(TECH_MATERIAL = 3)
|
||||
|
||||
/obj/item/robot_parts/robot_component/armor/mech/em
|
||||
name = "EM-shielded armor plating"
|
||||
desc = "A shielded plating that sorrounds the eletronics and protects them from electromagnetic radiation."
|
||||
name = "anti EM reactive armor plating"
|
||||
desc = "An advanced active-defense system that insulates the eletronics and destructively interferes with electromagnetic radiation."
|
||||
icon_state = "armor_e"
|
||||
icon_state_broken = "armor_e_broken"
|
||||
armor = list(
|
||||
@@ -47,6 +48,7 @@
|
||||
RAD = ARMOR_RAD_SMALL
|
||||
)
|
||||
origin_tech = list(TECH_MATERIAL = 3)
|
||||
emp_protection = 1
|
||||
|
||||
/obj/item/robot_parts/robot_component/armor/mech/combat
|
||||
name = "heavy combat plating"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
var/obj/item/robot_parts/robot_component/diagnosis_unit/diagnostics
|
||||
var/obj/item/cell/mecha/cell
|
||||
var/cell_type = /obj/item/cell/mecha
|
||||
var/obj/item/robot_parts/robot_component/armor/mech_armor
|
||||
var/obj/item/robot_parts/robot_component/armor/mech/mech_armor
|
||||
var/obj/structure/machinery/portable_atmospherics/canister/air_supply
|
||||
var/datum/gas_mixture/cockpit
|
||||
var/pilot_offset_x = 0
|
||||
|
||||
@@ -296,11 +296,12 @@
|
||||
desc = "The Hephaestus Armature system is a well liked energy deflector system designed to stop any projectile before it has a chance to become a threat."
|
||||
icon_state = "shield_droid"
|
||||
var/obj/aura/mechshield/aura
|
||||
var/max_charge = 150
|
||||
var/charge = 150
|
||||
var/max_charge = 100
|
||||
var/charge = 100
|
||||
var/last_recharge = 0
|
||||
var/charging_rate = 7500 * CELLRATE
|
||||
var/cooldown = 3.5 SECONDS // Time until we can recharge again after a blocked impact
|
||||
var/efficiency = 0.1 // How much power is required to recharge 1 point of shield charge
|
||||
restricted_hardpoints = list(HARDPOINT_BACK)
|
||||
restricted_software = list(MECH_SOFTWARE_WEAPONS)
|
||||
module_hints = list(
|
||||
@@ -331,7 +332,7 @@
|
||||
|
||||
last_recharge = world.time
|
||||
|
||||
if(difference > 0)
|
||||
if(difference >= 0)
|
||||
for(var/mob/pilot in owner.pilots)
|
||||
to_chat(pilot, FONT_LARGE(SPAN_WARNING("Warning: Deflector shield failure detected, shutting down.")))
|
||||
toggle()
|
||||
@@ -379,8 +380,10 @@
|
||||
if((world.time - last_recharge) < cooldown)
|
||||
return
|
||||
|
||||
var/actual_required_power = clamp(max_charge - charge, 0, charging_rate)
|
||||
owner.use_cell_power(actual_required_power)
|
||||
var/actual_required_power = clamp(max_charge * efficiency - charge * efficiency, 0, charging_rate)
|
||||
var/actual_power_used = owner.use_cell_power(actual_required_power)
|
||||
if(actual_power_used > 0)
|
||||
charge = clamp(charge + actual_power_used, 0, max_charge)
|
||||
|
||||
/obj/item/mecha_equipment/shield/get_hardpoint_status_value()
|
||||
return charge / max_charge
|
||||
@@ -434,24 +437,51 @@
|
||||
else
|
||||
icon_state = "shield_null"
|
||||
|
||||
/obj/aura/mechshield/handle_bullet_act(datum/source, obj/projectile/projectile)
|
||||
if(!active || !shields || !shields.charge)
|
||||
return FALSE
|
||||
|
||||
var/incoming_attack_direction = projectile.starting ? get_dir(shields, projectile.starting) : null
|
||||
if(!(dir & incoming_attack_direction))
|
||||
return FALSE
|
||||
|
||||
var/damage = projectile.get_structure_damage()
|
||||
if(!damage)
|
||||
damage = projectile.damage
|
||||
|
||||
projectile.damage = shields.stop_damage(damage)
|
||||
user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash and crackle."))
|
||||
flick("shield_impact", src)
|
||||
playsound(user, 'sound/effects/basscannon.ogg', 35, TRUE)
|
||||
//light up the night.
|
||||
new /obj/effect/smoke/illumination(get_turf(src), 5, 4, 1, "#ffffff")
|
||||
spark(get_turf(src), 5, GLOB.alldirs)
|
||||
playsound(get_turf(src), SFX_SPARKS, 25, TRUE)
|
||||
return COMPONENT_BULLET_BLOCKED
|
||||
|
||||
/obj/aura/mechshield/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(!active)
|
||||
return
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
|
||||
. = ..()
|
||||
if(!active || !shields || !shields.charge)
|
||||
return FALSE
|
||||
|
||||
if(shields?.charge)
|
||||
hitting_projectile.damage = shields.stop_damage(hitting_projectile.damage)
|
||||
user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash and crackle."))
|
||||
flick("shield_impact", src)
|
||||
playsound(user, 'sound/effects/basscannon.ogg', 35, TRUE)
|
||||
//light up the night.
|
||||
new /obj/effect/smoke/illumination(get_turf(src), 5, 4, 1, "#ffffff")
|
||||
if(hitting_projectile.damage <= 0)
|
||||
return AURA_FALSE|AURA_CANCEL
|
||||
var/incoming_attack_direction = hitting_projectile.starting ? get_dir(shields, hitting_projectile.starting) : null
|
||||
if(!(dir & incoming_attack_direction))
|
||||
return FALSE
|
||||
|
||||
spark(get_turf(src), 5, GLOB.alldirs)
|
||||
playsound(get_turf(src), SFX_SPARKS, 25, TRUE)
|
||||
var/damage = hitting_projectile.get_structure_damage()
|
||||
if(!damage)
|
||||
damage = hitting_projectile.damage
|
||||
|
||||
hitting_projectile.damage = shields.stop_damage(damage)
|
||||
user.visible_message(SPAN_WARNING("\The [shields.owner]'s shields flash and crackle."))
|
||||
flick("shield_impact", src)
|
||||
playsound(user, 'sound/effects/basscannon.ogg', 35, TRUE)
|
||||
//light up the night.
|
||||
new /obj/effect/smoke/illumination(get_turf(src), 5, 4, 1, "#ffffff")
|
||||
spark(get_turf(src), 5, GLOB.alldirs)
|
||||
playsound(get_turf(src), SFX_SPARKS, 25, TRUE)
|
||||
return AURA_FALSE|AURA_CANCEL
|
||||
|
||||
/obj/aura/mechshield/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
. = ..()
|
||||
|
||||
@@ -1,8 +1,35 @@
|
||||
///Returns TRUE if an incoming attack should target the pilot instead of the mech, FALSE otherwise.
|
||||
/mob/living/heavy_vehicle/proc/should_target_pilot(atom/attack_source = null)
|
||||
if(!body || !LAZYLEN(pilots)) //If there is no pilot, or the mech somehow doesn't have a body don't try hit the pilot.
|
||||
return FALSE
|
||||
|
||||
var/incoming_attack_direction = attack_source ? get_dir(src, attack_source) : null
|
||||
|
||||
if (istype(hardpoints[HARDPOINT_BACK], /obj/item/mecha_equipment/shield)) //If the mech has a shield.
|
||||
var/obj/item/mecha_equipment/shield/shield = hardpoints[HARDPOINT_BACK]
|
||||
if (shield.active && shield.aura && shield.aura.active) //If the shield is active.
|
||||
if (incoming_attack_direction && (dir & incoming_attack_direction)) //If the attack comes from the front and the shield is active, the pilot is protected.
|
||||
return FALSE
|
||||
|
||||
if(!prob(body.pilot_coverage)) //If the cockpit doesn't cover the pilot completely, attacks have a chance to hit the pilot instead of the mech.
|
||||
return TRUE
|
||||
|
||||
if(!hatch_closed) //Open hatches only expose the pilot to attacks from the front and a little bit from the sides.
|
||||
if(incoming_attack_direction)
|
||||
if (dir & incoming_attack_direction)
|
||||
if(prob(80)) //80% chance to hit the pilot from the front if the hatch is open. If this is 100% turrets will shoot mechs with open hatches forever.
|
||||
return TRUE
|
||||
if ((turn(dir, 90) & incoming_attack_direction) || (turn(dir, -90) & incoming_attack_direction))
|
||||
if(prob(20)) //20% chance to hit the pilot from the sides if the hatch is open.
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/mob/living/heavy_vehicle/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0)
|
||||
if(!effect || (blocked >= 100))
|
||||
return 0
|
||||
|
||||
if(LAZYLEN(pilots) && (!hatch_closed || !prob(body.pilot_coverage)))
|
||||
if(should_target_pilot())
|
||||
if(effect > 0 && effecttype == DAMAGE_RADIATION)
|
||||
var/mob/living/pilot = pick(pilots)
|
||||
return pilot.apply_effect(effect, effecttype, blocked)
|
||||
@@ -10,11 +37,18 @@
|
||||
. = ..()
|
||||
|
||||
/mob/living/heavy_vehicle/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
if(LAZYLEN(pilots) && (!hatch_closed || !prob(body.pilot_coverage)))
|
||||
if(should_target_pilot(hitting_atom))
|
||||
var/mob/living/pilot = pick(pilots)
|
||||
return pilot.hitby(arglist(args))
|
||||
. = ..()
|
||||
|
||||
/mob/living/heavy_vehicle/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
if(should_target_pilot(hitting_projectile?.starting))
|
||||
var/mob/living/pilot = pick(pilots)
|
||||
if(pilot)
|
||||
return pilot.bullet_act(hitting_projectile, def_zone, piercing_hit)
|
||||
return ..()
|
||||
|
||||
/mob/living/heavy_vehicle/get_armors_by_zone(def_zone, damage_type, damage_flags)
|
||||
. = ..()
|
||||
if(body)
|
||||
@@ -82,6 +116,13 @@
|
||||
return 0
|
||||
|
||||
var/target = zoneToComponent(def_zone)
|
||||
|
||||
if(target == body && body.damage_state == MECH_COMPONENT_DAMAGE_DAMAGED_TOTAL) //If the cockpit is destroyed, subsequent damage is applied to the pilot, modified by the mech's armour.
|
||||
if(body && LAZYLEN(pilots))
|
||||
var/mob/living/pilot = pick(pilots)
|
||||
visible_message(SPAN_DANGER("\The [used_weapon] pierces the mangled cockpit of \the [src], striking the pilot inside!"))
|
||||
pilot.apply_damage(damage, damagetype, def_zone, used_weapon, damage_flags, armor_pen, silent = FALSE)
|
||||
|
||||
//Only 2 types of damage concern mechs and vehicles
|
||||
switch(damagetype)
|
||||
if(DAMAGE_BRUTE)
|
||||
@@ -114,25 +155,26 @@
|
||||
|
||||
/mob/living/heavy_vehicle/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
var/obj/item/cell/C = get_cell()
|
||||
if(C.charge > 1000) //Don't completely run a mech out of power this way.
|
||||
var/power_used = use_cell_power(1000 / severity)
|
||||
var/percent_power_used = 0
|
||||
if(C && C.maxcharge)
|
||||
percent_power_used = round((power_used / C.maxcharge) * 100)
|
||||
visible_message(SPAN_NOTICE("\The [src]'s active EM defenses flash brightly, negating the EMP!"))
|
||||
for(var/pilot in pilots)
|
||||
if(ismob(pilot))
|
||||
to_chat(pilot, SPAN_NOTICE("Your mech reports that negating the EMP cost [(percent_power_used)]% charge."))
|
||||
else
|
||||
for(var/pilot in pilots)
|
||||
if(ismob(pilot))
|
||||
to_chat(pilot, SPAN_DANGER("Your mech's EMP countermeasures deactivate as power levels drop too low."))
|
||||
else
|
||||
var/ratio = get_blocked_ratio(null, DAMAGE_BURN, null, (4-severity) * 20)
|
||||
emp_damage += round((12 - (severity*3))*( 1 - ratio))
|
||||
|
||||
var/ratio = get_blocked_ratio(null, DAMAGE_BURN, null, (4-severity) * 20)
|
||||
|
||||
if(ratio >= 0.5)
|
||||
for(var/mob/living/m in pilots)
|
||||
to_chat(m, SPAN_NOTICE("Your Faraday shielding absorbed the pulse!"))
|
||||
return
|
||||
else if(ratio > 0)
|
||||
for(var/mob/living/m in pilots)
|
||||
to_chat(m, SPAN_NOTICE("Your Faraday shielding mitigated the pulse!"))
|
||||
|
||||
emp_damage += round((12 - (severity*3))*( 1 - ratio))
|
||||
|
||||
for(var/obj/item/thing in list(arms,legs,head,body))
|
||||
thing.emp_act(severity)
|
||||
if(!hatch_closed || !prob(body.pilot_coverage))
|
||||
for(var/thing in pilots)
|
||||
var/mob/pilot = thing
|
||||
pilot.emp_act(severity)
|
||||
update_emp_protection()
|
||||
|
||||
/mob/living/heavy_vehicle/fall_impact(levels_fallen, stopped_early = FALSE, var/damage_mod = 1)
|
||||
// No gravity, stop falling into spess!
|
||||
|
||||
@@ -161,20 +161,32 @@
|
||||
|
||||
/mob/living/heavy_vehicle/proc/use_cell_power(var/power_to_use)
|
||||
var/power_used = get_cell()?.use(power_to_use)
|
||||
if(power_used <= 0)
|
||||
if(power_used < power_to_use - 1) //Self recharging cells would otherwise allow a mech to run indefinately at full functionality with 0.1% charge.
|
||||
for(var/hardpoint in hardpoints)
|
||||
var/obj/item/mecha_equipment/ME = hardpoints[hardpoint]
|
||||
if(ME)
|
||||
ME.deactivate()
|
||||
if(power == MECH_POWER_ON)
|
||||
playsound(src, 'sound/mecha/mech-shutdown.ogg', 100, 0)
|
||||
power = MECH_POWER_OFF
|
||||
update_emp_protection()
|
||||
if(hud_power_control)
|
||||
SSicon_update.add_to_queue(hud_power_control)
|
||||
return power_used
|
||||
|
||||
/mob/living/heavy_vehicle/proc/drain_cell_power(var/power_to_drain)
|
||||
var/power_used = get_cell()?.drain_power(0, 0, power_to_drain)
|
||||
if(power_used <= 0)
|
||||
if(power_used < power_to_drain - 1) //Self recharging cells would otherwise allow a mech to run indefinately at full functionality with 0.1% charge.
|
||||
for(var/hardpoint in hardpoints)
|
||||
var/obj/item/mecha_equipment/ME = hardpoints[hardpoint]
|
||||
if(ME)
|
||||
ME.deactivate()
|
||||
if(power == MECH_POWER_ON)
|
||||
playsound(src, 'sound/mecha/mech-shutdown.ogg', 100, 0)
|
||||
power = MECH_POWER_OFF
|
||||
update_emp_protection()
|
||||
if(hud_power_control)
|
||||
SSicon_update.add_to_queue(hud_power_control)
|
||||
return power_used
|
||||
|
||||
/mob/living/heavy_vehicle/proc/checked_use_cell(var/power_to_drain)
|
||||
|
||||
@@ -266,6 +266,12 @@
|
||||
/mob/living/heavy_vehicle/return_air()
|
||||
return (body && body.pilot_coverage >= 100 && hatch_closed) ? body.cockpit : loc?.return_air()
|
||||
|
||||
/mob/living/heavy_vehicle/proc/update_emp_protection()
|
||||
RemoveElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
if(power == MECH_POWER_ON && body.mech_armor && body.mech_armor.emp_protection)
|
||||
if(get_cell().charge > 500)
|
||||
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
|
||||
|
||||
/mob/living/heavy_vehicle/GetIdCard()
|
||||
return access_card
|
||||
|
||||
@@ -288,18 +294,22 @@
|
||||
to_chat(reciever, SPAN_NOTICE("Power transition in progress. Please wait."))
|
||||
else if(power == MECH_POWER_ON) //Turning it off is instant
|
||||
power = MECH_POWER_OFF
|
||||
else if(get_cell(TRUE))
|
||||
update_emp_protection()
|
||||
else if(get_cell(TRUE).check_charge(1000)) //Check if we have enough charge to power on
|
||||
//Start power up sequence
|
||||
power = MECH_POWER_TRANSITION
|
||||
playsound(src, 'sound/mecha/powerup.ogg', 50, 0)
|
||||
if(do_after(reciever, 1.5 SECONDS) && power == MECH_POWER_TRANSITION)
|
||||
power = MECH_POWER_ON
|
||||
update_emp_protection()
|
||||
sound_looping = TRUE
|
||||
soundloop.start()
|
||||
else
|
||||
to_chat(reciever, SPAN_WARNING("You abort the powerup sequence."))
|
||||
power = MECH_POWER_OFF
|
||||
hud_power_control?.queue_icon_update()
|
||||
update_emp_protection()
|
||||
if(hud_power_control)
|
||||
SSicon_update.add_to_queue(hud_power_control)
|
||||
else
|
||||
to_chat(reciever, SPAN_WARNING("Error: No power cell was detected."))
|
||||
|
||||
|
||||
@@ -56,8 +56,7 @@
|
||||
//Auras, essentially magic and encompassing around us, gets checked first
|
||||
if(!src.aura_check(AURA_TYPE_BULLET, hitting_projectile, def_zone, piercing_hit))
|
||||
blocked = 100
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
|
||||
return BULLET_ACT_BLOCK
|
||||
|
||||
//Shields, in front of us (hopefully), check the bullet before it reaches us
|
||||
var/shield_check = check_shields(hitting_projectile.damage, hitting_projectile, hitting_projectile.firer, def_zone, "the [hitting_projectile.name]")
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
author: Fenodyree
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Fixes EMP armor for mechs."
|
||||
- bugfix: "Fixes mech pilot's getting EMP'd twice for every EMP hitting the mech."
|
||||
- bugfix: "Fixes shields for mechs."
|
||||
- bugfix: "Fixes mechs being able to draw infinite power, as long as there was any power in their cell."
|
||||
- bugfix: "Fixes cockpit coverage not letting the pilot be hit."
|
||||
- bugfix: "Fixes legacy icon updates."
|
||||
- rscadd: "Adds a chance for attacks to hit the mech's pilot after the cockpit has been destroyed. This still accounts for the mech's armor and shields."
|
||||
Reference in New Issue
Block a user