From 2442f893e3d21f80c2383a7083a6ceba734ae715 Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:28:16 -0800 Subject: [PATCH] Fix m56d and m2c crushing, labeling, and damage retention (#5481) # About the pull request This PR addresses 5 things regarding the m56d and m2c: 1. Both now properly retain labeler labels (though technically the m56d post can lose its label - gun takes priority) 2. The m56d now retains its damage when disassembled 3. The m56d's post now has an implementation for handle_charge_collision so they can croosh not fully assembled guns 4. It appeared possible to duplicate the m56d when a charger crushed it if it both was destroyed by the impact and the update_health resulted in the gun being refunded; this is no longer possible since the charge logic returns early if it is destroyed 5. Vehicles running over a m56d post now undeploys the m56d correctly if it had a gun attached (it would downgrade to just a post) # Explain why it's good for the game Fixes #5477 but I don't think this *ever* worked. Rather the issue is purely when the gun is in this state: ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/c72209b5-07da-46ac-adaf-c202bff4489e) Additionally, if we're going to have a mechanic to weld to fix the gun; you shouldn't be able to circumvent this by simply disassembling it... However, since the destruction of the m56d didn't have a guaranteed chance to destroy the gun, technically this results in a fully repaired gun again if you can make another post for it. It would need to work more like the m2c if we wanted it to remain in a broken state in this situation. # Testing Photographs and Procedure https://youtu.be/rg1mLFjhsEY (though I forgot to record crowbar disassembly for the m56d too) # Changelog :cl: Drathek fix: The M56D and the M2C now retain their labels when disassembled fix: The M56D can now be charger crushed when not fully assembled fix: The M56D being run over by a vehicle now undeploys the gun correctly (so it retains the gun if it had a gun) fix: Fix an edge case that could duplicate the M56D when charger crushed balance: The M56D now retains the health of the gun through all of its different disassembled states /:cl: --- code/modules/cm_marines/m2c.dm | 34 ++--- code/modules/cm_marines/smartgun_mount.dm | 88 ++++++++----- .../mutators/strains/crusher/charger.dm | 117 ++++++++++++------ .../vehicles/multitile/multitile_bump.dm | 20 ++- 4 files changed, 169 insertions(+), 90 deletions(-) diff --git a/code/modules/cm_marines/m2c.dm b/code/modules/cm_marines/m2c.dm index 4001e72b02f3..dea7d80b50f9 100644 --- a/code/modules/cm_marines/m2c.dm +++ b/code/modules/cm_marines/m2c.dm @@ -131,20 +131,21 @@ if(!check_can_setup(user, rotate_check, OT, ACR)) return - var/obj/structure/machinery/m56d_hmg/auto/M = new /obj/structure/machinery/m56d_hmg/auto(user.loc) - transfer_label_component(M) - M.setDir(user.dir) // Make sure we face the right direction - M.anchored = TRUE - playsound(M, 'sound/items/m56dauto_setup.ogg', 75, TRUE) - to_chat(user, SPAN_NOTICE("You deploy [M].")) - M.rounds = rounds - M.overheat_value = overheat_value - M.health = health - M.update_icon() + var/obj/structure/machinery/m56d_hmg/auto/HMG = new(user.loc) + transfer_label_component(HMG) + HMG.setDir(user.dir) // Make sure we face the right direction + HMG.anchored = TRUE + playsound(HMG, 'sound/items/m56dauto_setup.ogg', 75, TRUE) + to_chat(user, SPAN_NOTICE("You deploy [HMG].")) + HMG.rounds = rounds + HMG.overheat_value = overheat_value + HMG.health = health + HMG.update_damage_state() + HMG.update_icon() qdel(src) - if(M.rounds > 0) - M.try_mount_gun(user) + if(HMG.rounds > 0) + HMG.try_mount_gun(user) /obj/item/device/m2c_gun/attackby(obj/item/O as obj, mob/user as mob) if(!ishuman(user)) @@ -313,12 +314,13 @@ if(health <= 0) playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1) visible_message(SPAN_WARNING("[src] has broken down completely!")) - var/obj/item/device/m2c_gun/HMG = new(src.loc) + var/obj/item/device/m2c_gun/HMG = new(loc) HMG.rounds = rounds HMG.broken_gun = TRUE HMG.unacidable = FALSE HMG.health = 0 HMG.update_icon() + transfer_label_component(HMG) qdel(src) return @@ -475,10 +477,10 @@ return user.visible_message(SPAN_NOTICE("[user] disassembles [src]."),SPAN_NOTICE("You fold up the tripod for [src], disassembling it.")) playsound(src.loc, 'sound/items/m56dauto_setup.ogg', 75, 1) - var/obj/item/device/m2c_gun/HMG = new(src.loc) + var/obj/item/device/m2c_gun/HMG = new(loc) transfer_label_component(HMG) - HMG.rounds = src.rounds - HMG.overheat_value = round(0.5 * src.overheat_value) + HMG.rounds = rounds + HMG.overheat_value = round(0.5 * overheat_value) if (HMG.overheat_value <= 10) HMG.overheat_value = 0 HMG.update_icon() diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index dbfdf03e0b76..7cb3b4fa051b 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -137,14 +137,15 @@ to_chat(user, SPAN_WARNING("This is too close to [machine]!")) return - var/obj/structure/machinery/m56d_post/M = new /obj/structure/machinery/m56d_post(user.loc) - M.setDir(user.dir) // Make sure we face the right direction - M.gun_rounds = src.rounds //Inherit the amount of ammo we had. - M.gun_mounted = TRUE - M.anchored = TRUE - M.update_icon() - transfer_label_component(M) - to_chat(user, SPAN_NOTICE("You deploy \the [src].")) + var/obj/structure/machinery/m56d_post/post = new(user.loc) + post.setDir(user.dir) // Make sure we face the right direction + post.gun_rounds = rounds + post.gun_mounted = TRUE + post.gun_health = health // retain damage + post.anchored = TRUE + post.update_icon() + transfer_label_component(post) + to_chat(user, SPAN_NOTICE("You deploy [src].")) qdel(src) @@ -223,8 +224,8 @@ return to_chat(user, SPAN_NOTICE("You deploy \the [src].")) - var/obj/structure/machinery/m56d_post/M = new /obj/structure/machinery/m56d_post(user.loc) - transfer_label_component(M) + var/obj/structure/machinery/m56d_post/post = new(user.loc) + transfer_label_component(post) qdel(src) @@ -238,8 +239,12 @@ density = TRUE layer = ABOVE_MOB_LAYER projectile_coverage = PROJECTILE_COVERAGE_LOW - var/gun_mounted = FALSE //Has the gun been mounted? - var/gun_rounds = 0 //Did the gun come with any ammo? + ///Whether a gun is mounted + var/gun_mounted = FALSE + ///Ammo amount of the mounted gun + var/gun_rounds = 0 + ///Health of the mounted gun + var/gun_health = 0 health = 50 /obj/structure/machinery/m56d_post/initialize_pass_flags(datum/pass_flags_container/PF) @@ -302,8 +307,9 @@ to_chat(user, SPAN_WARNING("\The [src] can't be folded while screwed to the floor. Unscrew it first.")) return to_chat(user, SPAN_NOTICE("You fold [src].")) - var/obj/item/device/m56d_post/P = new(loc) - user.put_in_hands(P) + var/obj/item/device/m56d_post/post = new(loc) + transfer_label_component(post) + user.put_in_hands(post) qdel(src) /obj/structure/machinery/m56d_post/attackby(obj/item/O, mob/user) @@ -331,6 +337,8 @@ user.visible_message(SPAN_NOTICE("[user] installs [MG] into place."),SPAN_NOTICE("You install [MG] into place.")) gun_mounted = 1 gun_rounds = MG.rounds + gun_health = MG.health + MG.transfer_label_component(src) update_icon() user.temp_drop_inv_item(MG) qdel(MG) @@ -343,12 +351,19 @@ to_chat(user, "You begin dismounting [src]'s gun...") if(do_after(user, 30 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD) && gun_mounted) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) - user.visible_message(SPAN_NOTICE("[user] removes [src]'s gun."),SPAN_NOTICE("You remove [src]'s gun.")) - var/obj/item/device/m56d_gun/G = new(loc) - G.rounds = gun_rounds - G.update_icon() + user.visible_message(SPAN_NOTICE("[user] removes [src]'s gun."), SPAN_NOTICE("You remove [src]'s gun.")) + var/obj/item/device/m56d_gun/HMG = new(loc) + HMG.rounds = gun_rounds + if(gun_health) + HMG.health = gun_health + HMG.update_icon() + transfer_label_component(HMG) + var/datum/component/label/label = GetComponent(/datum/component/label) + if(label) + label.remove_label() gun_mounted = FALSE gun_rounds = 0 + gun_health = 0 update_icon() return @@ -389,13 +404,16 @@ var/disassemble_time = 30 if(do_after(user, disassemble_time * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) playsound(src.loc, 'sound/items/Deconstruct.ogg', 25, 1) - user.visible_message(SPAN_NOTICE("[user] screws the M56D into the mount."),SPAN_NOTICE("You finalize the M56D heavy machine gun.")) - var/obj/structure/machinery/m56d_hmg/G = new(src.loc) //Here comes our new turret. - transfer_label_component(G) - G.visible_message("[icon2html(G, viewers(src))] \The [G] is now complete!") //finished it for everyone to - G.setDir(dir) //make sure we face the right direction - G.rounds = src.gun_rounds //Inherent the amount of ammo we had. - G.update_icon() + user.visible_message(SPAN_NOTICE("[user] screws the M56D into the mount."), SPAN_NOTICE("You finalize the M56D heavy machine gun.")) + var/obj/structure/machinery/m56d_hmg/HMG = new(loc) + transfer_label_component(HMG) + HMG.visible_message("[icon2html(HMG, viewers(src))] \The [HMG] is now complete!") + HMG.setDir(dir) + HMG.rounds = gun_rounds + if(gun_health) + HMG.health = gun_health + HMG.update_damage_state() + HMG.update_icon() qdel(src) else if(anchored) @@ -562,7 +580,7 @@ return else playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) - user.visible_message("[user] rotates \the [src].","You rotate \the [src].") + user.visible_message("[user] rotates [src].", "You rotate [src].") setDir(turn(dir, -90)) if(operator) update_pixels(operator) @@ -576,14 +594,15 @@ var/disassemble_time = 30 if(do_after(user, disassemble_time * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) - user.visible_message(SPAN_NOTICE(" [user] disassembles [src]! "),SPAN_NOTICE(" You disassemble [src]!")) + user.visible_message(SPAN_NOTICE("[user] disassembles [src]!"), SPAN_NOTICE("You disassemble [src]!")) playsound(src.loc, 'sound/items/Screwdriver.ogg', 25, 1) - var/obj/item/device/m56d_gun/HMG = new(src.loc) //Here we generate our disassembled mg. + var/obj/item/device/m56d_gun/HMG = new(loc) transfer_label_component(HMG) - HMG.rounds = src.rounds //Inherent the amount of ammo we had. + HMG.rounds = rounds HMG.has_mount = TRUE + HMG.health = health HMG.update_icon() - qdel(src) //Now we clean up the constructed gun. + qdel(src) return if(istype(O, /obj/item/ammo_magazine/m56d)) // RELOADING DOCTOR FREEMAN. @@ -595,7 +614,7 @@ if(user.action_busy) return if(!do_after(user, 25 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) return - user.visible_message(SPAN_NOTICE("[user] loads [src]! "),SPAN_NOTICE("You load [src]!")) + user.visible_message(SPAN_NOTICE("[user] loads [src]!"), SPAN_NOTICE("You load [src]!")) playsound(loc, 'sound/weapons/gun_minigun_cocked.ogg', 25, 1) if(rounds) var/obj/item/ammo_magazine/m56d/D = new(user.loc) @@ -638,10 +657,10 @@ if(health <= 0) var/destroyed = rand(0,1) //Ammo cooks off or something. Who knows. playsound(src.loc, 'sound/items/Welder2.ogg', 25, 1) - if(!destroyed) new /obj/structure/machinery/m56d_post(loc) - else + if(!destroyed) var/obj/item/device/m56d_gun/HMG = new(loc) - HMG.rounds = src.rounds //Inherent the amount of ammo we had. + transfer_label_component(HMG) + HMG.rounds = rounds qdel(src) return @@ -981,6 +1000,7 @@ to_chat(operator, SPAN_HIGHDANGER("You are knocked off the gun by the sheer force of the ram!")) operator.unset_interaction() operator.apply_effect(3, WEAKEN) + operator.emote("pain") /// Getter for burst_firing /obj/structure/machinery/m56d_hmg/proc/get_burst_firing() diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/crusher/charger.dm b/code/modules/mob/living/carbon/xenomorph/mutators/strains/crusher/charger.dm index 1fc746829acd..17b5cf62052c 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/crusher/charger.dm +++ b/code/modules/mob/living/carbon/xenomorph/mutators/strains/crusher/charger.dm @@ -346,8 +346,8 @@ take_overall_armored_damage(charger_ability.momentum * momentum_mult, ARMOR_MELEE, BRUTE, 60, 13) // Giving AP because this spreads damage out and then applies armor to them apply_armoured_damage(charger_ability.momentum * momentum_mult/4, ARMOR_MELEE, BRUTE,"chest") xeno.visible_message( - SPAN_DANGER("[xeno] rams \the [src]!"), - SPAN_XENODANGER("You ram \the [src]!") + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") ) var/knockdown = 1 if(charger_ability.momentum == charger_ability.max_momentum) @@ -417,8 +417,8 @@ momentum_mult = 8 take_overall_damage(charger_ability.momentum * momentum_mult) xeno.visible_message( - SPAN_DANGER("[xeno] rams \the [src]!"), - SPAN_XENODANGER("You ram \the [src]!") + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") ) var/knockdown = 1 if(charger_ability.momentum == charger_ability.max_momentum) @@ -470,8 +470,8 @@ var/datum/effect_system/spark_spread/sparks = new sparks.set_up(5, 1, loc) xeno.visible_message( - SPAN_DANGER("[xeno] rams \the [src]!"), - SPAN_XENODANGER("You ram \the [src]!") + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") ) if(health <= CHARGER_DAMAGE_SENTRY) new /obj/effect/spawner/gibspawner/robot(src.loc) // if we goin down ,we going down with a show. @@ -488,37 +488,78 @@ // Marine MGs /obj/structure/machinery/m56d_hmg/handle_charge_collision(mob/living/carbon/xenomorph/xeno, datum/action/xeno_action/onclick/charger_charge/charger_ability) - if(charger_ability.momentum > CCA_MOMENTUM_LOSS_MIN) - CrusherImpact() - var/datum/effect_system/spark_spread/sparks = new - update_health(charger_ability.momentum * 15) - if(operator) operator.emote("pain") - sparks.set_up(1, 1, loc) - sparks.start() - xeno.visible_message( - SPAN_DANGER("[xeno] rams \the [src]!"), - SPAN_XENODANGER("You ram \the [src]!") - ) - playsound(src, "sound/effects/metal_crash.ogg", 25, TRUE) - if(istype(src,/obj/structure/machinery/m56d_hmg/auto)) // we don't want to charge it to the point of downgrading it (: - var/obj/item/device/m2c_gun/HMG = new(src.loc) - HMG.health = src.health - transfer_label_component(HMG) - HMG.rounds = src.rounds //Inherent the amount of ammo we had. - HMG.update_icon() - qdel(src) - else - var/obj/item/device/m56d_gun/HMG = new(src.loc) // note: find a better way than a copy pasted else statement - HMG.health = src.health - transfer_label_component(HMG) - HMG.rounds = src.rounds //Inherent the amount of ammo we had. - HMG.has_mount = TRUE - HMG.update_icon() - qdel(src) //Now we clean up the constructed gun. + if(charger_ability.momentum <= CCA_MOMENTUM_LOSS_MIN) + charger_ability.stop_momentum() + return + + CrusherImpact() + update_health(charger_ability.momentum * 15) + var/datum/effect_system/spark_spread/sparks = new + sparks.set_up(1, 1, loc) + sparks.start() + xeno.visible_message( + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") + ) + playsound(src, "sound/effects/metal_crash.ogg", 25, TRUE) + if(QDELETED(src)) + // The crash destroyed it charger_ability.lose_momentum(CCA_MOMENTUM_LOSS_MIN) //Lose one turfs worth of speed return XENO_CHARGE_TRY_MOVE - charger_ability.stop_momentum() + + // Undeploy + if(istype(src, /obj/structure/machinery/m56d_hmg/auto)) // we don't want to charge it to the point of downgrading it (: + var/obj/item/device/m2c_gun/HMG = new(loc) + HMG.health = health + transfer_label_component(HMG) + HMG.rounds = rounds + HMG.update_icon() + qdel(src) + else + var/obj/item/device/m56d_gun/HMG = new(loc) + HMG.health = health + transfer_label_component(HMG) + HMG.rounds = rounds + HMG.has_mount = TRUE + HMG.update_icon() + qdel(src) //Now we clean up the constructed gun. + +/obj/structure/machinery/m56d_post/handle_charge_collision(mob/living/carbon/xenomorph/xeno, datum/action/xeno_action/onclick/charger_charge/charger_ability) + if(charger_ability.momentum <= CCA_MOMENTUM_LOSS_MIN) + charger_ability.stop_momentum() + return + + update_health(charger_ability.momentum * 15) + var/datum/effect_system/spark_spread/sparks = new + sparks.set_up(1, 1, loc) + sparks.start() + xeno.visible_message( + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") + ) + playsound(src, "sound/effects/metal_crash.ogg", 25, TRUE) + + if(QDELETED(src)) + // The crash destroyed it + charger_ability.lose_momentum(CCA_MOMENTUM_LOSS_MIN) //Lose one turfs worth of speed + return XENO_CHARGE_TRY_MOVE + + // Undeploy + if(gun_mounted) + var/obj/item/device/m56d_gun/HMG = new(loc) + transfer_label_component(HMG) + HMG.rounds = gun_rounds + HMG.has_mount = TRUE + if(gun_health) + HMG.health = gun_health + HMG.update_icon() + qdel(src) + else + var/obj/item/device/m56d_post/post = new(loc) + post.health = health + transfer_label_component(post) + qdel(src) // Prison Windows @@ -549,8 +590,8 @@ charger_ability.stop_momentum() return xeno.visible_message( - SPAN_DANGER("[xeno] rams \the [src]!"), - SPAN_XENODANGER("You ram \the [src]!") + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") ) playsound(src, "sound/effects/metalhit.ogg", 25, TRUE) qdel(src) @@ -569,8 +610,8 @@ charger_ability.stop_momentum() return xeno.visible_message( - SPAN_DANGER("[xeno] rams \the [src]!"), - SPAN_XENODANGER("You ram \the [src]!") + SPAN_DANGER("[xeno] rams [src]!"), + SPAN_XENODANGER("You ram [src]!") ) playsound(src, "sound/effects/metalhit.ogg", 25, TRUE) qdel(src) diff --git a/code/modules/vehicles/multitile/multitile_bump.dm b/code/modules/vehicles/multitile/multitile_bump.dm index 48706805948f..79789af054fa 100644 --- a/code/modules/vehicles/multitile/multitile_bump.dm +++ b/code/modules/vehicles/multitile/multitile_bump.dm @@ -341,10 +341,24 @@ return TRUE /obj/structure/machinery/m56d_post/handle_vehicle_bump(obj/vehicle/multitile/V) - new /obj/item/device/m56d_post(loc) playsound(V, 'sound/effects/metal_crash.ogg', 20) visible_message(SPAN_DANGER("\The [V] drives over \the [src]!")) - qdel(src) + + if(gun_mounted) + var/obj/item/device/m56d_gun/HMG = new(loc) + transfer_label_component(HMG) + HMG.rounds = gun_rounds + HMG.has_mount = TRUE + if(gun_health) + HMG.health = gun_health + HMG.update_icon() + qdel(src) + else + var/obj/item/device/m56d_post/post = new(loc) + post.health = health + transfer_label_component(post) + qdel(src) + return TRUE /obj/structure/machinery/m56d_hmg/handle_vehicle_bump(obj/vehicle/multitile/V) @@ -352,7 +366,9 @@ HMG.name = name HMG.rounds = rounds HMG.has_mount = TRUE + HMG.health = health HMG.update_icon() + transfer_label_component(HMG) playsound(V, 'sound/effects/metal_crash.ogg', 20) visible_message(SPAN_DANGER("\The [V] drives over \the [src]!")) qdel(src)