diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index ea9dfcc983..5bc5d8bd30 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -69,10 +69,10 @@ reqs = list(list(/obj/item/handcuffs/cable = 1), list(/obj/item/stack/rods = 1), list(/obj/item/material/shard = 1, - /obj/item/material/butterflyblade = 1) + /obj/item/material/butterflyblade = 1) ) parts = list(/obj/item/material/shard = 1, - /obj/item/material/butterflyblade = 1) + /obj/item/material/butterflyblade = 1) time = 40 category = CAT_WEAPONRY subcategory = CAT_WEAPON @@ -94,40 +94,6 @@ S.set_material(M.material.name) qdel(M) -/datum/crafting_recipe/shortbow - name = "Shortbow" - result = /obj/item/gun/launcher/crossbow/bow - reqs = list(list(/obj/item/stack/material/wood = 10), - list(/obj/item/stack/material/cloth = 5)) - time = 120 - category = CAT_WEAPONRY - subcategory = CAT_WEAPON - -/datum/crafting_recipe/arrow_sandstone - name = "Wood arrow (sandstone tip)" - result = /obj/item/arrow/wood - reqs = list(list(/obj/item/stack/material/wood = 2), - list(/obj/item/stack/material/sandstone = 2)) - time = 20 - category = CAT_WEAPONRY - subcategory = CAT_AMMO - -/datum/crafting_recipe/arrow_marble - name = "Wood arrow (marble tip)" - result = /obj/item/arrow/wood - reqs = list(list(/obj/item/stack/material/wood = 2), - list(/obj/item/stack/material/marble = 2)) - time = 20 - category = CAT_WEAPONRY - subcategory = CAT_AMMO - -/datum/crafting_recipe/quiver - name = "Arrow quiver" - result = /obj/item/storage/bag/quiver - reqs = list(list(/obj/item/stack/material/leather = 8)) - time = 60 - category = CAT_STORAGE - /datum/crafting_recipe/material_armor name = "Material Armor Plate" result = /obj/item/clothing/accessory/material/advanced diff --git a/code/datums/components/crafting/recipes/archery.dm b/code/datums/components/crafting/recipes/archery.dm new file mode 100644 index 0000000000..fa5368a433 --- /dev/null +++ b/code/datums/components/crafting/recipes/archery.dm @@ -0,0 +1,107 @@ +/* + * Bows, Arrows, and Accessories. + */ + +/datum/crafting_recipe/shortbow + name = "Shortbow" + result = /obj/item/gun/launcher/crossbow/bow + reqs = list(list(/obj/item/stack/material/wood = 10), + list(/obj/item/stack/material/cloth = 5)) + time = 120 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/arrow_sandstone + name = "Wood Arrow (Sandstone Tip)" + result = /obj/item/arrow/wood + reqs = list(list(/obj/item/stack/material/wood = 2), + list(/obj/item/stack/material/sandstone = 2)) + time = 2 SECONDS + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/arrow_marble + name = "Wood Arrow (Marble Tip)" + result = /obj/item/arrow/wood + reqs = list(list(/obj/item/stack/material/wood = 2), + list(/obj/item/stack/material/marble = 2)) + time = 2 SECONDS + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/arrow_chitin + name = "Wood Arrow (Chitin Tip)" + result = /obj/item/arrow/wood/chitin + reqs = list(list(/obj/item/stack/material/wood = 2), + list(/obj/item/stack/material/chitin = 2), + list(/obj/item/stack/material/cloth = 1)) + time = 3 SECONDS + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/arrow_metal_material + name = "Metal Arrow (Custom Tip)" + result = /obj/item/material/arrow + reqs = list(list(/obj/item/handcuffs/cable = 1), + list(/obj/item/stack/material = 3)) + parts = list( + /obj/item/stack/material = 3 + ) + tool_paths = list( + /obj/item/material/sharpeningkit + ) + time = 6 SECONDS + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/arrow_metal_material/on_craft_completion(mob/user, atom/result) + var/obj/item/stack/material/M + for(var/path in parts) + var/obj/item/material/N = locate(path) in result + if(istype(N, path)) + if(!istype(M)) + M = N + else + N.forceMove(get_turf(result)) + if(!istype(M)) + return + + var/obj/item/material/arrow/A = result + A.set_material(M.material.name) + qdel(M) + +/datum/crafting_recipe/arrow_wood_material + name = "Wood Arrow (Crude Tip)" + result = /obj/item/material/arrow/crude + reqs = list(list(/obj/item/stack/material/wood = 2), + list(/obj/item/material/knife/machete/hatchet/stone = 1), + list(/obj/item/stack/material/cloth = 1)) + parts = list( + /obj/item/material/knife/machete/hatchet/stone = 1 + ) + time = 3 SECONDS + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/arrow_wood_material/on_craft_completion(mob/user, atom/result) + var/obj/item/material/M + for(var/path in parts) + var/obj/item/material/N = locate(path) in result + if(istype(N, path)) + if(!istype(M)) + M = N + else + N.forceMove(get_turf(result)) + if(!istype(M)) + return + + var/obj/item/material/arrow/A = result + A.set_material(M.material.name) + qdel(M) + +/datum/crafting_recipe/quiver + name = "Arrow quiver" + result = /obj/item/storage/bag/quiver + reqs = list(list(/obj/item/stack/material/leather = 8)) + time = 60 + category = CAT_STORAGE diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm index 1f249c8e7a..c7b84cc5ef 100644 --- a/code/game/objects/items/weapons/material/misc.dm +++ b/code/game/objects/items/weapons/material/misc.dm @@ -31,11 +31,14 @@ icon_state = "rock" item_state = "rock" attack_verb = list("chopped", "torn", "cut") + applies_material_colour = TRUE + default_material = MAT_SANDSTONE // Rocks from the earth are not typically high carbon steel. /obj/item/material/knife/machete/hatchet/stone/set_material(var/new_material) var/old_name = name . = ..() name = old_name + /obj/item/material/knife/machete/hatchet/unathiknife name = "duelling knife" desc = "A length of leather-bound wood studded with razor-sharp teeth. How crude." diff --git a/code/game/objects/items/weapons/material/thrown.dm b/code/game/objects/items/weapons/material/thrown.dm index d9e1bc722c..134e55015d 100644 --- a/code/game/objects/items/weapons/material/thrown.dm +++ b/code/game/objects/items/weapons/material/thrown.dm @@ -21,4 +21,28 @@ M.adjustToxLoss(rand(20,40)) /obj/item/material/star/ninja - default_material = "uranium" \ No newline at end of file + default_material = "uranium" + +// Hilariously, arrows are just darts, but bigger! ..The same can be said of spears. Thrown weapon. +/obj/item/material/arrow + name = "arrow" + desc = "A sharp, triangular head on a slender body. Yep, it's an arrow." + icon = 'icons/obj/weapons.dmi' + icon_state = "arrowmetal" + item_state = "bolt" + force_divisor = 0.1 // 6 with hardness 60 (steel) + thrown_force_divisor = 0.4 // 8 with weight 20 (steel) + throw_speed = 10 + throw_range = 4 + sharp = 1 + edge = 1 + + var/list/knock_point = list(7,7) + +/obj/item/material/arrow/crude + name = "crude arrow" + desc = "An ancient device for stabbing someone at range." + icon_state = "arrow" + thrown_force_divisor = 0.3 + throw_range = 3 + edge = 0 diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm index a6e65ee2b7..fbcf49471b 100644 --- a/code/game/objects/items/weapons/storage/bags.dm +++ b/code/game/objects/items/weapons/storage/bags.dm @@ -410,4 +410,4 @@ max_w_class = ITEMSIZE_NORMAL w_class = ITEMSIZE_LARGE slot_flags = SLOT_BACK - can_hold = list(/obj/item/arrow/wood) \ No newline at end of file + can_hold = list(/obj/item/arrow, /obj/item/material/arrow) diff --git a/code/modules/materials/sheets/_sheets.dm b/code/modules/materials/sheets/_sheets.dm index 7572d0e654..933b792789 100644 --- a/code/modules/materials/sheets/_sheets.dm +++ b/code/modules/materials/sheets/_sheets.dm @@ -1,6 +1,7 @@ // Stacked resources. They use a material datum for a lot of inherited values. // If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well /obj/item/stack/material + name = "material sheet" force = 5.0 throwforce = 5 w_class = ITEMSIZE_NORMAL @@ -86,4 +87,4 @@ else if(istype(W, /obj/item/stack/rods)) material.build_rod_product(user, W, src) return - return ..() \ No newline at end of file + return ..() diff --git a/code/modules/projectiles/guns/launcher/bows.dm b/code/modules/projectiles/guns/launcher/bows.dm index 0859aec2f2..e2f45a5fc1 100644 --- a/code/modules/projectiles/guns/launcher/bows.dm +++ b/code/modules/projectiles/guns/launcher/bows.dm @@ -11,6 +11,12 @@ drop_sound = 'sound/items/drop/woodweapon.ogg' pickup_sound = 'sound/items/pickup/woodweapon.ogg' + knock_point = list(9,8) + +/obj/item/arrow/wood/chitin + name = "chitin arrow" + desc = "A wooden arrow with a hard chitin tip. Simple, but gets the job done." + color = "#a66008" /obj/item/arrow/energy name = "hardlight arrow" @@ -48,10 +54,12 @@ release_speed = 15 release_force = 20 tension = 3 - var/drawn = FALSE drop_sound = 'sound/items/drop/woodweapon.ogg' pickup_sound = 'sound/items/pickup/woodweapon.ogg' + bolt_rotation_transform = 0 // Bows do not rotate their arrows like crossbows, as they face north-east on the ground. + drawn_knock = list(8,7) + ready_knock = list(15,14) /obj/item/gun/launcher/crossbow/bow/update_release_force(obj/item/projectile) return 0 @@ -59,34 +67,34 @@ /obj/item/gun/launcher/crossbow/bow/proc/unload(mob/user) var/obj/item/arrow/A = bolt bolt = null - drawn = FALSE + tension = FALSE A.forceMove(get_turf(user)) user.put_in_hands(A) update_icon() /obj/item/gun/launcher/crossbow/bow/consume_next_projectile(mob/user) - if(!drawn) + if(!tension) to_chat(user, "\The [src] is not drawn back!") return null return bolt /obj/item/gun/launcher/crossbow/bow/handle_post_fire(mob/user, atom/target) bolt = null - drawn = FALSE + tension = FALSE update_icon() ..() /obj/item/gun/launcher/crossbow/bow/attack_hand(mob/living/user) - if(loc == user && bolt && !drawn) + if(loc == user && bolt && !tension) user.visible_message("[user] removes [bolt] from [src].","You remove [bolt] from [src].") unload(user) else return ..() /obj/item/gun/launcher/crossbow/bow/attack_self(mob/living/user) - if(drawn) + if(tension) user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") - drawn = FALSE + tension = FALSE update_icon() else draw(user) @@ -102,7 +110,7 @@ current_user = user 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)) - drawn = TRUE + tension = TRUE user.visible_message("[user] draws the string on [src] back fully!", "You draw the string on [src] back fully!") update_icon() @@ -110,24 +118,27 @@ return /obj/item/gun/launcher/crossbow/bow/attackby(obj/item/W as obj, mob/user) - if(!bolt && istype(W,/obj/item/arrow/wood)) + if(!bolt && (istype(W,/obj/item/arrow) || istype(W,/obj/item/material/arrow))) user.drop_from_inventory(W, src) bolt = W user.visible_message("[user] nocks [bolt] in [src].","You nock [bolt] in [src].") update_icon() /obj/item/gun/launcher/crossbow/bow/update_icon() - if(drawn) + cut_overlays() + if(tension) icon_state = "[initial(icon_state)]_firing" else if(bolt) icon_state = "[initial(icon_state)]_loaded" else icon_state = "[initial(icon_state)]" + add_overlay(update_bolt_transform()) + /obj/item/gun/launcher/crossbow/bow/dropped(mob/user) - if(drawn) + if(tension) to_chat(user, "\The [src]'s tension is relaxed as you let go of it!") - drawn = FALSE + tension = FALSE update_icon() @@ -139,18 +150,23 @@ drop_sound = 'sound/items/drop/gun.ogg' pickup_sound = 'sound/items/pickup/gun.ogg' + var/arrow_type = /obj/item/arrow/energy + /obj/item/gun/launcher/crossbow/bow/hardlight/unload(mob/user) - qdel_null(bolt) - update_icon() + if(istype(bolt, /obj/item/arrow/energy)) // Let's not delete a Real Arrow^tm + qdel_null(bolt) + update_icon() + else + . = ..() /obj/item/gun/launcher/crossbow/bow/hardlight/attack_self(mob/living/user) - if(drawn) + if(tension) user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") - drawn = FALSE + tension = FALSE update_icon() else if(!bolt) user.visible_message("[user] fabricates a new hardlight projectile with [src].","You fabricate a new hardlight projectile with [src].") - bolt = new /obj/item/arrow/energy(src) + bolt = new arrow_type(src) update_icon() else - draw(user) \ No newline at end of file + draw(user) diff --git a/code/modules/projectiles/guns/launcher/crossbow.dm b/code/modules/projectiles/guns/launcher/crossbow.dm index 2eac970aa8..ac0f051579 100644 --- a/code/modules/projectiles/guns/launcher/crossbow.dm +++ b/code/modules/projectiles/guns/launcher/crossbow.dm @@ -13,6 +13,8 @@ sharp = 1 edge = 0 + var/list/knock_point = list(6,6) + /obj/item/arrow/proc/removed() //Helper for metal rods falling apart. return @@ -37,6 +39,8 @@ item_state = "quill" throwforce = 5 + knock_point = list(10,11) + /obj/item/arrow/rod name = "metal rod" desc = "Don't cry for me, Orithena." @@ -60,6 +64,11 @@ fire_delay = 25 slot_flags = SLOT_BACK + // Pixel location the arrow should rest on. + var/list/drawn_knock = list(10,9) + var/list/ready_knock = list(4,3) + var/bolt_rotation_transform = 180 // Crossbows point 'southwest' in their ground icon, so the arrows have to be flipped around. + var/obj/item/bolt var/tension = 0 // Current draw on the bow. var/max_tension = 5 // Highest possible tension. @@ -139,7 +148,7 @@ /obj/item/gun/launcher/crossbow/attackby(obj/item/W as obj, mob/user as mob) if(!bolt) - if (istype(W,/obj/item/arrow)) + if (istype(W,/obj/item/arrow) || istype(W, /obj/item/material/arrow)) user.drop_from_inventory(W, src) bolt = W user.visible_message("[user] slides [bolt] into [src].","You slide [bolt] into [src].") @@ -179,6 +188,14 @@ else ..() +/obj/item/gun/launcher/crossbow/attack_hand(mob/living/user) + . = ..() + update_icon() + +/obj/item/gun/launcher/crossbow/dropped(mob/user) + . = ..() + update_icon() + /obj/item/gun/launcher/crossbow/proc/superheat_rod(var/mob/user) if(!user || !cell || !bolt) return if(cell.charge < 500) return @@ -190,7 +207,29 @@ bolt.icon_state = "metal-rod-superheated" cell.use(500) +/obj/item/gun/launcher/crossbow/proc/update_bolt_transform() + if(!(istype(bolt,/obj/item/arrow) || istype(bolt, /obj/item/material/arrow))) + return + + var/obj/item/arrow/dart = bolt + + if(LAZYLEN(drawn_knock) && LAZYLEN(ready_knock) && LAZYLEN(dart.knock_point)) + dart.SetTransform(rotation = bolt_rotation_transform) + + if(!tension) + dart.SetTransform(offset_x = ready_knock[1] - dart?.knock_point[1], offset_y = ready_knock[2] - dart?.knock_point[2]) + + else + dart.SetTransform(offset_x = drawn_knock[1] - dart?.knock_point[1], offset_y = drawn_knock[2] - dart?.knock_point[2]) + + var/image/dart_image = image(dart) + dart_image.plane = plane // Make sure it's the same plane as the parent, otherwise we get phantom bolts. + dart.ClearTransform() + + return dart_image + /obj/item/gun/launcher/crossbow/update_icon() + cut_overlays() if(tension > 1) icon_state = "crossbow-drawn" else if(bolt) @@ -198,6 +237,8 @@ else icon_state = "crossbow" + if((istype(bolt,/obj/item/arrow) || istype(bolt, /obj/item/material/arrow))) + add_overlay(update_bolt_transform()) // Crossbow construction. /obj/item/crossbowframe diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index e294b1c59c..aefff673f6 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/polaris.dme b/polaris.dme index ce53f0551c..93f8b74434 100644 --- a/polaris.dme +++ b/polaris.dme @@ -301,6 +301,7 @@ #include "code\datums\components\crafting\crafting_external.dm" #include "code\datums\components\crafting\recipes.dm" #include "code\datums\components\crafting\tool_quality.dm" +#include "code\datums\components\crafting\recipes\archery.dm" #include "code\datums\elements\_element.dm" #include "code\datums\game_masters\_common.dm" #include "code\datums\game_masters\default.dm"