diff --git a/baystation12.dme b/baystation12.dme index 34150e695b8..528a42cfd82 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -93,6 +93,7 @@ #include "code\datums\ai_laws.dm" #include "code\datums\browser.dm" #include "code\datums\computerfiles.dm" +#include "code\datums\crafting.dm" #include "code\datums\datacore.dm" #include "code\datums\datumvars.dm" #include "code\datums\disease.dm" diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 13f4742c040..680ceea51a0 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -19,7 +19,6 @@ var/global/list/landmarks_list = list() //list of all landmarks created var/global/list/surgery_steps = list() //list of all surgery steps |BS12 var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12 var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking. -var/global/list/table_recipes = list() //list of all table craft recipes var/global/list/joblist = list() //list of all jobstypes, minus borg and AI //Languages/species/whitelist. @@ -111,8 +110,6 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al if(S.flags & IS_WHITELISTED) whitelisted_species += S.name - init_subtypes(/datum/table_recipe, table_recipes) - /* // Uncomment to debug chemical reaction list. /client/verb/debug_chemical_list() diff --git a/code/datums/crafting.dm b/code/datums/crafting.dm new file mode 100644 index 00000000000..99dc06b05c0 --- /dev/null +++ b/code/datums/crafting.dm @@ -0,0 +1,253 @@ +var/global/datum/crafting_controller/crafting_master = new() + +/datum/crafting_recipe + var/name = "" + var/reqs[] = list() + var/result_path + var/tools[] = list() + var/time = 0 + var/parts[] = list() + var/chem_catalists[] = list() + var/can_be_deconstructed = 0 + +/datum/crafting_recipe/New() + crafting_master.all_crafting_recipes.Add(src) + +/datum/crafting_controller + var/list/families = list() + var/list/all_crafting_points = list() + var/list/all_crafting_recipes = list() + +/datum/crafting_controller/New() + for(var/datum/crafting_recipe/A in typesof(/datum/crafting_recipe)) + all_crafting_recipes.Add(new A()) + +/datum/crafting_controller/proc/add_family(name, list/members) + var/list/family = members + families.Add(name = family) + +/datum/crafting_controller/proc/add_member(family_name, member) + var/list/family = families[family_name] + family.Add(member) + +/datum/crafting_controller/proc/add_recipe_to_family(family_name, datum/recipe) + var/list/family = families[family_name] + for(var/datum/crafting_holder/A in family) + A.add_recipe(recipe) + +/datum/crafting_controller/proc/remove_recipe_from_family(family_name, datum/recipe) + var/list/family = families[family_name] + for(var/datum/crafting_holder/A in family) + A.remove_recipe(recipe) + +/datum/crafting_controller/proc/remove_member(family_name, member) + var/list/family = families[family_name] + family.Remove(member) + +/datum/crafting_controller/proc/remove_family(family_name) + var/list/family = families[family_name] + families.Remove(family) + families.Remove(family_name) + +/datum/crafting_holder + var/name + var/atom/holder + var/recipes + var/busy + +/datum/crafting_holder/New(atom/location) + location.craft_holder = src + crafting_master.all_crafting_points |= src + +/datum/crafting_holder/proc/add_recipe(recipe) + recipes |= recipe + +/datum/crafting_holder/proc/remove_recipe(recipe) + recipes -= recipe + +/datum/crafting_holder/proc/deconstruct(mob/user, datum/crafting_recipe/R) + if(!R.can_be_deconstructed) + return + var/list/result = list() + var/list/holder_contents = check_holder() + var/atom/movable/target = locate(R.result_path) in holder_contents + if(!target) + return + if(check_tools(user, R, holder_contents)) + for(var/A in R.reqs) + var/amount = R.reqs[A] + if(ispath(A, /datum/reagent)) + for(var/obj/item/weapon/reagent_containers/RC in holder_contents) + var/diff = RC.reagents.total_volume - RC.reagents.maximum_volume + if(diff) + diff = min(diff, amount) + var/datum/reagent/C = new A() + C.volume = diff + RC.reagents.reagent_list.Add(C) + RC.reagents.total_volume += diff + result.Add(C) + amount -= diff + if(!amount) + break + else + while(amount) + result.Add(new A(holder.loc)) + amount-- + qdel(target) + return result + +/datum/crafting_holder/proc/check_contents(datum/crafting_recipe/R) + var/list/holder_contents = check_holder() + main_loop: + for(var/A in R.reqs) + for(var/B in holder_contents) + if(ispath(B, A)) + if(holder_contents[B] >= R.reqs[A]) + continue main_loop + return 0 + for(var/A in R.chem_catalists) + if(holder_contents[A] < R.chem_catalists[A]) + return 0 + return 1 + +/datum/crafting_holder/proc/check_holder() + var/list/holder_contents = list() + for(var/obj/I in holder.loc) + if(istype(I, /obj/item/stack)) + var/obj/item/stack/S = I + holder_contents[I.type] += S.amount + else + if(istype(I, /obj/item/weapon/reagent_containers)) + for(var/datum/reagent/R in I.reagents.reagent_list) + holder_contents[R.type] += R.volume + + holder_contents[I.type] += 1 + + return holder_contents + +/datum/crafting_holder/proc/check_tools(mob/user, datum/crafting_recipe/R, list/holder_contents) + if(!R.tools.len) + return 1 + var/list/possible_tools = list() + for(var/obj/item/I in user.contents) + if(istype(I, /obj/item/weapon/storage)) + for(var/obj/item/SI in I.contents) + possible_tools += SI.type + else + possible_tools += I.type + possible_tools += holder_contents + var/i = R.tools.len + var/I + for(var/A in R.tools) + I = possible_tools.Find(A) + if(I) + possible_tools.Cut(I, I+1) + i-- + else + break + return !i + +/datum/crafting_holder/proc/construct_item(mob/user, datum/crafting_recipe/R) + var/list/holder_contents = check_holder() + if(check_contents(R) && check_tools(user, R)) + if(do_after(user, R.time)) + if(!check_contents(R) || !check_tools(user, R, holder_contents)) + return 0 + var/list/parts = del_reqs(R) + var/atom/movable/I = new R.result_path + for(var/A in parts) + if(istype(A, /obj/item)) + var/atom/movable/B = A + B.loc = I + else + if(!I.reagents) + I.reagents = new /datum/reagents() + I.reagents.reagent_list.Add(A) + I.CheckParts() + I.loc = holder.loc + return 1 + return 0 + +/datum/crafting_holder/proc/del_reqs(datum/crafting_recipe/R, list/holder_contents) + var/list/Deletion = list() + var/amt + for(var/A in R.reqs) + amt = R.reqs[A] + if(ispath(A, /obj/item/stack)) + var/obj/item/stack/S + stack_loop: + for(var/B in holder_contents) + if(ispath(B, A)) + while(amt > 0) + S = locate(B) in holder.loc + if(S.amount >= amt) + S.use(amt) + break stack_loop + else + amt -= S.amount + qdel(S) + else if(ispath(A, /obj/item)) + var/obj/item/I + item_loop: + for(var/B in holder_contents) + if(ispath(B, A)) + while(amt > 0) + I = locate(B) in holder.loc + Deletion.Add(I) + amt-- + break item_loop + else + var/datum/reagent/RG = new A + reagent_loop: + for(var/B in holder_contents) + if(ispath(B, /obj/item/weapon/reagent_containers)) + var/obj/item/RC = locate(B) in holder.loc + if(RC.reagents.has_reagent(RG.id, amt)) + RC.reagents.remove_reagent(RG.id, amt) + RG.volume = amt + Deletion.Add(RG) + break reagent_loop + else if(RC.reagents.has_reagent(RG.id)) + Deletion.Add(RG) + RG.volume += RC.reagents.get_reagent_amount(RG.id) + amt -= RC.reagents.get_reagent_amount(RG.id) + RC.reagents.del_reagent(RG.id) + + for(var/A in R.parts) + for(var/B in Deletion) + if(!istype(B, A)) + Deletion.Remove(B) + qdel(B) + return Deletion + +/datum/crafting_holder/proc/interact(mob/user) + var/list/holder_contents = check_holder() + if(!holder_contents.len) + return + var/dat = "

