diff --git a/code/game/objects/items/weapons/clown.dm b/code/game/objects/items/weapons/clown.dm
new file mode 100644
index 0000000000..a01a0f18b6
--- /dev/null
+++ b/code/game/objects/items/weapons/clown.dm
@@ -0,0 +1,46 @@
+
+/obj/item/weapon/pie_cannon
+ name = "pie cannon"
+ desc = "Load cream pie for optimal results"
+ force = 10
+ icon_state = "piecannon"
+ item_state = "powerfist"
+ var/obj/item/weapon/reagent_containers/food/snacks/pie/loaded = null
+
+/obj/item/weapon/pie_cannon/attackby(obj/item/I, mob/living/L)
+ if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/pie))
+ if(!loaded)
+ L.transferItemToLoc(I, src)
+ loaded = I
+ to_chat(L, "You load the [I] into the [src]!")
+ return
+ return ..()
+
+/obj/item/weapon/pie_cannon/afterattack(atom/target, mob/living/user, flag, params)
+ if(!loaded)
+ return ..()
+ var/obj/item/projectile/pie/launched = new /obj/item/projectile/pie(src)
+ launched.P = loaded
+ loaded.forceMove(launched)
+ launched.appearance = loaded.appearance
+ loaded = null
+ launched.preparePixelProjectile(target, get_turf(target), user, params, 0)
+ launched.forceMove(get_turf(src))
+ launched.fire()
+ user.visible_message("[user] fires the [src] at [target]!")
+
+/obj/item/projectile/pie
+ name = "pie"
+ desc = "Think fast!"
+ var/obj/item/weapon/reagent_containers/food/snacks/pie/P = null
+
+/obj/item/projectile/pie/on_hit(atom/A)
+ . = ..()
+ if(P)
+ A.visible_message("[P] smashes into [A] at high velocity!")
+ P.forceMove(get_turf(A))
+ P.throw_impact(A)
+ if(ismovableatom(A))
+ var/atom/movable/AM = A
+ if(!AM.anchored)
+ AM.throw_at(get_edge_target_turf(get_dir(src, AM), 3, 2))
diff --git a/code/game/objects/items/weapons/pneumaticCannon.dm b/code/game/objects/items/weapons/pneumaticCannon.dm
index 61e68934b9..d1370c9d7c 100644
--- a/code/game/objects/items/weapons/pneumaticCannon.dm
+++ b/code/game/objects/items/weapons/pneumaticCannon.dm
@@ -1,3 +1,7 @@
+
+#define PCANNON_FIREALL 1
+#define PCANNON_FILO 2
+#define PCANNON_FIFO 3
/obj/item/weapon/pneumatic_cannon
name = "pneumatic cannon"
desc = "A gas-powered cannon that can fire any object loaded into it."
@@ -16,7 +20,15 @@
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/pressureSetting = 1 //How powerful the cannon is - higher pressure = more gas but more powerful throws
+ var/checktank = TRUE
+ var/range_multiplier = 1
+ var/throw_amount = 20 //How many items to throw per fire
+ var/fire_mode = PCANNON_FIREALL
+ var/automatic = FALSE
+ var/clumsyCheck = TRUE
+/obj/item/weapon/pneumatic_cannon/CanItemAutoclick()
+ return automatic
/obj/item/weapon/pneumatic_cannon/examine(mob/user)
..()
@@ -30,6 +42,8 @@
/obj/item/weapon/pneumatic_cannon/attackby(obj/item/weapon/W, mob/user, params)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
if(istype(W, /obj/item/weapon/tank/internals))
if(!tank)
var/obj/item/weapon/tank/internals/IT = W
@@ -55,19 +69,31 @@
to_chat(user, "\The [src] can't hold any more items!")
else if(istype(W, /obj/item))
var/obj/item/IW = W
- if((loadedWeightClass + IW.w_class) > maxWeightClass)
- to_chat(user, "\The [IW] won't fit into \the [src]!")
- return
- if(IW.w_class > src.w_class)
- to_chat(user, "\The [IW] is too large to fit into \the [src]!")
- return
- if(!user.transferItemToLoc(W, src))
- return
- to_chat(user, "You load \the [IW] into \the [src].")
- loadedItems.Add(IW)
- loadedWeightClass += IW.w_class
+ load_item(IW, user)
+/obj/item/weapon/pneumatic_cannon/proc/can_load_item(obj/item/I, mob/user)
+ if((loadedWeightClass + I.w_class) > maxWeightClass) //Only make messages if there's a user
+ if(user)
+ to_chat(user, "\The [I] won't fit into \the [src]!")
+ return FALSE
+ if(I.w_class > w_class)
+ if(user)
+ to_chat(user, "\The [I] is too large to fit into \the [src]!")
+ return FALSE
+ return TRUE
+/obj/item/weapon/pneumatic_cannon/proc/load_item(obj/item/I, mob/user)
+ if(!can_load_item(I, user))
+ return FALSE
+ if(user) //Only use transfer proc if there's a user, otherwise just set loc.
+ if(!user.transferItemToLoc(I, src))
+ return FALSE
+ to_chat(user, "You load \the [I] into \the [src].")
+ else
+ I.forceMove(src)
+ loadedItems += I
+ loadedWeightClass += I.w_class
+ return TRUE
/obj/item/weapon/pneumatic_cannon/afterattack(atom/target, mob/living/carbon/human/user, flag, params)
if(flag && user.a_intent == INTENT_HARM) //melee attack
@@ -76,7 +102,6 @@
return
Fire(user, target)
-
/obj/item/weapon/pneumatic_cannon/proc/Fire(mob/living/carbon/human/user, var/atom/target)
if(!istype(user) && !target)
return
@@ -90,13 +115,13 @@
if(!loadedItems || !loadedWeightClass)
to_chat(user, "\The [src] has nothing loaded.")
return
- if(!tank)
+ if(!tank && checktank)
to_chat(user, "\The [src] can't fire without a source of gas.")
return
if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting))
to_chat(user, "\The [src] lets out a weak hiss and doesn't react!")
return
- if(user.disabilities & CLUMSY && prob(75))
+ if(user.disabilities & CLUMSY && prob(75) && clumsyCheck)
user.visible_message("[user] loses their grip on [src], causing it to go off!", "[src] slips out of your hands and goes off!")
user.drop_item()
if(prob(10))
@@ -109,17 +134,48 @@
user.visible_message("[user] fires \the [src]!", \
"You fire \the [src]!")
add_logs(user, target, "fired at", src)
+ var/turf/T = get_target(target, get_turf(src))
playsound(src.loc, 'sound/weapons/sonic_jackhammer.ogg', 50, 1)
- for(var/obj/item/ITD in loadedItems) //Item To Discharge
- loadedItems.Remove(ITD)
- loadedWeightClass -= ITD.w_class
- ITD.throw_speed = pressureSetting * 2
- ITD.loc = get_turf(src)
- ITD.throw_at(target, pressureSetting * 5, pressureSetting * 2,user)
+ fire_items(T, user)
if(pressureSetting >= 3 && user)
user.visible_message("[user] is thrown down by the force of the cannon!", "[src] slams into your shoulder, knocking you down!")
user.Weaken(3)
+/obj/item/weapon/pneumatic_cannon/proc/fire_items(turf/target, mob/user)
+ if(fire_mode == PCANNON_FIREALL)
+ for(var/obj/item/ITD in loadedItems) //Item To Discharge
+ if(!throw_item(target, ITD, user))
+ break
+ else
+ for(var/i in 1 to throw_amount)
+ if(!loadedItems.len)
+ break
+ var/obj/item/I
+ if(fire_mode == PCANNON_FILO)
+ I = loadedItems[loadedItems.len]
+ else
+ I = loadedItems[1]
+ if(!throw_item(target, I, user))
+ break
+
+/obj/item/weapon/pneumatic_cannon/proc/throw_item(turf/target, obj/item/I, mob/user)
+ if(!istype(I))
+ return FALSE
+ loadedItems -= I
+ loadedWeightClass -= I.w_class
+ I.forceMove(get_turf(src))
+ I.throw_at(target, pressureSetting * 10 * range_multiplier, pressureSetting * 2, user)
+ return TRUE
+
+/obj/item/weapon/pneumatic_cannon/proc/get_target(turf/target, turf/starting)
+ if(range_multiplier == 1)
+ return target
+ var/x_o = (target.x - starting.x)
+ var/y_o = (target.y - starting.y)
+ var/new_x = Clamp((starting.x + (x_o * range_multiplier)), 0, world.maxx)
+ var/new_y = Clamp((starting.y + (y_o * range_multiplier)), 0, world.maxy)
+ var/turf/newtarget = locate(new_x, new_y, starting.z)
+ return newtarget
/obj/item/weapon/pneumatic_cannon/ghetto //Obtainable by improvised methods; more gas per use, less capacity, but smaller
name = "improvised pneumatic cannon"
@@ -164,3 +220,33 @@
return
add_overlay(tank.icon_state)
src.update_icon()
+
+/obj/item/weapon/pneumatic_cannon/proc/fill_with_type(type, amount)
+ if(!ispath(type, /obj/item))
+ return FALSE
+ var/loaded = 0
+ for(var/i in 1 to amount)
+ var/obj/item/I = new type
+ if(!load_item(I, null))
+ qdel(I)
+ return loaded
+ loaded++
+
+/obj/item/weapon/pneumatic_cannon/pie
+ name = "pie cannon"
+ desc = "Load cream pie for optimal results"
+ force = 10
+ icon_state = "piecannon"
+ gasPerThrow = 0
+ checktank = FALSE
+ range_multiplier = 3
+ fire_mode = PCANNON_FIFO
+ throw_amount = 1
+ maxWeightClass = 100 //50 pies. :^)
+ clumsyCheck = FALSE
+
+/obj/item/weapon/pneumatic_cannon/pie/can_load_item(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/pie))
+ return ..()
+ to_chat(user, "[src] only accepts pies!")
+ return FALSE
diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm
index 57883966b0..7d983e5519 100644
--- a/code/modules/jobs/job_types/civilian.dm
+++ b/code/modules/jobs/job_types/civilian.dm
@@ -35,7 +35,8 @@ Clown
/obj/item/weapon/reagent_containers/spray/waterflower = 1,
/obj/item/weapon/reagent_containers/food/snacks/grown/banana = 1,
/obj/item/device/megaphone/clown = 1,
- /obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1
+ /obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
+ /obj/item/weapon/pneumatic_cannon/pie = 1
)
implants = list(/obj/item/weapon/implant/sad_trombone)
diff --git a/icons/obj/pneumaticCannon.dmi b/icons/obj/pneumaticCannon.dmi
index 41de7677b5..86e14e19d6 100644
Binary files a/icons/obj/pneumaticCannon.dmi and b/icons/obj/pneumaticCannon.dmi differ