diff --git a/code/modules/heavy_vehicle/components/_components.dm b/code/modules/heavy_vehicle/components/_components.dm index 6e5d716b27d..07688994f92 100644 --- a/code/modules/heavy_vehicle/components/_components.dm +++ b/code/modules/heavy_vehicle/components/_components.dm @@ -9,13 +9,19 @@ var/total_damage = 0 var/brute_damage = 0 var/burn_damage = 0 + + /// The maximum combined brute and burn damage that the mech component can take before becoming completely broken. var/max_damage = 120 + var/damage_state = 1 var/list/has_hardpoints = list() var/power_use = 0 matter = list(DEFAULT_WALL_MATERIAL = 15000, MATERIAL_PLASTIC = 1000, MATERIAL_OSMIUM = 500) dir = SOUTH + /// Half of the baseline chance that attempting to use these arms will create sparks. Actual chance is twice this since the motivator damage contributes to the ratio. + var/spark_chance_ratio = 50 + /obj/item/mech_component/feedback_hints(mob/user, distance, is_adjacent) . += ..() if(ready_to_install()) diff --git a/code/modules/heavy_vehicle/components/body.dm b/code/modules/heavy_vehicle/components/body.dm index 90397a0b26e..e243cea2052 100644 --- a/code/modules/heavy_vehicle/components/body.dm +++ b/code/modules/heavy_vehicle/components/body.dm @@ -32,6 +32,13 @@ var/hide_pilot = TRUE has_hardpoints = list(HARDPOINT_BACK, HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) + /** + * Maximum % chance for an ejection to fail based on how much damage the mech's torso has taken. + * If you're stuck, better hope there's a friend available to bail you out.. + * Or you can keep the hatch open if you would rather risk getting zipped by incoming fire. + */ + var/ejection_fail_chance = 75 + /obj/item/mech_component/chassis/Initialize() . = ..() AddComponent(/datum/component/armor, armor, ARMOR_TYPE_STANDARD|ARMOR_TYPE_EXOSUIT) diff --git a/code/modules/heavy_vehicle/interface/screen_objects.dm b/code/modules/heavy_vehicle/interface/screen_objects.dm index c0760b1608e..2b0faf64527 100644 --- a/code/modules/heavy_vehicle/interface/screen_objects.dm +++ b/code/modules/heavy_vehicle/interface/screen_objects.dm @@ -211,6 +211,8 @@ /atom/movable/screen/mecha/toggle/air/toggled() toggled = !toggled owner.use_air = toggled + if (owner.use_air) + playsound(owner.loc, 'sound/effects/internals.ogg', 75, 1) var/main_color = owner.use_air ? "#d1d1d1" : "#525252" maptext = "AIR" notify_user(usr, SPAN_NOTICE("Auxiliary atmospheric system [owner.use_air ? "enabled" : "disabled"].")) @@ -286,6 +288,7 @@ maptext_y = 11 maptext_x = 5 notify_user(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked.")) + playsound(owner.loc, 'sound/effects/magnetclamp.ogg', 100, 1) /atom/movable/screen/mecha/toggle/hatch_open name = "open or close hatch" @@ -298,15 +301,29 @@ maptext_x = owner.hatch_closed ? 4 : 3 /atom/movable/screen/mecha/toggle/hatch_open/toggled(var/notify_user = TRUE) + var/obj/item/mech_component/chassis/body = owner.body + if(!body) // Edge case for the mech SOMEHOW not having a body. Players shouldn't ever see this. A mech without a body should be in the process of exploding. + notify_user(usr, SPAN_WARNING("What hatch? There's nothing left to open. If you're seeing this, please submit a bug report to our github issue tracker and tell us how!")) + return FALSE + if(owner.hatch_locked && owner.hatch_closed) notify_user(usr, SPAN_WARNING("You cannot open the hatch while it is locked.")) - return + return FALSE + + if(owner.hatch_closed && body.total_damage > 1 && prob((body.total_damage / body.max_damage) * body.ejection_fail_chance)) + to_chat(usr, SPAN_WARNING("You pull the hatch release. The hatch bolts hiss and clang with a deafening screech, but the hatch fails to open!")) + spark(owner, 6, GLOB.alldirs) + playsound(owner.loc, 'sound/effects/metalhit.ogg', 75, 1) + return FALSE + toggled = !toggled owner.hatch_closed = toggled + playsound(owner.loc, owner.hatch_closed ? 'sound/effects/metal_close.ogg' : 'sound/effects/air_seal.ogg', 75, 1) if(notify_user) notify_user(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ].")) update_icon() owner.update_icon() + return TRUE // This is basically just a holder for the updates the mech does. /atom/movable/screen/mecha/health diff --git a/code/modules/heavy_vehicle/mech_interaction.dm b/code/modules/heavy_vehicle/mech_interaction.dm index 73873c580c9..b8b993bebab 100644 --- a/code/modules/heavy_vehicle/mech_interaction.dm +++ b/code/modules/heavy_vehicle/mech_interaction.dm @@ -43,24 +43,29 @@ setClickCooldown(5) return - if(!(user in pilots) && user != src) - return - - // Are we facing the target? - if(!(get_dir(src, A) & dir)) - return - - if(!canClick()) + if(/* Do we have a pilot? */\ + !(user in pilots) && user != src \ + /* Are we facing the target? */\ + || !(get_dir(src, A) & dir) \ + /* Can we click on them? */\ + || !canClick()) return + // Check if the arms were completely destroyed. if(!arms) to_chat(user, SPAN_WARNING("\The [src] has no manipulators!")) setClickCooldown(3) + // Give some visible feedback for the mech damage preventing this. + spark(src, 2, GLOB.alldirs) return - if(!arms.motivator || !arms.motivator.is_functional()) + var/obj/item/robot_parts/robot_component/actuator/motivator = arms.motivator + // Check if the motivators were broken. + if(!motivator || !motivator.is_functional()) to_chat(user, SPAN_WARNING("Your motivators are damaged! You can't use your manipulators!")) setClickCooldown(15) + // Give some visible feedback for the mech damage preventing this. + spark(src, 2, GLOB.alldirs) return if(!checked_use_cell(arms.power_use * CELLRATE)) @@ -74,10 +79,18 @@ else zone_sel.set_selected_zone("chest", user) + // Get the ratio of damage over max damage + var/spark_chance = (motivator.total_dam / motivator.max_dam + arms.total_damage / arms.max_damage) \ + /* Multiply by the spark chance */\ + * arms.spark_chance_ratio \ + /* Then add the contribution from EMP damage. */\ + + emp_damage + // You may attack the target with your exosuit FIST if you're malfunctioning. var/failed = FALSE - if(emp_damage > EMP_ATTACK_DISRUPT && prob(emp_damage*2)) - to_chat(user, SPAN_WARNING("The wiring sparks as you attempt to control the exosuit!")) + if(prob(spark_chance)) + to_chat(user, SPAN_WARNING("Your exosuit's manipulators spark as you attempt to control them!")) + spark(src, 3, GLOB.alldirs) failed = TRUE if(!failed) @@ -146,7 +159,7 @@ D.TryToSwitchState(user) return else if(adj) - setClickCooldown(arms ? arms.action_delay : 15) + setClickCooldown(arms.action_delay) playsound(src.loc, arms.punch_sound, 45 + 25 * (arms.melee_damage / 50), -1 ) if(ismob(A)) var/mob/target = A @@ -246,7 +259,8 @@ if(hatch_locked) if(!silent) to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) return - hud_open.toggled(FALSE) + if(!hud_open.toggled(FALSE)) + return if(!silent) to_chat(user, SPAN_NOTICE("You open the hatch and climb out of \the [src].")) else @@ -362,7 +376,7 @@ /mob/living/heavy_vehicle/Move(atom/newloc, direct, glide_size_override = 0, update_dir = TRUE) // They shouldn't get to this proc without legs in the first place, but its okay to guard here. - if (!legs) + if (!legs || !legs.motivator) return . = ..() set_glide_size(DELAY_TO_GLIDE_SIZE(next_mecha_move - world.time)) @@ -372,6 +386,21 @@ use_cell_power(legs.power_use * CELLRATE) update_icon() + // Handling for leg damage feedback on movement. + var/obj/item/robot_parts/robot_component/actuator/motivator = legs.motivator + + // Get the ratio of damage over max damage. + var/spark_chance = (motivator.total_dam / motivator.max_dam + legs.total_damage / legs.max_damage) \ + /* Then multiply by the spark chance. */\ + * legs.spark_chance_ratio \ + /* And finally add the contribution from EMP damage. */\ + + emp_damage + + if(prob(spark_chance)) + for (var/mob/pilot in pilots) + to_chat(pilot, SPAN_WARNING("Your exosuit's legs spark as you attempt to control them!")) + spark(src, 3, GLOB.alldirs) + /mob/living/heavy_vehicle/Post_Incorpmove() if(istype(hardpoints[HARDPOINT_BACK], /obj/item/mecha_equipment/phazon)) var/obj/item/mecha_equipment/phazon/PZ = hardpoints[HARDPOINT_BACK] @@ -537,28 +566,41 @@ return ..() /mob/living/heavy_vehicle/attack_hand(var/mob/user) - // Drag the pilot out if possible. - if(user.a_intent == I_GRAB) - if(!LAZYLEN(pilots)) - to_chat(user, SPAN_WARNING("There is nobody inside \the [src].")) - else if(!hatch_closed) + // Try to attack on harm intent. + if(user.a_intent == I_HURT) + attack_generic(user) + return + + // Otherwise try to toggle the hatch. + if(!body) // Edge case for the mech SOMEHOW not having a body. Players shouldn't ever see this. A mech without a body should be in the process of exploding. + to_chat(user, SPAN_WARNING("What hatch? There's nothing left to open. If you're seeing this, please submit a bug report to our github issue tracker and tell us how!")) + return + + if(hatch_locked) + to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) + return + + if(!hatch_closed) + // Drag the pilot out if possible. + if(user.a_intent == I_GRAB) + if(!LAZYLEN(pilots)) + to_chat(user, SPAN_WARNING("There is nobody inside \the [src].")) + return + var/mob/pilot = pick(pilots) user.visible_message(SPAN_DANGER("\The [user] is trying to pull \the [pilot] out of \the [src]!")) if(do_after(user, 30) && user.Adjacent(src) && (pilot in pilots) && !hatch_closed) user.visible_message(SPAN_DANGER("\The [user] drags \the [pilot] out of \the [src]!")) eject(pilot, silent=1) - + return + else if (body.total_damage > 1 && prob((body.total_damage / body.max_damage) * body.ejection_fail_chance)) + to_chat(user, SPAN_WARNING("You pull the hatch release. The hatch bolts hiss and clang with a deafening screech, but the hatch fails to open!")) + spark(src, 6, GLOB.alldirs) + playsound(loc, 'sound/effects/metalhit.ogg', 75, 1) return - if(user.a_intent == I_HURT) - attack_generic(user) - return - - // Otherwise toggle the hatch. - if(hatch_locked) - to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked.")) - return hatch_closed = !hatch_closed + playsound(loc, hatch_closed ? 'sound/effects/metal_close.ogg' : 'sound/effects/air_seal.ogg', 75, 1) to_chat(user, SPAN_NOTICE("You [hatch_closed ? "close" : "open"] the [body.hatch_descriptor].")) hud_open.update_icon() update_icon() diff --git a/code/modules/heavy_vehicle/premade/combat.dm b/code/modules/heavy_vehicle/premade/combat.dm index 970a79690cd..c82823f8395 100644 --- a/code/modules/heavy_vehicle/premade/combat.dm +++ b/code/modules/heavy_vehicle/premade/combat.dm @@ -19,7 +19,7 @@ icon_state = "combat_arms" melee_damage = 30 action_delay = 5 - max_damage = 130 + max_damage = 195 power_use = 2500 has_hardpoints = list(HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) diff --git a/code/modules/heavy_vehicle/premade/cult.dm b/code/modules/heavy_vehicle/premade/cult.dm index ca4fbbb14e5..7a168930d53 100644 --- a/code/modules/heavy_vehicle/premade/cult.dm +++ b/code/modules/heavy_vehicle/premade/cult.dm @@ -24,7 +24,7 @@ icon_state = "cult_arms" melee_damage = 50 action_delay = 5 - max_damage = 90 + max_damage = 135 power_use = 3500 punch_sound = 'sound/mecha/mech_punch_slow.ogg' diff --git a/code/modules/heavy_vehicle/premade/heavy.dm b/code/modules/heavy_vehicle/premade/heavy.dm index 5757bd6a2dc..43590de0fb2 100644 --- a/code/modules/heavy_vehicle/premade/heavy.dm +++ b/code/modules/heavy_vehicle/premade/heavy.dm @@ -20,7 +20,7 @@ desc = "Designed to function where any other piece of equipment would have long fallen apart, the Hephaestus Superheavy Lifter series can take a beating and excel at delivering it." melee_damage = 50 action_delay = 15 - max_damage = 200 + max_damage = 300 power_use = 3500 punch_sound = 'sound/mecha/mech_punch_slow.ogg' diff --git a/code/modules/heavy_vehicle/premade/light.dm b/code/modules/heavy_vehicle/premade/light.dm index d69dafbc7f7..5678fa094d7 100644 --- a/code/modules/heavy_vehicle/premade/light.dm +++ b/code/modules/heavy_vehicle/premade/light.dm @@ -18,7 +18,7 @@ icon_state = "light_arms" melee_damage = 15 action_delay = 15 - max_damage = 100 + max_damage = 150 power_use = 1500 desc = "As flexible as they are fragile, these Bishop Cybernetics manipulators can follow a pilot's movements in close to real time." punch_sound = 'sound/mecha/mech_punch_fast.ogg' diff --git a/code/modules/heavy_vehicle/premade/military.dm b/code/modules/heavy_vehicle/premade/military.dm index 79d3f691d59..46943b76fc5 100644 --- a/code/modules/heavy_vehicle/premade/military.dm +++ b/code/modules/heavy_vehicle/premade/military.dm @@ -5,7 +5,7 @@ desc = "These basic, heavy plasteel mounts are used for mounting only the meanest weapons. Probably good at breaking things, too." melee_damage = 50 action_delay = 15 - max_damage = 4000 + max_damage = 900 power_use = 3500 has_hardpoints = list(HARDPOINT_LEFT_SHOULDER, HARDPOINT_RIGHT_SHOULDER) punch_sound = 'sound/mecha/mech_punch_slow.ogg' diff --git a/code/modules/heavy_vehicle/premade/powerloader.dm b/code/modules/heavy_vehicle/premade/powerloader.dm index bd788417190..e96afd9c827 100644 --- a/code/modules/heavy_vehicle/premade/powerloader.dm +++ b/code/modules/heavy_vehicle/premade/powerloader.dm @@ -42,7 +42,7 @@ /obj/item/mech_component/manipulators/ripley name = "exosuit arms" exosuit_desc_string = "heavy-duty industrial lifters" - max_damage = 150 + max_damage = 225 power_use = 1000 melee_damage = 40 desc = "The Xion Manufacturing Group Digital Interaction Manifolds allow you poke untold dangers from the relative safety of your cockpit." diff --git a/code/modules/heavy_vehicle/premade/pra.dm b/code/modules/heavy_vehicle/premade/pra.dm index 8468fb05e7d..f724850bcdb 100644 --- a/code/modules/heavy_vehicle/premade/pra.dm +++ b/code/modules/heavy_vehicle/premade/pra.dm @@ -18,7 +18,7 @@ icon_state = "egg_arms" melee_damage = 15 action_delay = 5 - max_damage = 100 + max_damage = 150 power_use = 2500 has_hardpoints = list(HARDPOINT_RIGHT_HAND, HARDPOINT_LEFT_HAND) @@ -81,7 +81,7 @@ desc = "Armored robotics arms designed to carry large weapons." icon_state = "strong_egg_arms" melee_damage = 20 - max_damage = 120 + max_damage = 180 /obj/item/mech_component/sensors/pra_egg/armored name = "armored P'kus-3 sensors" diff --git a/html/changelogs/hellfirejag-mech-damage-feedback.yml b/html/changelogs/hellfirejag-mech-damage-feedback.yml new file mode 100644 index 00000000000..fca80e9e4e7 --- /dev/null +++ b/html/changelogs/hellfirejag-mech-damage-feedback.yml @@ -0,0 +1,9 @@ +author: Hellfirejag +delete-after: True +changes: + - rscadd: "Mech arms now have a chance to fail on use when damaged, which scales proportionally with said damage." + - balance: "Since damage to mech arms now matters, the max health of all mech arms has been increased by 50%." + - balance: "Nerfed Superheavy mech arms to be more in line with other Superheavy mech components." + - rscadd: "Mech arms and legs now have a chance to create electrical sparks when utilized while damaged. This provides visual and audible feedback for a mech being damaged." + - rscadd: "Ejecting from a mech or opening its canopy now has a chance to fail loudly based on how much damage its center torso has taken." + - rscadd: "Added sound effects to mechs for opening and closing hatches, toggling the hatch lock, and for toggling the mech's air supply."