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