Bigger Booms: Adds Pipe-Organ Gun and Canister Gatling, two emplaced weapons, along with Mounted Gun code. (#86390)

## About The Pull Request



![image](https://github.com/user-attachments/assets/f62c9c17-6886-4170-9e4c-144f9aa1792e)

So, as you may know, I really like the bootleg weaponry this game has,
but after dealing with gun code for the crossbow, I wasnt inclined to
make more of it. However, when I'm playing ss13 I often have background
noise on, and one day I was listening to an age of empires game, which,
if you aren't aware, is basically a medival rts, featuring a weapon
called an "organ gun". Said organ gun is basically 8 or so muskets stuck
together firing at once. And well, given SS13 has pipeguns, also called
muskets, I couldnt pass up the pun of "pipe organ gun." And thats why
this pr exists. However, as I am noticing I have a habit of doing, I
tend to end up coding more than I ever initially planned.

So what does it add? Well, lets start with the pipe organ gun.

<img width="428" alt="image"
src="https://github.com/user-attachments/assets/0cb93fb9-6ed3-4cb1-a340-0b54832ac577">

The pipe organ gun is made from wood, pipes, iron, typical maints weapon
stuff. Where it differs is it isn't a handheld object - it's a machine
you push and pull around akin to say, the pirate cannons. It can hold up
to 8 pipegun shells, and launches them all at once when lit with
anything that ignites stuff, like a welder, match, torch, etc. It does a
lot of damage, but requires time to reload, and a smart enemy can just
lie down and ignore it. Or maybe it'll just roll 8 of the really bad
ammo types and do nothing, who knows.


https://github.com/user-attachments/assets/5ee1353b-c965-4f47-aa22-4f5cfeb04c51

Initially I planned to use the cannon code as a base, but that presented
a lot of issues, as they need to use cannonballs (which arent ammo in
the traditonal sense), along with only being single shot among other
things. So I made an entire new type of structure called Mounted guns,
which are like cannons that can use conventional ballistic ammo, and
dont have any of the restrictions, and made to be customizable. You want
a gun that takes plasma bars as ammo and launches fireballs? it can do
that. You want to have a rebar ballista, that can shoot up to 3 rods at
once, but only needs to be loaded once? It can do that too. Hell, you
could probably just make full-on gun emplacements with some code
changes. If it's a projectile, it can shoot it, and if its an object, it
can use it as ammo. A list of the current stuff you can change is below.

<img width="510" alt="image"
src="https://github.com/user-attachments/assets/107abbc1-a004-4724-9627-a3388f92cd63">

Which leads me to the second gun I added, which is more of an example of
what can be done with the mounted_gun class.
The canister gatling spawns on the flying dutchman pirate ship, with
enough ammo for five shots.
<img width="453" alt="image"
src="https://github.com/user-attachments/assets/46fdc16e-813a-4e14-b25a-9cf49d245ca6">

Five shots may not sound like much at first - but thats because each
shot is a burst of 50 individual shrapnel bullets. It's unable to break
any walls or doors except for windows, but against anything that isnt a
structure... well, as shown below, they'll have a very bad day.


https://github.com/user-attachments/assets/3519c49d-97e6-4095-99cf-ee8039adbaba

If people like these concepts, I genuinely might add that engineering
rebar ballista.


## Why It's Good For The Game

As said above, I'm a big fan of the whole improvised armory concept ss13
has, and the fact the only "big" gun featured is the trash cannon (which
is locked behind maint loot) is a shame. I felt the pipe-organ gun was a
good compromise - as stated, its just eight pipeguns stuck together,
with all the strengths (high damage output) and weaknesses (slow reload,
needs to be dragged around, cant hit people on the floor, cant damage
walls) that it lacks. As for the canister gatling, I dont forsee it
being a massive problem, as it cant breach walls or doors, so it isn't
just a better cannon.

## Changelog
🆑 WebcomicArtist
add: Added pipe-organ gun: a buildable object akin to trash cannon that
takes pipegun rounds, and shoots up to 8 off at once.
add: Added The Canister Gatling, a rapid fire but non-destructive cannon
for skeleton pirates. Also Canister shot ammo.
sound: Added sounds for the above guns.
image: Added sprites for the guns as well.
code: Added a whole "mounted_gun" class that is basically cannons but
you aren't forced to use cannonballs as ammo and load them with
gunpowder.
/🆑
This commit is contained in:
KingkumaArt
2024-09-19 23:28:15 +02:00
committed by GitHub
parent 2b65a8e561
commit c4974b63ab
10 changed files with 238 additions and 3 deletions
@@ -17,4 +17,10 @@ REGULAR CANNONBALL: A fine choice for killing landlubbers! Will take off any lim
EXPLOSIVE SHELLBALL: The most elegant in breaching (er killin', if you're good at aimin') tools, ye be packing this shell with many scuppering chemicals! Just make sure to not fire it when ye be close to target!<br>
MALFUNCTION SHOT: A very gentle "cannonball" dart at first glance, but make no mistake: This is their worst nightmare! Enjoy an easy boarding process while all their machines are broken and all their weapons unloaded from an EMP!<br>
THE BIGGEST ONE: A shellball, but much bigger. Ye won't be seein' much of these as they were discontinued for sinkin' the firer's ship as often as it sunk the scallywag's ship. Very big boom! If ye have one, ye have been warned!
<br><center><b>FIRING THAR CANISTER GATLING</b><br></center>
THE CANISTER GATLING AIN'T LIKE OTHER CANNONS, AND DOESN'T REQUIRE GUNPOWDER, INSTEAD RELYING ON SPECIAL CANISTER SHOT SHELLS.
ALL YOU HAVE TO DO IS CRAM A SHELL IN THE BREACH, LIGHT HER UP AND YOU'LL BE BLOWING THOSE CORPORATE SODS TO KINGDOM COME!
SHE LACKS THE SHEER WALL-BREAKING PUNCH OF THE HOLEMAKERS, BUT CHEWS THROUGH SOFT TARGETS LIKE A SHARK THROUGH A GROUP OF BEACH THROUGH A GROUP OF BEACHGOERS, YAHAR.
"}
@@ -0,0 +1,187 @@
//Mounted guns are basically a smaller equivalent to cannons, designed to use pre-existing ammo rather than cannonballs.
//Due to using pre-existing ammo, they dont require to be loaded with gunpowder or an equivalent.
/obj/structure/mounted_gun
name = "Mounted Gun"
desc = "Default mounted gun for inheritance purposes."
density = TRUE
anchored = FALSE
icon = 'icons/obj/weapons/cannons.dmi'
icon_state = "falconet_patina"
var/icon_state_base = "falconet_patina"
var/icon_state_fire = "falconet_patina_fire"
max_integrity = 300
///whether the cannon can be unwrenched from the ground. Anchorable_cannon equivalent.
var/anchorable_gun = TRUE
///Max shots per firing of the gun.
var/max_shots_per_fire = 1
///Shots currently loaded. Should never be more than max_shots_per_fire.
var/shots_in_gun = 1
///shots added to gun, per piece of ammo loaded.
var/shots_per_load = 1
///Accepted "ammo" type
var/obj/item/ammo_type = /obj/item/ammo_casing/strilka310
///Projectile from said gun. Doesnt automatically inherit said ammo's projectile in case you wanted to make a gun that shoots floor tiles or something.
var/obj/item/projectile_type = /obj/projectile/bullet/strilka310
///If the gun has anything in it.
var/loaded_gun = TRUE
///If the gun is currently loaded with its maximum capacity.
var/fully_loaded_gun = TRUE
///delay in firing the gun after lighting
var/fire_delay = 5
///Delay between shots
var/shot_delay = 3
///If the gun shakes the camera when firing
var/firing_shakes_camera = TRUE
///sound of firing for all but last shot
var/fire_sound = 'sound/weapons/gun/general/mountedgun.ogg'
///sound of firing for last shot
var/last_fire_sound = 'sound/weapons/gun/general/mountedgunend.ogg'
/obj/structure/mounted_gun/wrench_act(mob/living/user, obj/item/tool)
. = ..()
if(!anchorable_gun) /// Can't anchor an unanchorable gun.
return FALSE
default_unfasten_wrench(user, tool)
return ITEM_INTERACT_SUCCESS
///Covers Reloading and lighting of the gun
/obj/structure/mounted_gun/attackby(obj/item/ammo_casing/used_item, mob/user, params)
var/ignition_message = used_item.ignition_effect(src, user) // Checks if item used can ignite stuff.
if(istype(used_item, ammo_type))
if(fully_loaded_gun)
balloon_alert(user, "already fully loaded!")
return
else
shots_in_gun = shots_in_gun + shots_per_load //Add one to the shots in the gun
loaded_gun = TRUE // Make sure it registers theres ammo in there, so it can fire.
QDEL_NULL(used_item)
if(shots_in_gun >= max_shots_per_fire)
shots_in_gun = max_shots_per_fire // in case of somehow firing only some of a guns shots, and reloading, you still cant get above the maximum ammo size.
fully_loaded_gun = TRUE //So you cant load extra.
return
else if(ignition_message) // if item the player used ignites, light the gun!
visible_message(ignition_message)
user.log_message("fired a cannon", LOG_ATTACK)
log_game("[key_name(user)] fired a cannon in [AREACOORD(src)]")
addtimer(CALLBACK(src, PROC_REF(fire)), fire_delay) //uses fire proc as shown below to shoot the gun
return
..()
/obj/structure/mounted_gun/proc/fire()
if (!loaded_gun)
balloon_alert_to_viewers("gun is not loaded!","",2)
return
for(var/times_fired = 1, times_fired <= shots_in_gun, times_fired++) //The normal DM for loop structure since the times it has fired is changing in the loop itself.
for(var/mob/shaken_mob in urange(10, src))
if(shaken_mob.stat == CONSCIOUS && firing_shakes_camera == TRUE)
shake_camera(shaken_mob, 3, 1)
icon_state = icon_state_fire
if(loaded_gun)
if (times_fired < shots_in_gun)
playsound(src, fire_sound, 50, FALSE, 5)
else
playsound(src, last_fire_sound, 50, TRUE, 5)
var/obj/projectile/fired_projectile = new projectile_type(get_turf(src))
fired_projectile.firer = src
fired_projectile.fired_from = src
fired_projectile.fire(dir2angle(dir))
sleep(shot_delay)
loaded_gun = FALSE
shots_in_gun = 0
fully_loaded_gun = FALSE
icon_state = icon_state_base
/obj/structure/mounted_gun/pipe
name = "Pipe Organ Gun"
desc = "To become master over one who has killed, one must become a better killer. This engine of destruction is one of many things made to that end."
icon_state = "pipeorgangun"
icon_state_base = "pipeorgangun"
icon_state_fire = "pipeorgangun_fire"
anchored = FALSE
anchorable_gun = TRUE
max_shots_per_fire = 8
shots_in_gun = 8
shots_per_load = 2
ammo_type = /obj/item/ammo_casing/junk
projectile_type = /obj/projectile/bullet/junk
loaded_gun = TRUE
fully_loaded_gun = TRUE
fire_delay = 3
shot_delay = 2
firing_shakes_camera = FALSE
/obj/structure/mounted_gun/pipe/examine_more(mob/user)
. = ..()
. += span_notice("<b><i>Looking down at the [name], you recall a tale told to you in some distant memory...</i></b>")
. += span_info("To commit an act of vengeance is not unlike to enter a blood pact with a devil, ending the life of another, at the cost of your own.")
. += span_info("When humanity first spilled the blood of its own kind, with likely nothing more than a rock, the seal was broken. Vengeance was borne unto the world.")
. += span_info("However, vengeance alone is not enough to carry through the grim deed of murder. One must an gain advantage over their adversary.")
. += span_info("As such, the man who ended another's life with a stone, was in turn smote himself by another wielding a spear. After spears, bows. Swords. Guns. Tanks. Missiles. And on and on Vengeance fed. Growing stronger. Growing Worse.")
. += span_info("Vengeance persists to this day. It sometimes may slumber, seemingly content with having gorged itself, but in the end, its ceaseless hunger can be neither numbed nor sated.")
/obj/structure/mounted_gun/pipe/fire()
if (!loaded_gun)
balloon_alert_to_viewers("Gun is not loaded!","",2)
return
for(var/times_fired = 1, times_fired <= shots_in_gun, times_fired++) //The normal DM for loop structure since the times it has fired is changing in the loop itself.
for(var/mob/shaken_mob in urange(10, src))
if((shaken_mob.stat == CONSCIOUS)&&(firing_shakes_camera == TRUE))
shake_camera(shaken_mob, 3, 1)
icon_state = icon_state_fire
if(loaded_gun)
playsound(src, fire_sound, 50, TRUE, 5)
var/list_of_projectiles = list(
/obj/projectile/bullet/junk = 40,
/obj/projectile/bullet/incendiary/fire/junk = 25,
/obj/projectile/bullet/junk/shock = 25,
/obj/projectile/bullet/junk/hunter = 20,
/obj/projectile/bullet/junk/phasic = 8,
/obj/projectile/bullet/junk/ripper = 8,
/obj/projectile/bullet/junk/reaper = 3,
)
projectile_type = pick_weight(list_of_projectiles)
var/obj/projectile/fired_projectile = new projectile_type(get_turf(src))
fired_projectile.firer = src
fired_projectile.fired_from = src
fired_projectile.fire(dir2angle(dir))
sleep(shot_delay)
loaded_gun = FALSE
shots_in_gun = 0
fully_loaded_gun = FALSE
icon_state = icon_state_base
/obj/structure/mounted_gun/canister_gatling //for the funny skeleton pirates!
name = "Canister Gatling Gun"
desc = "''Quantity has a quality of its own.''"
icon_state = "canister_gatling"
icon_state_base = "canister_gatling"
icon_state_fire = "canister_gatling_fire"
anchored = FALSE
anchorable_gun = TRUE
max_shots_per_fire = 50
shots_per_load = 50
shots_in_gun = 50
ammo_type = /obj/item/ammo_casing/canister_shot
projectile_type = /obj/projectile/bullet/shrapnel
loaded_gun = TRUE
fully_loaded_gun = TRUE
fire_delay = 3
shot_delay = 1
firing_shakes_camera = FALSE
/obj/item/ammo_casing/canister_shot
name = "Canister Shot"
desc = "A gigantic... well, canister of canister shot. Used for reloading the Canister Gatling Gun."
icon_state = "canister_shot"
obj_flags = CONDUCTS_ELECTRICITY
throwforce = 0
w_class = WEIGHT_CLASS_BULKY