diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index c4c5d3cea4c..50dc5c3b467 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -140,7 +140,6 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \ new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 50, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("bookcase", /obj/structure/bookcase, 5, time = 50, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \ - /*new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0), \ */ new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 20, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("easel", /obj/structure/easel, 3, one_per_turf = 1, on_floor = 1), \ diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index f676ac14d44..bbdb526c70a 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -200,4 +200,22 @@ time = 15 reqs = list(/obj/item/stack/sheet/wood = 1, /obj/item/stack/cable_coil = 5) - tools = list(/obj/item/weapon/kitchen/knife) // Gotta carve the wood into handles \ No newline at end of file + tools = list(/obj/item/weapon/kitchen/knife) // Gotta carve the wood into handles + +/datum/table_recipe/makeshift_bolt + name = "Makeshift Bolt" + result = /obj/item/weapon/arrow/rod + time = 15 + reqs = list(/obj/item/stack/rods = 1) + tools = list(/obj/item/weapon/weldingtool) + +/datum/table_recipe/crossbow + name = "Powered Crossbow" + result = /obj/item/weapon/gun/throw/crossbow + time = 300 + reqs = list(/obj/item/stack/rods = 3, + /obj/item/stack/cable_coil = 10, + /obj/item/stack/sheet/mineral/plastic = 3, + /obj/item/stack/sheet/wood = 5) + tools = list(/obj/item/weapon/weldingtool, + /obj/item/weapon/screwdriver) diff --git a/code/modules/projectiles/guns/projectile/rocket.dm b/code/modules/projectiles/guns/rocket.dm similarity index 94% rename from code/modules/projectiles/guns/projectile/rocket.dm rename to code/modules/projectiles/guns/rocket.dm index 6f0b217de47..72ab89bf40e 100644 --- a/code/modules/projectiles/guns/projectile/rocket.dm +++ b/code/modules/projectiles/guns/rocket.dm @@ -24,10 +24,12 @@ qdel(D) rockets = null + return ..() + /obj/item/weapon/gun/rocketlauncher/update_icon() return -/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I as obj, mob/user as mob, params) +/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/ammo_casing/rocket)) if(rockets.len < max_rockets) user.drop_item() @@ -52,6 +54,5 @@ log_game("[key_name_admin(user)] used a rocket launcher ([name]).") rockets -= I qdel(I) - return else to_chat(usr, "[src] is empty.") diff --git a/code/modules/projectiles/guns/throw.dm b/code/modules/projectiles/guns/throw.dm new file mode 100644 index 00000000000..d1bcda59067 --- /dev/null +++ b/code/modules/projectiles/guns/throw.dm @@ -0,0 +1,93 @@ +/obj/item/weapon/gun/throw + name = "abstract item thrower" + desc = "This shouldn't be here, yell at a coder." + fire_sound = 'sound/weapons/punchmiss.ogg' + fire_sound_text = "thwock" + + var/obj/item/to_launch + var/list/valid_projectile_type + var/max_capacity = 1 + var/list/loaded_projectiles = list() + + var/projectile_speed = 1 + var/projectile_range = 1 + +/obj/item/weapon/gun/throw/proc/notify_ammo_count(mob/user) + return + +/obj/item/weapon/gun/throw/proc/get_throwrange() + return projectile_speed + +/obj/item/weapon/gun/throw/proc/get_throwspeed() + return projectile_range + +/obj/item/weapon/gun/throw/proc/modify_projectile(obj/item/I, on_chamber = 0) + return + +/obj/item/weapon/gun/throw/proc/get_ammocount(include_loaded = 1) + var/count = loaded_projectiles.len + if(include_loaded && to_launch) + count++ + return count + +/obj/item/weapon/gun/throw/examine(mob/user) + ..() + to_chat(user, "It is [to_launch ? "loaded with \a [to_launch]" : "not loaded"].") + notify_ammo_count(user) + +/obj/item/weapon/gun/throw/Destroy() + qdel(to_launch) + to_launch = null + for(var/atom/A in loaded_projectiles) + qdel(A) + loaded_projectiles = null + + return ..() + +/obj/item/weapon/gun/throw/update_icon() + return + +/obj/item/weapon/gun/throw/attackby(obj/item/I, mob/user, params) + if(istype(I, valid_projectile_type) && !(I.flags & NODROP)) + if(get_ammocount() < max_capacity) + user.drop_item() + I.forceMove(src) + loaded_projectiles += I + to_chat(user, "You load [I] into [src].") + if(!to_launch) + process_chamber() + notify_ammo_count(user) + else + to_chat(user, "[src] cannot hold any more projectiles.") + else + to_chat(user, "You cannot load [I] into [src]!") + +/obj/item/weapon/gun/throw/process_chamber() + if(!to_launch && loaded_projectiles.len) + to_launch = loaded_projectiles[1] + loaded_projectiles -= to_launch + return + +/obj/item/weapon/gun/throw/can_shoot() + if(to_launch) + return 1 + return 0 + +/obj/item/weapon/gun/throw/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) + add_fingerprint(user) + if(semicd) + return + + var/obj/item/I = to_launch + I.forceMove(get_turf(src)) + to_launch = null + modify_projectile(I) + playsound(user, fire_sound, 50, 1) + I.throw_at(target, get_throwrange(), get_throwspeed(), user, 1) + message_admins("[key_name_admin(user)] fired \a [I] from a [src].") + log_game("[key_name_admin(user)] used \a [src].") + process_chamber() + + semicd = 1 + spawn(fire_delay) + semicd = 0 diff --git a/code/modules/projectiles/guns/throw/crossbow.dm b/code/modules/projectiles/guns/throw/crossbow.dm new file mode 100644 index 00000000000..55e76bec6b7 --- /dev/null +++ b/code/modules/projectiles/guns/throw/crossbow.dm @@ -0,0 +1,181 @@ +#define XBOW_TENSION_20 "20%" +#define XBOW_TENSION_40 "40%" +#define XBOW_TENSION_60 "60%" +#define XBOW_TENSION_80 "80%" +#define XBOW_TENSION_FULL "100%" + +/obj/item/weapon/gun/throw/crossbow + name = "powered crossbow" + desc = "A modern twist on an old classic. Pick up that can." + icon_state = "crossbow" + item_state = "crossbow-solid" + fire_sound_text = "a solid thunk" + fire_delay = 25 + + valid_projectile_type = /obj/item/weapon/arrow + + var/tension = 0 + var/drawtension = 5 + var/maxtension = 5 + var/speed_multiplier = 5 + var/range_multiplier = 3 + var/obj/item/weapon/stock_parts/cell/cell = null // Used for firing superheated rods. + var/list/possible_tensions = list(XBOW_TENSION_20, XBOW_TENSION_40, XBOW_TENSION_60, XBOW_TENSION_80, XBOW_TENSION_FULL) + +/obj/item/weapon/gun/throw/crossbow/emp_act(severity) + if(cell && severity) + emp_act(severity) + +/obj/item/weapon/gun/throw/crossbow/update_icon() + if(!tension) + if(!to_launch) + icon_state = "[initial(icon_state)]" + else + icon_state = "[initial(icon_state)]-nocked" + else + icon_state = "[initial(icon_state)]-drawn" + +/obj/item/weapon/gun/throw/crossbow/examine(mob/user) + ..() + if(cell) + to_chat(user, "\A [cell] is mounted onto [src]. Battery cell charge: [cell.charge]/[cell.maxcharge]") + else + to_chat(user, "It has an empty mount for a battery cell.") + +/obj/item/weapon/gun/throw/crossbow/modify_projectile(obj/item/I, on_chamber = 0) + if(cell && on_chamber && istype(I, /obj/item/weapon/arrow/rod)) + var/obj/item/weapon/arrow/rod/R = I + visible_message("[R] plinks and crackles as it begins to glow red-hot.") + R.throwforce = 15 + R.superheated = 1 + cell.use(500) + +/obj/item/weapon/gun/throw/crossbow/get_throwspeed() + return tension * speed_multiplier + +/obj/item/weapon/gun/throw/crossbow/get_throwrange() + return tension * range_multiplier + +/obj/item/weapon/gun/throw/crossbow/process_chamber() + ..() + if(to_launch) + modify_projectile(to_launch, 1) + update_icon() + +/obj/item/weapon/gun/throw/crossbow/attack_self(mob/living/user) + if(tension) + if(to_launch) + user.visible_message("[user] relaxes the tension on [src]'s string and removes [to_launch].","You relax the tension on [src]'s string and remove [to_launch].") + to_launch.forceMove(get_turf(src)) + var/obj/item/weapon/arrow/A = to_launch + to_launch = null + A.removed() + process_chamber() + else + user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") + tension = 0 + update_icon() + else + draw(user) + +/obj/item/weapon/gun/throw/crossbow/proc/draw(mob/living/user) + if(user.incapacitated()) + return + if(!to_launch) + to_chat(user, "You can't draw [src] without a bolt nocked.") + return + + user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].") + if(do_after(user, 25 * drawtension, target = user)) + tension = drawtension + user.visible_message("[usr] draws back the string of [src]!","[src] clunks as you draw the string to its maximum tension!!") + update_icon() + +/obj/item/weapon/gun/throw/crossbow/attackby(obj/item/W as obj, mob/user as mob, params) + if(istype(W, /obj/item/weapon/stock_parts/cell)) + if(!cell) + user.drop_item() + W.loc = src + cell = W + to_chat(user, "You jam [cell] into [src] and wire it to the firing coil.") + process_chamber() + else + to_chat(user, "[src] already has a cell installed.") + else if(istype(W, /obj/item/weapon/screwdriver)) + if(cell) + cell.loc = get_turf(src) + to_chat(user, "You jimmy [cell] out of [src] with [W].") + cell = null + else + to_chat(user, "[src] doesn't have a cell installed.") + else + ..() + +/obj/item/weapon/gun/throw/crossbow/verb/set_tension() + set name = "Adjust Tension" + set category = "Object" + set src in range(0) + + var/mob/user = usr + if(user.incapacitated()) + return + var/choice = input("Select tension to draw to:", "[src]", XBOW_TENSION_FULL) as null|anything in possible_tensions + if(!choice) + return + + switch(choice) + if(XBOW_TENSION_20) + drawtension = Ceiling(0.2 * maxtension) + if(XBOW_TENSION_40) + drawtension = Ceiling(0.4 * maxtension) + if(XBOW_TENSION_60) + drawtension = Ceiling(0.6 * maxtension) + if(XBOW_TENSION_80) + drawtension = Ceiling(0.8 * maxtension) + if(XBOW_TENSION_FULL) + drawtension = maxtension + +/obj/item/weapon/gun/throw/crossbow/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) + ..() + tension = 0 + update_icon() +/obj/item/weapon/gun/throw/crossbow/french + name = "french powered crossbow" + icon_state = "fcrossbow" + valid_projectile_type = /obj/item/weapon/reagent_containers/food/snacks/baguette + +/obj/item/weapon/gun/throw/crossbow/french/modify_projectile(obj/item/I, on_chamber = 0) + return + +/obj/item/weapon/arrow + name = "bolt" + desc = "It's got a tip for you - get the point?" + icon_state = "bolt" + item_state = "bolt" + throwforce = 20 + w_class = 3.0 + sharp = 1 + edge = 0 + +/obj/item/weapon/arrow/proc/removed() //Helper for metal rods falling apart. + return + +/obj/item/weapon/arrow/rod + name = "makeshift bolt" + desc = "A sharpened metal rod that can be fired out of a crossbow." + icon_state = "metal-rod" + throwforce = 8 + var/superheated = 0 + +/obj/item/weapon/arrow/rod/removed() + if(superheated) // The rod has been superheated - we don't want it to be useable when removed from the bow. + visible_message("[src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.") + var/obj/item/weapon/shard/shrapnel/S = new /obj/item/weapon/shard/shrapnel + S.loc = get_turf(src) + qdel(src) + +#undef XBOW_TENSION_20 +#undef XBOW_TENSION_40 +#undef XBOW_TENSION_60 +#undef XBOW_TENSION_80 +#undef XBOW_TENSION_FULL diff --git a/code/modules/projectiles/guns/throw/pielauncher.dm b/code/modules/projectiles/guns/throw/pielauncher.dm new file mode 100644 index 00000000000..f6405f47194 --- /dev/null +++ b/code/modules/projectiles/guns/throw/pielauncher.dm @@ -0,0 +1,36 @@ +/obj/item/weapon/gun/throw/piecannon + name = "pie cannon" + desc = "A projectile weapon that fires pies." + icon_state = "piecannon" + w_class = 5 + throw_speed = 2 + throw_range = 3 + force = 5 + + clumsy_check = 0 + valid_projectile_type = /obj/item/weapon/reagent_containers/food/snacks/pie + max_capacity = 5 + projectile_speed = 2 + projectile_range = 30 + + +/obj/item/weapon/gun/throw/piecannon/New() + ..() + for(var/i in 1 to max_capacity) + var/obj/item/weapon/reagent_containers/food/snacks/pie/P = new /obj/item/weapon/reagent_containers/food/snacks/pie(src) + loaded_projectiles += P + process_chamber() + +/obj/item/weapon/gun/throw/piecannon/notify_ammo_count(mob/user) + to_chat(user, "[src] has [get_ammocount()] of [max_capacity] pies left.") + +/obj/item/weapon/gun/throw/piecannon/update_icon() + if(to_launch) + icon_state = "piecannon1" + else + icon_state = "piecannon0" + item_state = icon_state + +/obj/item/weapon/gun/throw/piecannon/process_chamber() + ..() + update_icon() diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 38c9a9efd55..8f8809c504f 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -178,6 +178,7 @@ stun = 5 forcedodge = 1 nodamage = 1 + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE hitsound = 'sound/items/bikehorn.ogg' icon = 'icons/obj/harvest.dmi' icon_state = "banana" diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index aeefc778615..1064c55f48b 100644 Binary files a/icons/mob/inhands/guns_lefthand.dmi and b/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/guns_righthand.dmi b/icons/mob/inhands/guns_righthand.dmi index 392202c343d..93e30e4e812 100644 Binary files a/icons/mob/inhands/guns_righthand.dmi and b/icons/mob/inhands/guns_righthand.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 67313e46bfb..184d1461f3a 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index 1462d26e344..aaed17b8f94 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index 4d7e28b5626..45579065830 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index dc40e02aa5b..42c7ed6defc 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/paradise.dme b/paradise.dme index 97f182a3d3a..fb7631ab2ed 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1763,7 +1763,9 @@ #include "code\modules\projectiles\guns\medbeam.dm" #include "code\modules\projectiles\guns\mounted.dm" #include "code\modules\projectiles\guns\projectile.dm" +#include "code\modules\projectiles\guns\rocket.dm" #include "code\modules\projectiles\guns\syringe_gun.dm" +#include "code\modules\projectiles\guns\throw.dm" #include "code\modules\projectiles\guns\energy\laser.dm" #include "code\modules\projectiles\guns\energy\nuclear.dm" #include "code\modules\projectiles\guns\energy\pulse.dm" @@ -1776,11 +1778,12 @@ #include "code\modules\projectiles\guns\projectile\launchers.dm" #include "code\modules\projectiles\guns\projectile\pistol.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" -#include "code\modules\projectiles\guns\projectile\rocket.dm" #include "code\modules\projectiles\guns\projectile\saw.dm" #include "code\modules\projectiles\guns\projectile\shotgun.dm" #include "code\modules\projectiles\guns\projectile\sniper.dm" #include "code\modules\projectiles\guns\projectile\toy.dm" +#include "code\modules\projectiles\guns\throw\crossbow.dm" +#include "code\modules\projectiles\guns\throw\pielauncher.dm" #include "code\modules\projectiles\projectile\beams.dm" #include "code\modules\projectiles\projectile\bullets.dm" #include "code\modules\projectiles\projectile\energy.dm"