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)