Construction menu

" + dat += "
" + if(busy) + dat += "Construction inprogress...
" + else + for(var/datum/crafting_recipe/R in recipes) + if(check_contents(R)) + dat += "[R.name]
" + dat += "" + + var/datum/browser/popup = new(user, "craft", "Craft", 300, 300) + popup.set_content(dat) + popup.open() + return + +/datum/crafting_holder/Topic(href, href_list) + if(usr.stat || !holder.Adjacent(usr) || usr.lying) + return + if(href_list["make"]) + var/datum/crafting_recipe/TR = locate(href_list["make"]) + busy = 1 + if(construct_item(usr, TR)) + usr << "[TR.name] constructed." + else + usr << "Construction failed." + busy = 0 + interact(usr) \ No newline at end of file diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 25dacdacbc9..32bc87cd5bb 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -10,6 +10,7 @@ var/pass_flags = 0 var/throwpass = 0 var/germ_level = 0 // The higher the germ level, the more germ on the atom. + var/datum/crafting_holder/craft_holder = null ///Chemistry. var/datum/reagents/reagents = null diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 758a5442db1..2247a8d0247 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -10,100 +10,6 @@ /* * Tables */ - -/datum/table_recipe - var/name = "" - var/reqs[] = list() - var/result_path - var/tools[] = list() - var/time = 0 - var/parts[] = list() - var/chem_catalists[] = list() - -/datum/table_recipe/IED - name = "IED" - result_path = /obj/item/weapon/grenade/iedcasing - reqs = list("/obj/item/weapon/handcuffs/cable" = 1, - "/obj/item/stack/cable_coil" = 1, - "/obj/item/device/assembly/igniter" = 1, - "/obj/item/weapon/reagent_containers/food/drinks/cans" = 1, - "/datum/reagent/fuel" = 10) - time = 80 - -/datum/table_recipe/stunprod - name = "Stunprod" - result_path = /obj/item/weapon/melee/baton/cattleprod - reqs = list("/obj/item/weapon/handcuffs/cable" = 1, - "/obj/item/stack/rods" = 1, - "/obj/item/weapon/wirecutters" = 1, - "/obj/item/weapon/cell" = 1) - time = 80 - parts = list("/obj/item/weapon/cell" = 1) - -/datum/table_recipe/ed209 - name = "ED209" - result_path = /obj/machinery/bot/ed209 - reqs = list("/obj/item/robot_parts/robot_suit" = 1, - "/obj/item/clothing/head/helmet" = 1, - "/obj/item/clothing/suit/armor/vest" = 1, - "/obj/item/robot_parts/l_leg" = 1, - "/obj/item/robot_parts/r_leg" = 1, - "/obj/item/stack/sheet/metal" = 5, - "/obj/item/stack/cable_coil" = 5, - "/obj/item/weapon/gun/energy/taser" = 1, - "/obj/item/weapon/cell" = 1, - "/obj/item/device/assembly/prox_sensor" = 1, - "/obj/item/robot_parts/r_arm" = 1) - tools = list(/obj/item/weapon/weldingtool, /obj/item/weapon/screwdriver) - time = 120 - -/datum/table_recipe/secbot - name = "Secbot" - result_path = /obj/machinery/bot/secbot - reqs = list("/obj/item/device/assembly/signaler" = 1, - "/obj/item/clothing/head/helmet" = 1, - "/obj/item/weapon/melee/baton" = 1, - "/obj/item/device/assembly/prox_sensor" = 1, - "/obj/item/robot_parts/r_arm" = 1) - tools = list(/obj/item/weapon/weldingtool) - time = 120 - -/datum/table_recipe/cleanbot - name = "Cleanbot" - result_path = /obj/machinery/bot/cleanbot - reqs = list("/obj/item/weapon/reagent_containers/glass/bucket" = 1, - "/obj/item/device/assembly/prox_sensor" = 1, - "/obj/item/robot_parts/r_arm" = 1) - time = 80 - -/datum/table_recipe/floorbot - name = "Floorbot" - result_path = /obj/machinery/bot/floorbot - reqs = list("/obj/item/weapon/storage/toolbox/mechanical" = 1, - "/obj/item/stack/tile/plasteel" = 1, - "/obj/item/device/assembly/prox_sensor" = 1, - "/obj/item/robot_parts/r_arm" = 1) - time = 80 - -/datum/table_recipe/medbot - name = "Medbot" - result_path = /obj/machinery/bot/medbot - reqs = list("/obj/item/device/healthanalyzer" = 1, - "/obj/item/weapon/storage/firstaid" = 1, - "/obj/item/device/assembly/prox_sensor" = 1, - "/obj/item/robot_parts/r_arm" = 1) - time = 80 - -/datum/table_recipe/flamethrower - name = "Flamethrower" - result_path = /obj/item/weapon/flamethrower - reqs = list("/obj/item/weapon/weldingtool" = 1, - "/obj/item/device/assembly/igniter" = 1, - "/obj/item/stack/rods" = 2) - tools = list(/obj/item/weapon/screwdriver) - time = 20 - - /obj/structure/table name = "table" desc = "A square piece of metal standing on four metal legs. It can not move." @@ -143,191 +49,6 @@ density = 0 qdel(src) -/obj/structure/table/MouseDrop(atom/over) - if(usr.stat || usr.lying || !Adjacent(usr) || (over != usr)) - return - interact(usr) - -/obj/structure/table/proc/check_contents(datum/table_recipe/R) - check_table() - var/I = R.reqs.len - var/i = R.reqs.len - for(var/A in R.reqs) - var/AP = text2path(A) - if(!ispath(AP)) - for(var/B in table_contents) - if(!ispath(B)) - if(table_contents[B] >= R.reqs[A]) - i-- - break - I-- - if(i > I) - return 0 - else - continue - for(var/B in table_contents) - var/BP = text2path(B) - if(ispath(BP, AP)) - if(table_contents[B] >= R.reqs[A]) - i-- - break - I-- - if(i > I) - return 0 - for(var/A in R.chem_catalists) - if(table_contents[A] < R.chem_catalists[A]) - return 0 - return !i - -/obj/structure/table/proc/check_table() - table_contents = list() - for(var/obj/item/I in loc) - if(istype(I, /obj/item/stack)) - var/obj/item/stack/S = I - table_contents["[I.type]"] += S.amount //(table_contents[I.type] ? (table_contents[I.type] + S.amount) : S.amount) - else - if(istype(I, /obj/item/weapon/reagent_containers)) - for(var/datum/reagent/R in I.reagents.reagent_list) - table_contents["[R.type]"] += R.volume - - table_contents["[I.type]"] += 1 //(table_contents[I.type] ? (table_contents[I.type] + 1) : 1) - -/obj/structure/table/proc/check_tools(mob/user, datum/table_recipe/TR) - if(!TR.tools.len) - return 1 - var/list/possible_tools = list() - for(var/obj/item/I in user.contents) - if(istype(I, /obj/item/weapon/storage)) - for(var/obj/item/SI in I.contents) - possible_tools += (SI.type) - else - possible_tools += (I.type) - for(var/obj/item/TI in loc) - possible_tools |= (TI.type) - var/i = TR.tools.len - var/I - for(var/A in TR.tools) - I = possible_tools.Find(A) - if(I) - possible_tools.Cut(I, I+1) - i-- - else - break - return !i - -/obj/structure/table/proc/construct_item(mob/user, datum/table_recipe/TR) - check_table() - if(check_contents(TR) && check_tools(user, TR)) - if(do_after(user, TR.time)) - if(!check_contents(TR) || !check_tools(user, TR)) - return 0 - var/list/parts = del_reqs(TR) - var/atom/movable/I = new TR.result_path - for(var/A in parts) - if(istype(A, /obj/item)) - var/atom/movable/B = A - B.loc = I - else - if(!I.reagents) - I.reagents = new /datum/reagents() - I.reagents.reagent_list.Add(A) - I.CheckParts() - I.loc = loc - return 1 - return 0 - -/obj/structure/table/proc/del_reqs(datum/table_recipe/R) - var/list/Deletion = list() - var/AP - var/BP - var/amt - for(var/A in R.reqs) - amt = R.reqs[A] - AP = text2path(A) - if(ispath(AP, /obj/item/stack)) - var/obj/item/stack/S - stack_loop: - for(var/B in table_contents) - BP = text2path(B) - if(ispath(BP, AP)) - while(amt > 0) - S = locate(BP) in loc - if(S.amount >= amt) - S.use(amt) - break stack_loop - else - amt -= S.amount - del(S) - else if(ispath(AP, /obj/item)) - var/obj/item/I - item_loop: - for(var/B in table_contents) - BP = text2path(B) - if(ispath(BP, AP)) - while(amt > 0) - I = locate(BP) in loc - Deletion.Add(I) - amt-- - break item_loop - else - var/datum/reagent/RG = new AP - reagent_loop: - for(var/B in table_contents) - BP = text2path(B) - if(ispath(BP, /obj/item/weapon/reagent_containers)) - var/obj/item/RC = locate(BP) in loc - if(RC.reagents.has_reagent(RG.id, amt)) - RC.reagents.remove_reagent(RG.id, amt) - RG.volume = amt - Deletion.Add(RG) - break reagent_loop - else if(RC.reagents.has_reagent(RG.id)) - Deletion.Add(RG) - RG.volume += RC.reagents.get_reagent_amount(RG.id) - amt -= RC.reagents.get_reagent_amount(RG.id) - RC.reagents.del_reagent(RG.id) - - for(var/A in R.parts) - AP = text2path(A) - for(var/B in Deletion) - if(!istype(B, AP)) - Deletion.Remove(B) - del(B) - return Deletion - -/obj/structure/table/interact(mob/user) - check_table() - if(!table_contents.len) - return - var/dat = "

Construction menu

" - dat += "
" - if(busy) - dat += "Construction inprogress...
" - else - for(var/datum/table_recipe/R in table_recipes) - if(check_contents(R)) - dat += "[R.name]
" - dat += "" - - var/datum/browser/popup = new(user, "table", "Table", 300, 300) - popup.set_content(dat) - popup.open() - return - -/obj/structure/table/Topic(href, href_list) - if(usr.stat || !Adjacent(usr) || usr.lying) - return - if(href_list["make"]) - var/datum/table_recipe/TR = locate(href_list["make"]) - busy = 1 - interact(usr) - if(construct_item(usr, TR)) - usr << "[TR.name] constructed." - else - usr << "Construction failed." - busy = 0 - attack_hand(usr) - /obj/structure/table/update_icon() if(flipped) var/type = 0