From 29bc02f44ec4f9c701c9bc9e94cf304d44dbcf5b Mon Sep 17 00:00:00 2001 From: Casper3667 <8396443+Casper3667@users.noreply.github.com> Date: Wed, 27 May 2026 17:39:42 +0200 Subject: [PATCH] Various bullet fixes and changes (#22503) fixes https://github.com/Aurorastation/Aurora.3/issues/22370 and https://github.com/Aurorastation/Aurora.3/issues/22475 I decided to lower the amount of bullets to increase the item pile, as otherwise removing a single shotgun shell from a pile would be enough to reduce its size, and that felt wrong. - rscadd: "Added the ability to stack spent bullet casings." - balance: "Ammo piles now increase in size the second time when there is 6 items in the pile, rather than 8" - bugfix: "Fixed bullet casings being ejected when trying to suicide with a gun on safety." - bugfix: "Fixed that bullet piles didn't update their size correctly." - bugfix: "Fixed that shotgun practice shells were labelled incorrectly in the autolathe." - bugfix: "Singular bullets no longer layer under tables." --- .../designs/general/designs_ammo.dm | 2 +- code/modules/projectiles/ammunition.dm | 7 +-- .../projectiles/ammunition/ammo_pile.dm | 56 ++++++++++++++----- code/modules/projectiles/gun.dm | 28 +++++----- html/changelogs/AmmoFixes.yml | 11 ++++ 5 files changed, 73 insertions(+), 31 deletions(-) create mode 100644 html/changelogs/AmmoFixes.yml diff --git a/code/modules/fabrication/designs/general/designs_ammo.dm b/code/modules/fabrication/designs/general/designs_ammo.dm index 3e51bac762e..105edd1718f 100644 --- a/code/modules/fabrication/designs/general/designs_ammo.dm +++ b/code/modules/fabrication/designs/general/designs_ammo.dm @@ -50,7 +50,7 @@ ABSTRACT_TYPE(/singleton/fabricator_recipe/ammunition) security_level = SEC_LEVEL_RED /singleton/fabricator_recipe/ammunition/shotgun/practice - name = "shells (buckshot, shotgun)" + name = "shells (practice, shotgun)" path = /obj/item/ammo_pile/shotgun_practice // Revolvers diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index b4e717700f6..577d7463efb 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -7,7 +7,6 @@ obj_flags = OBJ_FLAG_CONDUCTABLE slot_flags = SLOT_BELT | SLOT_EARS throwforce = 1 - layer = BELOW_TABLE_LAYER w_class = WEIGHT_CLASS_TINY var/leaves_residue = 1 @@ -69,11 +68,11 @@ if(max_stack == 1) to_chat(user, SPAN_WARNING("\The [src] cannot be stacked!")) return - if(!src.BB) + var/obj/item/ammo_casing/B = attacking_item + if(!src.BB && B.BB) to_chat(user, SPAN_WARNING("That round is spent!")) return - var/obj/item/ammo_casing/B = attacking_item - if(!B.BB) + if(!B.BB && src.BB) to_chat(user, SPAN_WARNING("Your round is spent!")) return var/obj/item/ammo_pile/pile = new /obj/item/ammo_pile(get_turf(user), list(src, attacking_item)) diff --git a/code/modules/projectiles/ammunition/ammo_pile.dm b/code/modules/projectiles/ammunition/ammo_pile.dm index d0158b1bfcf..481b9247a27 100644 --- a/code/modules/projectiles/ammunition/ammo_pile.dm +++ b/code/modules/projectiles/ammunition/ammo_pile.dm @@ -7,6 +7,7 @@ var/list/image/ammo_overlays = list() var/ammo_type // the type of ammo this ammo pile accepts var/max_ammo = 5 + var/spent_ammo = FALSE /obj/item/ammo_pile/Destroy() QDEL_LIST(ammo) @@ -21,20 +22,26 @@ /obj/item/ammo_pile/Initialize(mapload, var/list/provided_ammo) . = ..() if(islist(provided_ammo)) - var/obj/first_round = provided_ammo[1] + if(!istype(provided_ammo[1], /obj/item/ammo_casing)) + return + var/obj/item/ammo_casing/first_round = provided_ammo[1] add_ammo(first_round) check_name_and_ammo() + if(!first_round.BB) + spent_ammo = TRUE provided_ammo -= first_round - for(var/obj/rounds in provided_ammo) + for(var/obj/item/ammo_casing/rounds in provided_ammo) add_ammo(rounds) else if(ammo_type) - var/obj/first_round = new ammo_type() + var/obj/item/ammo_casing/first_round = new ammo_type() add_ammo(first_round) check_name_and_ammo() + if(!first_round.BB) + spent_ammo = TRUE for(var/i = 1, i <= max_ammo - 1, i++) - var/obj/C = new ammo_type() + var/obj/item/ammo_casing/C = new ammo_type() add_ammo(C) - addtimer(CALLBACK(src, PROC_REF(check_ammo)), 5) // if we don't have any ammo in 5 deciseconds, we're an empty pile, which is worthless, so self-delete + check_ammo() /obj/item/ammo_pile/attack(mob/living/target_mob, mob/living/user, target_zone) return @@ -50,11 +57,18 @@ to_chat(user, SPAN_WARNING("\The [src] is already fully stacked.")) return var/obj/item/ammo_casing/B = A - if(!B.BB) + if(!B.BB && !spent_ammo) to_chat(user, SPAN_WARNING("\The [B] is spent!")) return + if(B.BB && spent_ammo) + to_chat(user, SPAN_WARNING("\The [src] is spent!")) + return to_chat(user, SPAN_NOTICE("You add \the [A] to \the [src].")) add_ammo(A) + return + else if(istype(A, /obj/item/ammo_casing)) + to_chat(user, SPAN_WARNING("\The [A] has a different type of ammunition!")) + return else if(istype(A, /obj/item/ammo_pile)) if(length(ammo) >= max_ammo) to_chat(user, SPAN_WARNING("\The [src] is already fully stacked.")) @@ -63,6 +77,12 @@ if(target_pile.ammo_type != src.ammo_type) to_chat(user, SPAN_WARNING("\The [target_pile] has a different type of ammunition!")) return + if(target_pile.spent_ammo && !spent_ammo) + to_chat(user, SPAN_WARNING("\The [target_pile] is spent!")) + return + if(!target_pile.spent_ammo && spent_ammo) + to_chat(user, SPAN_WARNING("\The [src] is spent!")) + return var/amount_taken = 0 for(var/obj/bullet in target_pile.ammo) if(length(src.ammo) >= src.max_ammo) @@ -71,11 +91,14 @@ target_pile.remove_ammo() amount_taken++ to_chat(user, SPAN_NOTICE("You take [amount_taken] rounds from the other pile and add it to yours.")) + return else if(istype(A, /obj/item/gun) || istype(A, /obj/item/ammo_magazine)) var/obj/bullet = get_next_ammo() A.attackby(bullet, user) - if(!(bullet in src)) // if the gun / mag accepted the bullet, it will no longer be in our pile + // if the gun / mag accepted the bullet, it will no longer be in our pile + if(!(bullet in src)) remove_ammo() + return /obj/item/ammo_pile/attackby(obj/item/attacking_item, mob/user) if(istype(attacking_item, /obj/item/ammo_casing)) @@ -86,8 +109,11 @@ to_chat(user, SPAN_WARNING("\The [src] is already fully stacked.")) return TRUE var/obj/item/ammo_casing/B = attacking_item - if(!B.BB) - to_chat(user, SPAN_WARNING("\The [B] is spent!")) + if(!B.BB && !spent_ammo) + to_chat(user, SPAN_WARNING("Your round is spent!")) + return TRUE + else if(B.BB && spent_ammo) + to_chat(user, SPAN_WARNING("\The [src] is spent!")) return TRUE to_chat(user, SPAN_NOTICE("You add \the [attacking_item] to \the [src].")) add_ammo(attacking_item) @@ -110,7 +136,8 @@ ammo_type = first_round.type max_ammo = first_round.max_stack -/obj/item/ammo_pile/proc/get_next_ammo() //Returns the next shell to be used. +/// Returns the next shell to be used. +/obj/item/ammo_pile/proc/get_next_ammo() if(!length(ammo)) qdel(src) return null @@ -121,8 +148,9 @@ var/ammo_amount = length(ammo) if(ammo_amount > 1) var/obj/first_round = ammo[1] - if(ammo_amount > 7) - w_class = first_round.w_class + 2 // too many to fit in your pockets, generally + if(ammo_amount >= 6) + // too many to fit in your pockets, generally + w_class = first_round.w_class + 2 else w_class = first_round.w_class + 1 return @@ -141,7 +169,7 @@ gunman.put_in_hands(bullet) /obj/item/ammo_pile/proc/add_ammo(var/obj/item/ammo_casing/bullet) - if(!bullet.BB) + if((!bullet.BB && !spent_ammo) && (bullet.BB && spent_ammo)) return RegisterSignal(bullet, COMSIG_QDELETING, PROC_REF(clear_ammo)) if(ismob(bullet.loc)) @@ -157,6 +185,8 @@ ammo_picture.pixel_y = rand(-6, 6) ammo_overlays[bullet] = ammo_picture AddOverlays(ammo_overlays[bullet]) + if(length(ammo) >= 2) + check_ammo() /// Called when one of our contained bullets is qdel'd -- why does this happen? it is a mystery /obj/item/ammo_pile/proc/clear_ammo(datum/source) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c72e142781d..daa3d99b23c 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -702,21 +702,23 @@ ABSTRACT_TYPE(/obj/item/gun) M.visible_message(SPAN_GOOD("\The [user] takes \the [src] out of their mouth.")) mouthshoot = FALSE return + + user.visible_message(SPAN_DANGER("\The [user] pulls the trigger.")) + if (!pin && needspin) // Checks the pin of the gun. + handle_click_empty(user) + mouthshoot = FALSE + return + else if (!pin.pin_auth() && needspin) + handle_click_empty(user) + mouthshoot = FALSE + return + else if(safety() && user.a_intent != I_HURT) + handle_click_empty(user) + mouthshoot = FALSE + return + var/obj/projectile/in_chamber = consume_next_projectile() if(istype(in_chamber)) - user.visible_message(SPAN_DANGER("\The [user] pulls the trigger.")) - if (!pin && needspin) // Checks the pin of the gun. - handle_click_empty(user) - mouthshoot = FALSE - return - if (!pin.pin_auth() && needspin) - handle_click_empty(user) - mouthshoot = FALSE - return - if(safety() && user.a_intent != I_HURT) - handle_click_empty(user) - mouthshoot = FALSE - return play_fire_sound() in_chamber.on_hit(M) diff --git a/html/changelogs/AmmoFixes.yml b/html/changelogs/AmmoFixes.yml new file mode 100644 index 00000000000..c82485c15fe --- /dev/null +++ b/html/changelogs/AmmoFixes.yml @@ -0,0 +1,11 @@ +author: TheGreyWolf + +delete-after: True + +changes: + - rscadd: "Added the ability to stack spent bullet casings." + - balance: "Ammo piles now increase in size the second time when there is 6 items in the pile, rather than 8" + - bugfix: "Fixed bullet casings being ejected when trying to suicide with a gun on safety." + - bugfix: "Fixed that shotgun shell piles didn't update their size correctly." + - bugfix: "Fixed that shotgun practice shells were labelled incorrectly in the autolathe." + - bugfix: "Singular bullets no longer layer under tables."