From 57e46b4c9c0be642a166b7170bb2f9ab3e08ea08 Mon Sep 17 00:00:00 2001 From: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Date: Fri, 3 Apr 2026 10:33:26 -0400 Subject: [PATCH] Pneumatic Cannons can now be placed on tables and some cleanup/QOL. (#95571) ## About The Pull Request The Pneumatic Cannon: ~~god's greatest mistake~~ On live there's current a bug, almost certainly attack chain-based causing the cannon to be unable to be placed on tables. This most often occurs with the clown's pie cannon, as it will always try and fire at the table instead of putting it down. This PR corrects this by adding a small intermediary proc similar to the ones guns use in order to verify some of the conditions that could prevent you from firing the pneumatic cannon, while still letting you fire point blank at another mob. Additionally, Autodocs some variables, as well as axing a variable that was doing quite literally nothing that another variable was already doing. Finally, cleans up some of the logic on `examine()` for the cannon, such as not looping through 50 pies that an automatic pie cannon can hold, and cleaning up some magic numbers a bit with some self explanatory logic regarding combined weight on self-charging pneumatic cannons. ## Why It's Good For The Game Cleans up some attack chain code, and allows for everyone favorite non-gun gun to behave in a similar way to a gun that we'd all expect. Also, makes the examine text a bit more useful, such as displaying the contents of the cannon in a way that doesn't require a CHECK_TICK for something that can only hold pies. Lastly, cleans up most of the var documentation because it's my pet peeve ## Changelog :cl: qol: The pneumatic cannon's examine will now show the contents of the cannon loaded. fix: You may now place a pneumatic cannon (and the clown's pie cannon!) onto tables. /:cl: --- .../items/weaponry/ranged/pneumatic_cannon.dm | 72 +++++++++++++------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/code/game/objects/items/weaponry/ranged/pneumatic_cannon.dm b/code/game/objects/items/weaponry/ranged/pneumatic_cannon.dm index 8ea0ee60b67..508bb2d3f72 100644 --- a/code/game/objects/items/weaponry/ranged/pneumatic_cannon.dm +++ b/code/game/objects/items/weaponry/ranged/pneumatic_cannon.dm @@ -1,7 +1,11 @@ +/// Fire all loaded contents at once. #define PCANNON_FIREALL 1 +/// First in, Last out. #define PCANNON_FILO 2 +/// First in, first out. Default value. #define PCANNON_FIFO 3 + ///Defines for the pressure strength of the cannon #define LOW_PRESSURE 1 #define MID_PRESSURE 2 @@ -21,27 +25,40 @@ righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' armor_type = /datum/armor/item_pneumatic_cannon custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 6) - var/maxWeightClass = 20 //The max weight of items that can fit into the cannon - var/loadedWeightClass = 0 //The weight of items currently in the cannon - var/obj/item/tank/internals/tank = null //The gas tank that is drawn from to fire things - var/gasPerThrow = 3 //How much gas is drawn from a tank's pressure to fire - var/list/loadedItems = list() //The items loaded into the cannon that will be fired out - var/pressure_setting = LOW_PRESSURE //How powerful the cannon is - higher pressure = more gas but more powerful throws - var/checktank = TRUE + /// The max weight of items that can fit into the cannon + var/maxWeightClass = 20 + /// The weight of items currently in the cannon + var/loadedWeightClass = 0 + /// The gas tank that is drawn from to fire things + var/obj/item/tank/internals/tank = null + /// How much gas is drawn from a tank's pressure to fire + var/gasPerThrow = 3 + /// The items loaded into the cannon that will be fired out + var/list/loadedItems = list() + /// How powerful the cannon is - higher pressure = more gas but more powerful throws + var/pressure_setting = LOW_PRESSURE + /// Additional multiplier that adjusts how much farther thrown objects can travel. var/range_multiplier = 1 - var/throw_amount = 1 //How many items to throw per fire + /// How many items to throw per fire + var/throw_amount = 1 + /// What methodology should be used when firing? See #defines at top of file. var/fire_mode = PCANNON_FIFO + /// Allows you to hold down LMB to continuously fire. var/automatic = FALSE + /// Determines if a pneumatic cannon needs an air tank to fire. False for things like the pie cannons. var/needs_air = TRUE + /// If true, has side effects if fired with the clumsy trait (read: clowns) var/clumsyCheck = TRUE - var/list/allowed_typecache //Leave as null to allow all. + ///Leave as null to allow all. Otherwise whitelists what can be inserted into the cannon. + var/list/allowed_typecache var/charge_amount = 1 var/charge_ticks = 1 var/charge_tick = 0 - var/charge_type + var/atom/charge_type var/selfcharge = FALSE var/fire_sound = 'sound/items/weapons/sonic_jackhammer.ogg' - var/spin_item = TRUE //Do the projectiles spin when launched? + ///Do the projectiles spin when launched? + var/spin_item = TRUE trigger_guard = TRIGGER_GUARD_NORMAL @@ -86,9 +103,15 @@ if(!in_range(user, src)) out += span_notice("You'll need to get closer to see any more.") return - for(var/obj/item/I in loadedItems) - out += span_info("[icon2html(I, user)] It has \a [I] loaded.") - CHECK_TICK + if(selfcharge) + if(length(loadedItems)) + out += span_info("[icon2html(pick(loadedItems), user)] It has [length(loadedItems)] [charge_type::name] loaded.") + else + for(var/obj/item/I in loadedItems) + out += span_info("[icon2html(I, user)] It has \a [I] loaded.") + CHECK_TICK + if(!length(loadedItems)) + out += span_info("The chamber has nothing loaded.") if(tank) out += span_notice("[icon2html(tank, user)] It has \a [tank] mounted onto it. It could be removed with a screwdriver.") if(needs_air == TRUE) @@ -165,6 +188,8 @@ /obj/item/pneumatic_cannon/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(user.combat_mode) return ITEM_INTERACT_SKIP_TO_ATTACK + if(!pre_fire(user, interacting_with)) + return NONE Fire(user, interacting_with) return ITEM_INTERACT_SUCCESS @@ -172,6 +197,15 @@ Fire(user, interacting_with) return ITEM_INTERACT_SUCCESS +/** Checks */ +/obj/item/pneumatic_cannon/proc/pre_fire(mob/living/user, atom/target) + if(user.Adjacent(target)) + if(target in user.contents) + return FALSE + if(!ismob(target)) + return FALSE + return TRUE + /obj/item/pneumatic_cannon/proc/Fire(mob/living/user, atom/target) if(!istype(user) && !target) return @@ -181,7 +215,7 @@ if(!loadedItems || !loadedWeightClass) to_chat(user, span_warning("\The [src] has nothing loaded.")) return - if(!tank && checktank) + if(!tank && needs_air) to_chat(user, span_warning("\The [src] can't fire without a source of gas.")) return if(HAS_TRAIT(user, TRAIT_PACIFISM)) @@ -313,11 +347,9 @@ force = 10 icon_state = "piecannon" gasPerThrow = 0 - checktank = FALSE range_multiplier = 3 - fire_mode = PCANNON_FIFO throw_amount = 1 - maxWeightClass = 150 //50 pies. :^) + maxWeightClass = (/obj/item/food/pie::w_class * 50) //50 pies. :^) needs_air = FALSE clumsyCheck = FALSE var/static/list/pie_typecache = typecacheof(/obj/item/food/pie) @@ -330,13 +362,13 @@ automatic = TRUE selfcharge = TRUE charge_type = /obj/item/food/pie/cream - maxWeightClass = 60 //20 pies. + maxWeightClass = (/obj/item/food/pie::w_class * 20) //20 pies. /obj/item/pneumatic_cannon/pie/selfcharge/cyborg name = "low velocity pie cannon" automatic = FALSE charge_type = /obj/item/food/pie/cream/nostun - maxWeightClass = 6 //2 pies + maxWeightClass = (/obj/item/food/pie::w_class * 2) //2 pies charge_ticks = 2 //4 second/pie #undef PCANNON_FIREALL