From 89ad96c63f5a228cbbdfd32e1f11b88241f4719b Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Fri, 22 Oct 2021 14:23:31 -0400 Subject: [PATCH 1/2] Merge pull request #11553 from VOREStation/upstream-merge-8184 [MIRROR] Refactors crafting to support requirement alternatives --- code/datums/components/crafting/crafting.dm | 409 +++++++++--------- .../components/crafting/crafting_external.dm | 39 +- code/datums/components/crafting/recipes.dm | 25 ++ .../components/crafting/recipes/primitive.dm | 12 +- .../components/crafting/recipes/survival.dm | 68 +-- .../components/crafting/recipes/weapons.dm | 38 +- 6 files changed, 321 insertions(+), 270 deletions(-) diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index f4a1fc2c3b..cada2fadef 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -62,55 +62,7 @@ del_reqs - takes recipe and a user, loops over the recipes reqs var and tries to find everything in the list make by get_environment and delete it/add to parts list, then returns the said list */ -/** - * Check that the contents of the recipe meet the requirements. - * - * user: The /mob that initated the crafting. - * R: The /datum/crafting_recipe being attempted. - * contents: List of items to search for R's reqs. - */ -/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents) - var/list/item_instances = contents["instances"] - var/list/machines = contents["machinery"] - contents = contents["other"] - - - var/list/requirements_list = list() - - // Process all requirements - for(var/requirement_path in R.reqs) - // Check we have the appropriate amount available in the contents list - var/needed_amount = R.reqs[requirement_path] - for(var/content_item_path in contents) - // Right path and not blacklisted - if(!ispath(content_item_path, requirement_path) || R.blacklist.Find(content_item_path)) - continue - - needed_amount -= contents[content_item_path] - if(needed_amount <= 0) - break - - if(needed_amount > 0) - return FALSE - - // Store the instances of what we will use for R.check_requirements() for requirement_path - var/list/instances_list = list() - for(var/instance_path in item_instances) - if(ispath(instance_path, requirement_path)) - instances_list += item_instances[instance_path] - - requirements_list[requirement_path] = instances_list - - for(var/requirement_path in R.chem_catalysts) - if(contents[requirement_path] < R.chem_catalysts[requirement_path]) - return FALSE - - for(var/machinery_path in R.machinery) - if(!machines[machinery_path])//We don't care for volume with machines, just if one is there or not - return FALSE - - return R.check_requirements(a, requirements_list) - +// Returns a list of objects available /datum/component/personal_crafting/proc/get_environment(atom/a, list/blacklist = null, radius_range = 1) . = list() @@ -122,13 +74,13 @@ continue . += AM - +// Returns an associative list containing the types of tools available, and the paths of objects available /datum/component/personal_crafting/proc/get_surroundings(atom/a, list/blacklist=null) . = list() - .["tool_qualities"] = list() - .["other"] = list() - .["instances"] = list() - .["machinery"] = list() + .["tool_qualities"] = list() // List of tool types available + .["other"] = list() // List of reagents/material stacks available + .["instances"] = list() // List of /obj/items available, maybe? + .["machinery"] = list() // List of /obj/machinery available for(var/obj/object in get_environment(a, blacklist)) if(isitem(object)) var/obj/item/item = object @@ -150,11 +102,55 @@ else if (istype(object, /obj/machinery)) LAZYADDASSOCLIST(.["machinery"], object.type, object) +/** + * Check that the contents of the recipe meet the requirements. + * + * user: The /mob that initated the crafting. + * R: The /datum/crafting_recipe being attempted. + * contents: List of items to search for R's reqs. + */ +/datum/component/personal_crafting/proc/check_contents(atom/a, datum/crafting_recipe/R, list/contents) + var/list/item_instances = contents["instances"] + contents = contents["other"] + var/list/requirements_list = list() + + // Process all requirements + for(var/list/requirement in R.reqs) + var/satisfied = FALSE + for(var/requirement_path in requirement) + // Check we have the appropriate amount available in the contents list + var/needed_amount = requirement[requirement_path] + for(var/content_item_path in contents) + // Right path and not blacklisted + if(!ispath(content_item_path, requirement_path) || R.blacklist.Find(content_item_path)) + continue + + needed_amount -= contents[content_item_path] + if(needed_amount <= 0) + break + + if(needed_amount > 0) + continue + + // Store the instances of what we will use for R.check_requirements() for requirement_path + var/list/instances_list = list() + for(var/instance_path in item_instances) + if(ispath(instance_path, requirement_path)) + instances_list += item_instances[instance_path] + + requirements_list[requirement_path] = instances_list + satisfied = TRUE + break + if(!satisfied) + return FALSE + + return R.check_requirements(a, requirements_list) + /// Returns a boolean on whether the tool requirements of the input recipe are satisfied by the input source and surroundings. -/datum/component/personal_crafting/proc/check_tools(atom/source, datum/crafting_recipe/recipe, list/surroundings) - if(!length(recipe.tool_behaviors) && !length(recipe.tool_paths)) +/datum/component/personal_crafting/proc/check_tools(atom/source, datum/crafting_recipe/R, list/surroundings) + if(!length(R.tool_behaviors) && !length(R.tool_paths)) return TRUE var/list/available_tools = list() var/list/present_qualities = list() @@ -176,50 +172,70 @@ for(var/path in surroundings["other"]) available_tools[path] = TRUE - for(var/required_quality in recipe.tool_behaviors) + for(var/required_quality in R.tool_behaviors) if(present_qualities[required_quality]) continue return FALSE - for(var/required_path in recipe.tool_paths) - var/found_this_tool = FALSE - for(var/tool_path in available_tools) - if(!ispath(required_path, tool_path)) - continue - found_this_tool = TRUE - break - if(found_this_tool) + for(var/required_path in R.tool_paths) + if(is_path_in_list(required_path, available_tools)) continue return FALSE return TRUE +/datum/component/personal_crafting/proc/check_reagents(atom/source, datum/crafting_recipe/R, list/surroundings) + var/list/reagents = surroundings["other"] + for(var/requirement_path in R.chem_catalysts) + if(reagents[requirement_path] < R.chem_catalysts[requirement_path]) + return FALSE + return TRUE + +/datum/component/personal_crafting/proc/check_machinery(atom/source, datum/crafting_recipe/R, list/surroundings) + var/list/machines = surroundings["machinery"] + for(var/machinery_path in R.machinery) + if(!machines[machinery_path])//We don't care for volume with machines, just if one is there or not + return FALSE + return TRUE + +/datum/component/personal_crafting/proc/check_requirements(atom/source, datum/crafting_recipe/R, list/surroundings) + if(!check_contents(source, R, surroundings)) + return ", missing component." + if(!check_tools(source, R, surroundings)) + return ", missing tool." + if(!check_reagents(source, R, surroundings)) + return ", missing reagents." + if(!check_machinery(source, R, surroundings)) + return ", missing machinery." + return /datum/component/personal_crafting/proc/construct_item(atom/a, datum/crafting_recipe/R) - var/list/contents = get_surroundings(a,R.blacklist) + var/list/surroundings = get_surroundings(a,R.blacklist) // var/send_feedback = 1 - if(check_contents(a, R, contents)) - if(check_tools(a, R, contents)) - if(R.one_per_turf) - for(var/content in get_turf(a)) - if(istype(content, R.result)) - return ", object already present." - //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item - if(ismob(a) && !do_after(a, R.time, target = a)) - return "." - contents = get_surroundings(a,R.blacklist) - if(!check_contents(a, R, contents)) - return ", missing component." - if(!check_tools(a, R, contents)) - return ", missing tool." - var/list/parts = del_reqs(R, a) - var/atom/movable/I = new R.result (get_turf(a.loc)) - I.CheckParts(parts, R) - // if(send_feedback) - // SSblackbox.record_feedback("tally", "object_crafted", 1, I.type) - return I //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item - return ", missing tool." - return ", missing component." + . = check_requirements(a, R, surroundings) + if(.) + return + + if(R.one_per_turf) + for(var/content in get_turf(a)) + if(istype(content, R.result)) + return ", object already present." + + //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item + if(ismob(a) && !do_after(a, R.time, target = a)) + return "." + + surroundings = get_surroundings(a, R.blacklist) + . = check_requirements(a, R, surroundings) + if(.) + return + + var/list/parts = del_reqs(R, a) + var/atom/movable/I = new R.result (get_turf(a.loc)) + I.CheckParts(parts, R) + // if(send_feedback) + // SSblackbox.record_feedback("tally", "object_crafted", 1, I.type) + return I //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item /*Del reqs works like this: @@ -246,119 +262,108 @@ */ /datum/component/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, atom/a) - var/list/surroundings - var/list/Deletion = list() - . = list() - var/data - var/amt + var/list/surroundings = get_environment(a) + var/list/parts = list("items" = list()) + if(R.get_parts_reagents_volume()) + parts["reagents"] = new /datum/reagents(R.get_parts_reagents_volume()) // Datums don't have create_reagents() var/list/requirements = list() if(R.reqs) - requirements += R.reqs + for(var/list/L in R.reqs) + requirements += L if(R.machinery) requirements += R.machinery - main_loop: - for(var/path_key in requirements) - amt = R.reqs[path_key] || R.machinery[path_key] - if(!amt)//since machinery can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it! - continue main_loop - surroundings = get_environment(a, R.blacklist) - surroundings -= Deletion - if(ispath(path_key, /datum/reagent)) - var/datum/reagent/RG = new path_key - var/datum/reagent/RGNT - while(amt > 0) - var/obj/item/weapon/reagent_containers/RC = locate() in surroundings - RG = RC.reagents.get_reagent(path_key) - if(RG) - if(!locate(RG.type) in Deletion) - Deletion += new RG.type() - if(RG.volume > amt) - RG.volume -= amt - data = RG.data - RC.reagents.conditional_update(RC) - RG = locate(RG.type) in Deletion - RG.volume = amt - RG.data += data - continue main_loop - else - surroundings -= RC - amt -= RG.volume - RC.reagents.reagent_list -= RG - RC.reagents.conditional_update(RC) - RGNT = locate(RG.type) in Deletion - RGNT.volume += RG.volume - RGNT.data += RG.data - qdel(RG) - SEND_SIGNAL(RC.reagents, COMSIG_REAGENTS_CRAFTING_PING) // - [] TODO: Make this entire thing less spaghetti - else - surroundings -= RC - else if(ispath(path_key, /obj/item/stack)) - var/obj/item/stack/S - var/obj/item/stack/SD - while(amt > 0) - S = locate(path_key) in surroundings - if(S.get_amount() >= amt) - if(!locate(S.type) in Deletion) - SD = new S.type() - Deletion += SD - S.use(amt) - SD = locate(S.type) in Deletion - SD.add(amt) - continue main_loop - else - amt -= S.get_amount() - if(!locate(S.type) in Deletion) - Deletion += S - else - data = S.get_amount() - S = locate(S.type) in Deletion - S.add(data) - surroundings -= S - else - var/atom/movable/I - while(amt > 0) - I = locate(path_key) in surroundings - Deletion += I - surroundings -= I - amt-- - var/list/partlist = list(R.parts.len) - for(var/M in R.parts) - partlist[M] = R.parts[M] - for(var/part in R.parts) - if(istype(part, /datum/reagent)) - var/datum/reagent/RG = locate(part) in Deletion - if(RG.volume > partlist[part]) - RG.volume = partlist[part] - . += RG - Deletion -= RG + + // Try to find everything that was actually used to craft + for(var/path_key in requirements) + var/amt = requirements[path_key] + if(amt <= 0)//since machinery can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it! continue - else if(istype(part, /obj/item/stack)) - var/obj/item/stack/ST = locate(part) in Deletion - if(ST.get_amount() > partlist[part]) - ST.set_amount(partlist[part]) - . += ST - Deletion -= ST - continue - else - while(partlist[part] > 0) - var/atom/movable/AM = locate(part) in Deletion - . += AM - Deletion -= AM - partlist[part] -= 1 - while(Deletion.len) - var/DL = Deletion[Deletion.len] - Deletion.Cut(Deletion.len) - // Snowflake handling of reagent containers and storage atoms. - // If we consumed them in our crafting, we should dump their contents out before qdeling them. - if(istype(DL, /obj/item/weapon/reagent_containers)) - var/obj/item/weapon/reagent_containers/container = DL - container.reagents.clear_reagents() - // container.reagents.expose(container.loc, TOUCH) - else if(istype(DL, /obj/item/weapon/storage)) - var/obj/item/weapon/storage/container = DL - container.spill() - container.close_all() - qdel(DL) + + // If the path is in R.parts, we want to grab those to stuff into the product + var/amt_to_transfer = 0 + if(is_path_in_list(path_key, R.parts)) + amt_to_transfer = R.parts[path_key] + + + // Reagent: gotta go sniffing in all the beakers + if(ispath(path_key, /datum/reagent)) + var/datum/reagent/reagent = path_key + var/id = initial(reagent.id) + + for(var/obj/item/weapon/reagent_containers/RC in surroundings) + // Found everything we need + if(amt <= 0 && amt_to_transfer <= 0) + break + + // If we need to keep any to put in the new object, pull it out + if(amt_to_transfer > 0) + var/A = RC.reagents.trans_id_to(parts["reagents"], id, amt_to_transfer) + amt_to_transfer -= A + amt -= A + + // If we need to consume some amount of it + if(amt > 0) + var/datum/reagent/RG = RC.reagents.get_reagent(id) + var/A = min(RG.volume, amt) + RC.reagents.remove_reagent(id, A) + amt -= A + SEND_SIGNAL(RC.reagents, COMSIG_REAGENTS_CRAFTING_PING) + + // Material stacks may have to accumulate across multiple stacks + else if(ispath(path_key, /obj/item/stack)) + for(var/obj/item/stack/S in surroundings) + if(amt <= 0 && amt_to_transfer <= 0) + break + + // This could put 50 stacks in an object but frankly so long as the amount's right we don't care + if(amt_to_transfer > 0) + var/obj/item/stack/split = S.split(amt_to_transfer) + if(istype(split)) + parts["items"] += split + amt_to_transfer -= split.get_amount() + amt -= split.get_amount() + + if(amt > 0) + var/A = min(amt, S.get_amount()) + if(S.use(A)) + amt -= A + + + else // Just a regular item. Find them all and delete them + for(var/atom/movable/I in surroundings) + if(amt <= 0 && amt_to_transfer <= 0) + break + + if(!istype(I, path_key)) + continue + + // Special case: the reagents may be needed for other recipes + if(istype(I, /obj/item/weapon/reagent_containers)) + var/obj/item/weapon/reagent_containers/RC = I + if(RC.reagents.total_volume > 0) + continue + + // We're using it for something + amt-- + + // Prepare to stuff inside product, don't delete it + if(is_path_in_list(path_key, parts)) + parts["items"] += I + amt_to_transfer-- + continue + + // Snowflake handling of reagent containers and storage atoms. + // If we consumed them in our crafting, we should dump their contents out before qdeling them. + if(istype(I, /obj/item/weapon/reagent_containers)) + var/obj/item/weapon/reagent_containers/container = I + container.reagents.clear_reagents() + // container.reagents.expose(container.loc, TOUCH) + else if(istype(I, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/container = I + container.spill() + container.close_all() + qdel(I) + return parts /datum/component/personal_crafting/proc/component_ui_interact(source, location, control, params, user) // SIGNAL_HANDLER @@ -487,10 +492,14 @@ var/list/tool_list = list() var/list/catalyst_text = list() - for(var/atom/req_atom as anything in R.reqs) - //We just need the name, so cheat-typecast to /atom for speed (even tho Reagents are /datum they DO have a "name" var) - //Also these are typepaths so sadly we can't just do "[a]" - req_text += "[R.reqs[req_atom]] [initial(req_atom.name)]" + for(var/list/req in R.reqs) + var/list/L = list() + for(var/atom/req_atom as anything in req) + //We just need the name, so cheat-typecast to /atom for speed (even tho Reagents are /datum they DO have a "name" var) + //Also these are typepaths so sadly we can't just do "[a]" + L += "[req[req_atom]] [initial(req_atom.name)]" + req_text += L.Join(" OR ") + for(var/obj/machinery/content as anything in R.machinery) req_text += "[R.reqs[content]] [initial(content.name)]" if(R.additional_req_text) diff --git a/code/datums/components/crafting/crafting_external.dm b/code/datums/components/crafting/crafting_external.dm index e40d501132..8346a0fa58 100644 --- a/code/datums/components/crafting/crafting_external.dm +++ b/code/datums/components/crafting/crafting_external.dm @@ -12,21 +12,30 @@ */ /atom/proc/CheckParts(list/parts_list, datum/crafting_recipe/R) SEND_SIGNAL(src, COMSIG_ATOM_CHECKPARTS, parts_list, R) - if(parts_list) - for(var/A in parts_list) - if(istype(A, /datum/reagent)) - if(!reagents) - reagents = new() - reagents.reagent_list.Add(A) - reagents.conditional_update() - else if(ismovable(A)) - var/atom/movable/M = A - if(isliving(M.loc)) - var/mob/living/L = M.loc - L.unEquip(M, target = src) - else - M.forceMove(src) - SEND_SIGNAL(M, COMSIG_ATOM_USED_IN_CRAFT, src) + if(LAZYLEN(parts_list)) + if(istype(parts_list["reagents"], /datum/reagents)) + var/datum/reagents/RG = parts_list["reagents"] + if(istype(reagents)) + RG.trans_to_holder(reagents, RG.total_volume) + else + reagents = RG + RG.my_atom = src + reagents.conditional_update() + + for(var/atom/movable/M as anything in parts_list["items"]) + if(isliving(M.loc)) + var/mob/living/L = M.loc + L.unEquip(M, target = src) + else + M.forceMove(src) + SEND_SIGNAL(M, COMSIG_ATOM_USED_IN_CRAFT, src) + + var/list/L = parts_list["reagents"] + if(LAZYLEN(L)) + L.Cut() + L = parts_list["items"] + if(LAZYLEN(L)) + L.Cut() parts_list.Cut() /obj/machinery/CheckParts(list/parts_list) diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index bd5aec3395..d39d012832 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -47,3 +47,28 @@ /datum/crafting_recipe/proc/on_craft_completion(mob/user, atom/result) return + +// Computes the total reagents volume +/datum/crafting_recipe/proc/get_parts_reagents_volume() + . = 0 + for(var/list/L in parts) + for(var/path in L) + if(ispath(path, /datum/reagent)) + . += L[path] + +// Locate one of the things that set the material type, and update it from the default (glass) +/datum/crafting_recipe/spear/on_craft_completion(mob/user, atom/result) + var/obj/item/weapon/material/M + for(var/path in parts) + var/obj/item/weapon/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/weapon/material/twohanded/spear/S = result + S.set_material(M.material.name) + qdel(M) diff --git a/code/datums/components/crafting/recipes/primitive.dm b/code/datums/components/crafting/recipes/primitive.dm index 3c3eb4e84b..97f6be5e39 100644 --- a/code/datums/components/crafting/recipes/primitive.dm +++ b/code/datums/components/crafting/recipes/primitive.dm @@ -1,14 +1,14 @@ /datum/crafting_recipe/cloth name = "Cloth bolt" result = /obj/item/stack/material/cloth - reqs = list(/obj/item/stack/material/fiber = 3) + reqs = list(list(/obj/item/stack/material/fiber = 3)) time = 40 category = CAT_PRIMAL /datum/crafting_recipe/crude_bandage name = "Crude bandages (x10)" result = /obj/item/stack/medical/crude_pack - reqs = list(/obj/item/stack/material/cloth = 2) + reqs = list(list(/obj/item/stack/material/cloth = 2)) time = 40 category = CAT_PRIMAL @@ -20,8 +20,8 @@ name = "primitive clothes" result = /obj/item/clothing/under/primitive reqs = list( - /obj/item/stack/material/fiber = 4, - /obj/item/stack/material/cloth = 6 + list(/obj/item/stack/material/fiber = 4), + list(/obj/item/stack/material/cloth = 6) ) time = 90 category = CAT_CLOTHING @@ -30,8 +30,8 @@ name = "primitive shoes" result = /obj/item/clothing/shoes/primitive reqs = list( - /obj/item/stack/material/fiber = 2, - /obj/item/stack/material/cloth = 3 + list(/obj/item/stack/material/fiber = 2), + list(/obj/item/stack/material/cloth = 3) ) time = 60 category = CAT_CLOTHING \ No newline at end of file diff --git a/code/datums/components/crafting/recipes/survival.dm b/code/datums/components/crafting/recipes/survival.dm index 6e0f26dd52..436cada1cf 100644 --- a/code/datums/components/crafting/recipes/survival.dm +++ b/code/datums/components/crafting/recipes/survival.dm @@ -2,10 +2,10 @@ name = "Wooden Shovel" result = /obj/item/weapon/shovel/wood reqs = list( - /obj/item/stack/material/stick = 5, - /obj/item/stack/material/wood = 1, - /obj/item/stack/material/fiber = 3, - /obj/item/stack/material/flint = 1 + list(/obj/item/stack/material/stick = 5), + list(/obj/item/stack/material/wood = 1), + list(/obj/item/stack/material/fiber = 3), + list(/obj/item/stack/material/flint = 1) ) time = 120 category = CAT_WEAPONRY @@ -15,7 +15,7 @@ name = "stone blade" result = /obj/item/weapon/material/knife/stone reqs = list( - /obj/item/stack/material/flint = 2 + list(/obj/item/stack/material/flint = 2) ) time = 60 category = CAT_WEAPONRY @@ -25,10 +25,10 @@ name = "stone knife" result = /obj/item/weapon/material/knife/stone/wood reqs = list( - /obj/item/weapon/material/knife/stone = 1, - /obj/item/stack/material/flint = 1, - /obj/item/stack/material/wood = 1, - /obj/item/stack/material/fiber = 3 + list(/obj/item/weapon/material/knife/stone = 1), + list(/obj/item/stack/material/flint = 1), + list(/obj/item/stack/material/wood = 1), + list(/obj/item/stack/material/fiber = 3) ) time = 120 category = CAT_WEAPONRY @@ -38,10 +38,10 @@ name = "stone knife" result = /obj/item/weapon/material/knife/stone/bone reqs = list( - /obj/item/weapon/material/knife/stone = 1, - /obj/item/stack/material/flint = 1, - /obj/item/weapon/bone = 1, - /obj/item/stack/material/fiber = 3 + list(/obj/item/weapon/material/knife/stone = 1), + list(/obj/item/stack/material/flint = 1), + list(/obj/item/weapon/bone = 1), + list(/obj/item/stack/material/fiber = 3) ) time = 120 category = CAT_WEAPONRY @@ -51,9 +51,9 @@ name = "wooden bucket" result = /obj/item/weapon/reagent_containers/glass/bucket/wood reqs = list( - /obj/item/stack/material/wood = 1, - /obj/item/stack/material/stick = 1, - /obj/item/stack/material/fiber = 2 + list(/obj/item/stack/material/wood = 1), + list(/obj/item/stack/material/stick = 1), + list(/obj/item/stack/material/fiber = 2) ) time = 60 category = CAT_TOOL @@ -61,7 +61,7 @@ /datum/crafting_recipe/sticks name = "sticks" result = /obj/item/stack/material/stick/fivestack - reqs = list(/obj/item/stack/material/wood = 1) + reqs = list(list(/obj/item/stack/material/wood = 1)) tool_paths = list(/obj/item/weapon/material/knife) time = 200 category = CAT_MISC @@ -70,10 +70,10 @@ name = "stone axe" result = /obj/item/weapon/material/knife/machete/hatchet/stone reqs = list( - /obj/item/weapon/material/knife/stone = 1, - /obj/item/stack/material/flint = 1, - /obj/item/stack/material/stick = 10, - /obj/item/stack/material/fiber = 3 + list(/obj/item/weapon/material/knife/stone = 1), + list(/obj/item/stack/material/flint = 1), + list(/obj/item/stack/material/stick = 1), + list(/obj/item/stack/material/fiber = 3) ) time = 120 category = CAT_WEAPONRY @@ -83,10 +83,10 @@ name = "stone axe" result = /obj/item/weapon/material/knife/machete/hatchet/stone/bone reqs = list( - /obj/item/weapon/material/knife/stone = 1, - /obj/item/stack/material/flint = 1, - /obj/item/weapon/bone = 1, - /obj/item/stack/material/fiber = 3 + list(/obj/item/weapon/material/knife/stone = 1), + list(/obj/item/stack/material/flint = 1), + list(/obj/item/weapon/bone = 1), + list(/obj/item/stack/material/fiber = 3) ) time = 120 category = CAT_WEAPONRY @@ -96,10 +96,10 @@ name = "stone spear" result = /obj/item/weapon/material/twohanded/spear/flint reqs = list( - /obj/item/weapon/material/knife/stone = 1, - /obj/item/stack/material/flint = 1, - /obj/item/stack/material/wood = 2, - /obj/item/stack/material/fiber = 3 + list(/obj/item/weapon/material/knife/stone = 1), + list(/obj/item/stack/material/flint = 1), + list(/obj/item/stack/material/wood = 2), + list(/obj/item/stack/material/fiber = 3) ) time = 120 category = CAT_WEAPONRY @@ -109,10 +109,10 @@ name = "stone spear" result = /obj/item/weapon/material/twohanded/spear/flint reqs = list( - /obj/item/weapon/material/knife/stone = 1, - /obj/item/stack/material/flint = 1, - /obj/item/weapon/bone = 2, - /obj/item/stack/material/fiber = 3 + list(/obj/item/weapon/material/knife/stone = 1), + list(/obj/item/stack/material/flint = 1), + list(/obj/item/weapon/bone = 2), + list(/obj/item/stack/material/fiber = 3) ) time = 120 category = CAT_WEAPONRY @@ -121,6 +121,6 @@ /datum/crafting_recipe/ropebindings name = "rope bindings" result = /obj/item/weapon/handcuffs/cable/plantfiber - reqs = list(/obj/item/stack/material/fiber = 3) + reqs = list(list(/obj/item/stack/material/fiber = 3)) time = 60 category = CAT_MISC diff --git a/code/datums/components/crafting/recipes/weapons.dm b/code/datums/components/crafting/recipes/weapons.dm index 4022265137..6baa4b5e9b 100644 --- a/code/datums/components/crafting/recipes/weapons.dm +++ b/code/datums/components/crafting/recipes/weapons.dm @@ -1,9 +1,23 @@ /datum/crafting_recipe/stunprod name = "Stunprod" result = /obj/item/weapon/melee/baton/cattleprod - reqs = list(/obj/item/weapon/handcuffs/cable = 1, - /obj/item/stack/rods = 1, - /obj/item/weapon/tool/wirecutters = 1) + reqs = list(list(/obj/item/weapon/handcuffs/cable = 1), + list(/obj/item/stack/rods = 1), + list(/obj/item/weapon/tool/wirecutters = 1)) + time = 40 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/spear + name = "Spear" + result = /obj/item/weapon/material/twohanded/spear + reqs = list(list(/obj/item/weapon/handcuffs/cable = 1), + list(/obj/item/stack/rods = 1), + list(/obj/item/weapon/material/shard = 1, + /obj/item/weapon/material/butterflyblade = 1) + ) + parts = list(/obj/item/weapon/material/shard = 1, + /obj/item/weapon/material/butterflyblade = 1) time = 40 category = CAT_WEAPONRY subcategory = CAT_WEAPON @@ -11,10 +25,8 @@ /datum/crafting_recipe/shortbow name = "Shortbow" result = /obj/item/weapon/gun/launcher/crossbow/bow - reqs = list( - /obj/item/stack/material/wood = 10, - /obj/item/stack/material/cloth = 5 - ) + reqs = list(list(/obj/item/stack/material/wood = 10), + list(/obj/item/stack/material/cloth = 5)) time = 120 category = CAT_WEAPONRY subcategory = CAT_WEAPON @@ -22,10 +34,8 @@ /datum/crafting_recipe/arrow_sandstone name = "Wood arrow (sandstone tip)" result = /obj/item/weapon/arrow/standard - reqs = list( - /obj/item/stack/material/wood = 2, - /obj/item/stack/material/sandstone = 2 - ) + reqs = list(list(/obj/item/stack/material/wood = 2), + list(/obj/item/stack/material/sandstone = 2)) time = 40 category = CAT_WEAPONRY subcategory = CAT_AMMO @@ -33,10 +43,8 @@ /datum/crafting_recipe/arrow_marble name = "Wood arrow (marble tip)" result = /obj/item/weapon/arrow/standard - reqs = list( - /obj/item/stack/material/wood = 2, - /obj/item/stack/material/marble = 2 - ) + reqs = list(list(/obj/item/stack/material/wood = 2), + list(/obj/item/stack/material/marble = 2)) time = 40 category = CAT_WEAPONRY subcategory = CAT_AMMO