diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 441e48139c8..c80127de905 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -25,6 +25,12 @@ var/global/list/joblist = list() //list of all jobstypes, minus borg and AI
var/global/list/flag_list = list() //list of flags during Nations gamemode
var/global/list/airlocks = list() //list of all airlocks
+
+var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z") //added for Xenoarchaeology, might be useful for other stuff
+
+var/global/list/aibots = list() // AI controlled bots
+var/global/list/table_recipes = list() //list of all table craft recipes
+
//Languages/species/whitelist.
var/global/list/all_species[0]
var/global/list/all_languages[0]
@@ -132,6 +138,8 @@ 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)
return 1
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index bd41e4249f1..20252b0403b 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -49,7 +49,7 @@
return
-/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras","Garbage", "Crafting", "Transfer Controller","Event"))
+/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -101,9 +101,6 @@
if("Cameras")
debug_variables(cameranet)
feedback_add_details("admin_verb","DCameras")
- if("Crafting")
- debug_variables(crafting_master)
- feedback_add_details("admin_verb","DCrafting")
if("Event")
debug_variables(event_manager)
feedback_add_details("admin_verb","DEvent")
diff --git a/code/datums/cargoprofile.dm b/code/datums/cargoprofile.dm
index d2c11e8984b..c2a5ed8bea1 100644
--- a/code/datums/cargoprofile.dm
+++ b/code/datums/cargoprofile.dm
@@ -268,7 +268,7 @@
/obj/item/weapon/aiModule,/obj/item/weapon/airalarm_electronics,/obj/item/weapon/airlock_electronics,/obj/item/weapon/circular_saw,
/obj/item/weapon/cloaking_device,/obj/item/weapon/crowbar,/obj/item/weapon/disk,/obj/item/weapon/firealarm_electronics,/obj/item/weapon/hand_tele,
/obj/item/weapon/hand_labeler,/obj/item/weapon/hemostat,/obj/item/weapon/mop,/obj/item/weapon/locator,/obj/item/weapon/minihoe,
- /obj/item/weapon/packageWrap,/obj/item/weapon/pen,/obj/item/weapon/pickaxe,/obj/item/weapon/pinpointer,
+ /obj/item/stack/packageWrap,/obj/item/weapon/pen,/obj/item/weapon/pickaxe,/obj/item/weapon/pinpointer,
/obj/item/weapon/rcd,/obj/item/weapon/rcd_ammo,/obj/item/weapon/retractor,/obj/item/weapon/rsf,/obj/item/weapon/rsp,/obj/item/weapon/scalpel,
/obj/item/weapon/screwdriver,/obj/item/weapon/shovel,/obj/item/weapon/soap,/obj/item/weapon/stamp,/obj/item/weapon/tray,/obj/item/weapon/weldingtool,
/obj/item/weapon/wirecutters,/obj/item/weapon/wrench,/obj/item/weapon/extinguisher)
diff --git a/code/datums/crafting/crafting.dm b/code/datums/crafting/crafting.dm
deleted file mode 100644
index 71a5d3fbd82..00000000000
--- a/code/datums/crafting/crafting.dm
+++ /dev/null
@@ -1,312 +0,0 @@
-var/global/datum/crafting_controller/crafting_master
-
-/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[name] = src
-
-/datum/crafting_recipe/table/New()
- ..()
- crafting_master.add_recipe_to_family("table", src)
-
-
-/datum/crafting_controller
- var/list/families = list()
- var/list/all_crafting_points = list()
- var/list/all_crafting_recipes = list()
-
-/hook/startup/proc/setupCraftingMaster()
- crafting_master = new /datum/crafting_controller()
- return 1
-
-/datum/crafting_controller/New()
- crafting_master = src
- add_family("table")
- add_family("forge")
- for(var/A in typesof(/datum/crafting_recipe))
- if(A == /datum/crafting_recipe)
- continue
- var/datum/crafting_recipe/CR = new A()
- all_crafting_recipes[CR.name] = CR
-
-/datum/crafting_controller/proc/add_global_recipe(datum/crafting_recipe/CR)
- all_crafting_recipes[CR.name] = CR
-
-/datum/crafting_controller/proc/remove_global_recipe(datum/crafting_recipe/CR)
- all_crafting_recipes[CR.name] = null
- all_crafting_recipes.Remove(CR.name)
-
-/datum/crafting_controller/proc/add_family(name, list/members, list/recipes)
- var/datum/crafting_family/family = new(name, members, recipes)
- families[name] = family
-
-/datum/crafting_controller/proc/get_family_by_name(name)
- return families[name]
-
-/datum/crafting_controller/proc/add_member_to_family(family_name, member)
- var/datum/crafting_family/family = families[family_name]
- family.add_member(member)
-
-/datum/crafting_controller/proc/add_recipe_to_family(family_name, datum/crafting_recipe/recipe)
- var/datum/crafting_family/family = families[family_name]
- family.add_recipe(recipe)
-
-/datum/crafting_controller/proc/remove_recipe_from_family(family_name, datum/crafting_recipe/recipe)
- var/datum/crafting_family/family = families[family_name]
- family.remove_recipe(recipe)
-
-/datum/crafting_controller/proc/remove_member(family_name, member)
- var/datum/crafting_family/family = families[family_name]
- family.remove_member(member)
-
-/datum/crafting_controller/proc/remove_family(family_name)
- var/datum/crafting_family/family = families[family_name]
- del(family)
-
-/datum/crafting_family
- var/name
- var/list/recipes
- var/list/members
-
-/datum/crafting_family/New(new_name, list/new_members = list(), list/new_recipes = list())
- name = new_name
- recipes = new_recipes
- members = new_members
-
-/datum/crafting_family/proc/add_member(datum/crafting_holder/member)
- members |= member
- member.family = src
-
-/datum/crafting_family/proc/remove_member(datum/crafting_holder/member)
- members -= member
- member.family = null
-
-/datum/crafting_family/proc/add_recipe(datum/crafting_recipe/recipe)
- recipes[recipe.name] = recipe
-
-/datum/crafting_family/proc/remove_recipe(datum/crafting_recipe/recipe)
- recipes[recipe.name] = null
- recipes.Remove(recipe.name)
-
-
-/datum/crafting_holder
- var/name
- var/atom/holder
- var/recipes
- var/busy
- var/datum/crafting_family/family
-
-/datum/crafting_holder/New(atom/location, family_name)
- location.craft_holder = src
- holder = location
- spawn(50)
- if(crafting_master)
- crafting_master.all_crafting_points |= src
- if(family_name)
- family = crafting_master.get_family_by_name(family_name)
- if(family)
- recipes = family.recipes
-
-/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, list/holder_contents)
- 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, holder_contents) && check_tools(user, R, holder_contents))
- if(do_after(user, R.time))
- if(!check_contents(R, holder_contents) || !check_tools(user, R, holder_contents))
- return 0
- var/list/parts = del_reqs(R, holder_contents)
- 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/A in recipes)
- var/datum/crafting_recipe/R = recipes[A]
- if(check_contents(R, holder_contents))
- 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"])
- if(busy)
- return
- busy = 1
- interact(usr)
- var/datum/crafting_recipe/TR = locate(href_list["make"])
- if(construct_item(usr, TR))
- usr << "[TR.name] constructed."
- else
- usr << "Construction failed."
- busy = 0
- interact(usr)
diff --git a/code/datums/crafting/recipes.dm b/code/datums/crafting/recipes.dm
deleted file mode 100644
index c2f882eec08..00000000000
--- a/code/datums/crafting/recipes.dm
+++ /dev/null
@@ -1,137 +0,0 @@
-//Basic crafting components -- Using cheap easily found items to create components that can be used to make more complex objects
-
-/datum/crafting_recipe/table/igniter
- name = "Igniter"
- result_path = /obj/item/device/assembly/igniter
- reqs = list(/obj/item/weapon/lighter = 1,
- /obj/item/stack/cable_coil = 1)
- time = 20
-
-/datum/crafting_recipe/table/voice
- name = "Voice analyzer"
- result_path = /obj/item/device/assembly/voice
- reqs = list(/obj/item/device/taperecorder = 1,
- /obj/item/stack/cable_coil = 1)
- time = 20
-
-/datum/crafting_recipe/table/infra
- name = "Infrared Emitter"
- result_path = /obj/item/device/assembly/infra
- reqs = list(/obj/item/device/laser_pointer = 1,
- /obj/item/stack/cable_coil = 1)
- time = 20
-
-//Medium crafting
-
-/datum/crafting_recipe/table/IED
- name = "IED"
- result_path = /obj/item/weapon/grenade/iedcasing
- reqs = list(/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/crafting_recipe/table/stunprod
- name = "Stunprod"
- result_path = /obj/item/weapon/melee/baton/cattleprod
- reqs = list(/obj/item/weapon/restraints/handcuffs/cable = 1,
- /obj/item/stack/rods = 1,
- /obj/item/weapon/wirecutters = 1,
- /obj/item/weapon/stock_parts/cell = 1)
- time = 80
- parts = list(/obj/item/weapon/stock_parts/cell = 1)
-
-/datum/crafting_recipe/table/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
-
-/datum/crafting_recipe/table/meteorshot
- name = "Meteorshot Shell"
- result_path = /obj/item/ammo_casing/shotgun/meteorshot
- reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
- /obj/item/weapon/rcd_ammo = 1,
- /obj/item/weapon/stock_parts/manipulator = 2)
- tools = list(/obj/item/weapon/screwdriver)
- time = 5
-
-/datum/crafting_recipe/table/pulseslug
- name = "Pulse Slug Shell"
- result_path = /obj/item/ammo_casing/shotgun/pulseslug
- reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
- /obj/item/weapon/stock_parts/capacitor/adv = 2,
- /obj/item/weapon/stock_parts/micro_laser/ultra = 1)
- tools = list(/obj/item/weapon/screwdriver)
- time = 5
-
-/datum/crafting_recipe/table/dragonsbreath
- name = "Dragonsbreath Shell"
- result_path = /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath
- reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
- /datum/reagent/phosphorus = 5,)
- tools = list(/obj/item/weapon/screwdriver)
- time = 5
-
-//Advanced crafting
-
-/datum/crafting_recipe/table/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/advtaser = 1,
- /obj/item/weapon/stock_parts/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/crafting_recipe/table/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/crafting_recipe/table/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/crafting_recipe/table/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/crafting_recipe/table/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
-
-
-/////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index a3fbd9c9f86..0795d4dca7e 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -1114,7 +1114,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/device/camera_film,
/obj/item/device/camera_film,
/obj/item/weapon/storage/photo_album,
- /obj/item/weapon/packageWrap,
+ /obj/item/stack/packageWrap,
/obj/item/weapon/reagent_containers/glass/paint/red,
/obj/item/weapon/reagent_containers/glass/paint/green,
/obj/item/weapon/reagent_containers/glass/paint/blue,
@@ -1124,9 +1124,9 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/weapon/reagent_containers/glass/paint/white,
/obj/item/weapon/reagent_containers/glass/paint/remover,
/obj/item/weapon/contraband/poster,
- /obj/item/weapon/wrapping_paper,
- /obj/item/weapon/wrapping_paper,
- /obj/item/weapon/wrapping_paper)
+ /obj/item/stack/wrapping_paper,
+ /obj/item/stack/wrapping_paper,
+ /obj/item/stack/wrapping_paper)
cost = 10
containername = "Arts and Crafts crate"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 51eec5190f3..2a7f975e46b 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -9,7 +9,6 @@
var/last_bumped = 0
var/pass_flags = 0
var/throwpass = 0
- var/datum/crafting_holder/craft_holder = null
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
///Chemistry.
diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm
index 53b3d7d6c5d..255d6faa4e2 100644
--- a/code/game/machinery/Freezer.dm
+++ b/code/game/machinery/Freezer.dm
@@ -97,13 +97,13 @@
data["on"] = on ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
- data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C)
+ data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C,1)
if(air_contents.total_moles == 0 && air_contents.temperature == 0)
data["gasTemperatureCelsius"] = 0
data["minGasTemperature"] = round(min_temperature)
data["maxGasTemperature"] = round(T20C)
data["targetGasTemperature"] = round(current_temperature)
- data["targetGasTemperatureCelsius"] = round(current_temperature - T0C)
+ data["targetGasTemperatureCelsius"] = round(current_temperature - T0C,1)
var/temp_class = "good"
if (air_contents.temperature > (T0C - 20))
@@ -254,13 +254,13 @@
data["on"] = on ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
- data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C)
+ data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C,1)
if(air_contents.total_moles == 0 && air_contents.temperature == 0)
data["gasTemperatureCelsius"] = 0
data["minGasTemperature"] = round(T20C)
data["maxGasTemperature"] = round(T20C+max_temperature)
data["targetGasTemperature"] = round(current_temperature)
- data["targetGasTemperatureCelsius"] = round(current_temperature - T0C)
+ data["targetGasTemperatureCelsius"] = round(current_temperature - T0C,1)
var/temp_class = "normal"
if (air_contents.temperature > (T20C+40))
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index b510d6be4f6..56a78e1065c 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -133,6 +133,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
new/datum/stack_recipe("wooden chair", /obj/structure/stool/bed/chair/wood/normal, 3, time = 10, one_per_turf = 1, on_floor = 1), \
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), \
diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm
index a1bd6e79f47..314566fe81d 100644
--- a/code/game/objects/items/weapons/gift_wrappaper.dm
+++ b/code/game/objects/items/weapons/gift_wrappaper.dm
@@ -118,81 +118,14 @@
/*
* Wrapping Paper
*/
-/obj/item/weapon/wrapping_paper
+/obj/item/stack/wrapping_paper
name = "wrapping paper"
desc = "You can use this to wrap items in."
icon = 'icons/obj/items.dmi'
icon_state = "wrap_paper"
- var/amount = 20.0
+ flags = NOBLUDGEON
+ amount = 25
+ max_amount = 25
-/obj/item/weapon/wrapping_paper/attackby(obj/item/weapon/W as obj, mob/user as mob)
- ..()
- if (!( locate(/obj/structure/table, src.loc) ))
- user << "\blue You MUST put the paper on a table!"
- if (W.w_class < 4)
- if ((istype(user.l_hand, /obj/item/weapon/wirecutters) || istype(user.r_hand, /obj/item/weapon/wirecutters)))
- var/a_used = 2 ** (src.w_class - 1)
- if (src.amount < a_used)
- user << "\blue You need more paper!"
- return
- else
- if(istype(W, /obj/item/smallDelivery) || istype(W, /obj/item/weapon/gift)) //No gift wrapping gifts!
- return
-
- src.amount -= a_used
- user.drop_item()
- var/obj/item/weapon/gift/G = new /obj/item/weapon/gift( src.loc )
- G.size = W.w_class
- G.w_class = G.size + 1
- G.icon_state = text("gift[]", G.size)
- G.gift = W
- W.loc = G
- G.add_fingerprint(user)
- W.add_fingerprint(user)
- src.add_fingerprint(user)
- if (src.amount <= 0)
- new /obj/item/weapon/c_tube( src.loc )
- del(src)
- return
- else
- user << "\blue You need scissors!"
- else
- user << "\blue The object is FAR too large!"
- return
-
-
-/obj/item/weapon/wrapping_paper/examine()
- set src in oview(1)
-
- ..()
- usr << text("There is about [] square units of paper left!", src.amount)
- return
-
-/obj/item/weapon/wrapping_paper/attack(mob/target as mob, mob/user as mob)
- if (!istype(target, /mob/living/carbon/human)) return
- var/mob/living/carbon/human/H = target
-
- if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket) || H.stat)
- if (src.amount > 2)
- var/obj/effect/spresent/present = new /obj/effect/spresent (H.loc)
- src.amount -= 2
-
- if (H.client)
- H.client.perspective = EYE_PERSPECTIVE
- H.client.eye = present
-
- H.loc = present
-
- H.attack_log += text("\[[time_stamp()]\] Has been wrapped with [src.name] by [user.name] ([user.ckey])")
- user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to wrap [H.name] ([H.ckey])")
- log_attack("[user.name] ([user.ckey]) used the [src.name] to wrap [H.name] ([H.ckey])")
-
- if(!iscarbon(user))
- H.LAssailant = null
- else
- H.LAssailant = user
-
- else
- user << "\blue You need more paper."
- else
- user << "They are moving around too much. A straightjacket would help."
\ No newline at end of file
+/obj/item/stack/wrapping_paper/attack_self(mob/user)
+ user << "You need to use it on a package that has already been wrapped!"
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index ba7fae62304..3b6da3c7c2a 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -26,15 +26,9 @@
update_icon()
-/obj/item/weapon/grenade/chem_grenade/examine()
- set src in usr
- usr << desc
- if(stage >= WIRED)
- if(nadeassembly)
- usr << nadeassembly.a_left.describe()
- usr << nadeassembly.a_right.describe()
- else
- usr << "The timer is set to [det_time/10] second\s."
+/obj/item/weapon/grenade/chem_grenade/examine(mob/user)
+ display_timer = (stage == READY && !nadeassembly) //show/hide the timer based on assembly state
+ ..()
/obj/item/weapon/grenade/chem_grenade/proc/get_trigger()
diff --git a/code/game/objects/items/weapons/grenades/ghettobomb.dm b/code/game/objects/items/weapons/grenades/ghettobomb.dm
index e4301755a92..848ab4ac101 100644
--- a/code/game/objects/items/weapons/grenades/ghettobomb.dm
+++ b/code/game/objects/items/weapons/grenades/ghettobomb.dm
@@ -1,64 +1,39 @@
//improvised explosives//
-//iedcasing assembly crafting//
-/obj/item/weapon/reagent_containers/food/drinks/cans/attackby(var/obj/item/I, mob/user as mob)
- if(istype(I, /obj/item/device/assembly/igniter))
- var/obj/item/device/assembly/igniter/G = I
- var/obj/item/weapon/grenade/iedcasing/W = new /obj/item/weapon/grenade/iedcasing
- user.unEquip(G)
- user.unEquip(src)
- user.put_in_hands(W)
- user << "You stuff the [I] in the [src], emptying the contents beforehand."
- W.underlays += image(src.icon, icon_state = src.icon_state)
- del(I)
- del(src)
-
-
/obj/item/weapon/grenade/iedcasing
- name = "improvised explosive assembly"
- desc = "An igniter stuffed into an aluminum shell."
+ name = "improvised firebomb"
+ desc = "A weak, improvised incendiary device."
w_class = 2.0
icon = 'icons/obj/grenade.dmi'
icon_state = "improvised_grenade"
item_state = "flashbang"
- throw_speed = 4
- throw_range = 20
+ throw_speed = 3
+ throw_range = 7
flags = CONDUCT
slot_flags = SLOT_BELT
- var/assembled = 0
- active = 1
+ active = 0
det_time = 50
+ display_timer = 0
+ var/range = 3
+ var/times = list()
+/obj/item/weapon/grenade/iedcasing/New(loc)
+ ..()
+ overlays += image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_filled")
+ overlays += image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_wired")
+ times = list("5" = 10, "-1" = 20, "[rand(30,80)]" = 50, "[rand(65,180)]" = 20)// "Premature, Dud, Short Fuse, Long Fuse"=[weighting value]
+ det_time = text2num(pickweight(times))
+ if(det_time < 0) //checking for 'duds'
+ range = 1
+ det_time = rand(30,80)
+ else
+ range = pick(2,2,2,3,3,3,4)
+/obj/item/weapon/grenade/iedcasing/CheckParts()
+ var/obj/item/weapon/reagent_containers/food/drinks/cans/can = locate() in contents
+ if(can)
+ underlays += can
-/obj/item/weapon/grenade/iedcasing/afterattack(atom/target, mob/user , flag) //Filling up the can
- if(assembled == 0)
- if( istype(target, /obj/structure/reagent_dispensers/fueltank))
- if(target.reagents.total_volume < 50)
- user << "There's not enough fuel left to work with."
- return
- var/obj/structure/reagent_dispensers/fueltank/F = target
- F.reagents.remove_reagent("fuel", 50, 1)//Deleting 50 fuel from the welding fuel tank,
- assembled = 1
- user << "You've filled the makeshift explosive with welding fuel."
- playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6)
- desc = "An improvised explosive assembly. Filled to the brim with 'Explosive flavor'"
- overlays += image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_filled")
- return
-
-
-/obj/item/weapon/grenade/iedcasing/attackby(var/obj/item/I, mob/user as mob) //Wiring the can for ignition
- if(istype(I, /obj/item/stack/cable_coil))
- if(assembled == 1)
- var/obj/item/stack/cable_coil/C = I
- C.use(1)
- assembled = 2
- user << "You wire the igniter to detonate the fuel."
- desc = "A weak, improvised explosive."
- overlays += image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_wired")
- name = "improvised explosive"
- active = 0
- det_time = rand(30,80)
/obj/item/weapon/grenade/iedcasing/attack_self(mob/user as mob) //
if(!active)
@@ -67,14 +42,12 @@
active = 1
overlays -= image('icons/obj/grenade.dmi', icon_state = "improvised_grenade_filled")
icon_state = initial(icon_state) + "_active"
- assembled = 3
add_fingerprint(user)
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
- var/log_str = "[key_name(usr)]? has primed a [name] for detonation at [A.name] (JMP)."
- msg_admin_attack(log_str)
- log_game(log_str)
- bombers += "[log_str]"
+
+ message_admins("[key_name(usr)]? has primed a [name] for detonation at [A.name] (JMP).")
+ log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).")
if(iscarbon(user))
var/mob/living/carbon/C = user
C.throw_mode_on()
@@ -82,14 +55,10 @@
prime()
/obj/item/weapon/grenade/iedcasing/prime() //Blowing that can up
-// update_mob()
-// explosion(epicenter, 1, 2, 3, 3)
- explosion(src.loc,0,0,2,2)
- del(src)
+ update_mob()
+ explosion(src.loc,-1,-1,-1, flame_range = range) // no explosive damage, only a large fireball.
+ qdel(src)
-/obj/item/weapon/grenade/iedcasing/examine()
- set src in usr
- usr << desc
- if(assembled == 3)
- usr << "You can't tell when it will explode!" //Stops you from checking the time to detonation unlike regular grenades
- return
\ No newline at end of file
+/obj/item/weapon/grenade/iedcasing/examine(mob/user)
+ ..()
+ user << "You can't tell when it will explode!"
diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm
index c0ddc3c2359..5b5e25ff384 100644
--- a/code/game/objects/items/weapons/grenades/grenade.dm
+++ b/code/game/objects/items/weapons/grenades/grenade.dm
@@ -11,6 +11,7 @@
slot_flags = SLOT_BELT
var/active = 0
var/det_time = 50
+ var/display_timer = 1
/obj/item/weapon/grenade/proc/clown_check(var/mob/living/user)
if((M_CLUMSY in user.mutations) && prob(50))
@@ -45,13 +46,12 @@
/obj/item/weapon/grenade/examine()
- set src in usr
- usr << desc
- if(det_time > 1)
- usr << "The timer is set to [det_time/10] seconds."
- return
- usr << "\The [src] is set for instant detonation."
-
+ ..()
+ if(display_timer)
+ if(det_time > 1)
+ usr << "The timer is set to [det_time/10] second\s."
+ else
+ usr << "\The [src] is set for instant detonation."
/obj/item/weapon/grenade/attack_self(mob/user as mob)
if(!active)
diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm
index 5c66dd46bcb..9b12b3dcc46 100644
--- a/code/game/objects/random/random.dm
+++ b/code/game/objects/random/random.dm
@@ -94,7 +94,7 @@
item_to_spawn()
return pick(prob(3);/obj/random/powercell,\
prob(2);/obj/random/technology_scanner,\
- prob(1);/obj/item/weapon/packageWrap,\
+ prob(1);/obj/item/stack/packageWrap,\
prob(2);/obj/random/bomb_supply,\
prob(1);/obj/item/weapon/extinguisher,\
prob(1);/obj/item/clothing/gloves/fyellow,\
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 8887609a1a6..1054dbfcb1e 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -265,7 +265,7 @@
return
if(W)
W.loc = src.loc
- else if(istype(W, /obj/item/weapon/packageWrap))
+ else if(istype(W, /obj/item/stack/packageWrap))
return
else if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
index 23dc36da2a1..3f60559f0fe 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
@@ -94,7 +94,7 @@
else
for(var/mob/O in viewers(user, 3))
O.show_message("The locker has been broken by [user] with an electromagnetic card!", 1, "You hear a faint electrical spark.", 2)
- else if(istype(W,/obj/item/weapon/packageWrap) || istype(W,/obj/item/weapon/weldingtool))
+ else if(istype(W,/obj/item/stack/packageWrap) || istype(W,/obj/item/weapon/weldingtool))
return ..(W,user)
else
togglelock(user)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 019eacd96ed..9df3987af5f 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -138,7 +138,7 @@
return
if(W)
W.loc = src.loc
- else if(istype(W, /obj/item/weapon/packageWrap))
+ else if(istype(W, /obj/item/stack/packageWrap))
return
else if(istype(W, /obj/item/stack/cable_coil))
if(rigged)
@@ -247,7 +247,7 @@
src.toggle(user)
/obj/structure/closet/crate/secure/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if(is_type_in_list(W, list(/obj/item/weapon/packageWrap, /obj/item/stack/cable_coil, /obj/item/device/radio/electropack, /obj/item/weapon/wirecutters)))
+ if(is_type_in_list(W, list(/obj/item/stack/packageWrap, /obj/item/stack/cable_coil, /obj/item/device/radio/electropack, /obj/item/weapon/wirecutters)))
return ..()
if(locked && (istype(W, /obj/item/weapon/card/emag)||istype(W, /obj/item/weapon/melee/energy/blade)))
overlays.Cut()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 02a645d919e..676250d27a0 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -24,7 +24,6 @@
var/parts = /obj/item/weapon/table_parts
var/flipped = 0
var/health = 100
- var/list/table_contents = list()
var/busy = 0
/obj/structure/table/proc/update_adjacent()
@@ -41,9 +40,6 @@
update_icon()
update_adjacent()
- spawn(5)
- craft_holder = new /datum/crafting_holder(src, "table")
-
/obj/structure/table/Destroy()
update_adjacent()
..()
@@ -53,11 +49,6 @@
density = 0
qdel(src)
-/obj/structure/table/MouseDrop(atom/over)
- if(usr.stat || usr.lying || !Adjacent(usr) || (over != usr))
- return
- craft_holder.interact(usr)
-
/obj/structure/table/update_icon()
if(flipped)
var/type = 0
diff --git a/code/global.dm b/code/global.dm
index ef6a3959f2c..7871eb70493 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -327,11 +327,5 @@ var/score_dmgestkey = null
// Recall time limit: 2 hours
var/recall_time_limit=72000
-//added for Xenoarchaeology, might be useful for other stuff
-var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
-
-// AI controlled bots
-var/global/list/aibots = list()
-
// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it.
-var/global/obj/item/device/radio/intercom/global_announcer = new(null)
\ No newline at end of file
+var/global/obj/item/device/radio/intercom/global_announcer = new(null)
diff --git a/code/modules/crafting/guncrafting.dm b/code/modules/crafting/guncrafting.dm
new file mode 100644
index 00000000000..a466b2431d6
--- /dev/null
+++ b/code/modules/crafting/guncrafting.dm
@@ -0,0 +1,83 @@
+// This file is for projectile weapon crafting. All parts and construction paths will be contained here.
+// The weapons themselves are children of other weapons and should be contained in their respective files.
+
+// PARTS //
+
+/obj/item/weaponcrafting/receiver
+ name = "modular receiver"
+ desc = "A prototype modular receiver and trigger assembly for a firearm."
+ icon = 'icons/obj/improvised.dmi'
+ icon_state = "receiver"
+
+/obj/item/weaponcrafting/stock
+ name = "rifle stock"
+ desc = "A classic rifle stock that doubles as a grip, roughly carved out of wood."
+ icon = 'icons/obj/improvised.dmi'
+ icon_state = "riflestock"
+
+
+// CRAFTING //
+
+/obj/item/weaponcrafting/receiver/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W,/obj/item/pipe))
+ user << "You attach the shotgun barrel to the receiver. The pins seem loose."
+ var/obj/item/weaponcrafting/ishotgunconstruction/I = new /obj/item/weaponcrafting/ishotgunconstruction
+ user.unEquip(src)
+ user.put_in_hands(I)
+ del(W)
+ del(src)
+ return
+
+// SHOTGUN //
+
+/obj/item/weaponcrafting/ishotgunconstruction
+ name = "slightly conspicuous metal construction"
+ desc = "A long pipe attached to a firearm receiver. The pins seem loose."
+ icon = 'icons/obj/improvised.dmi'
+ icon_state = "ishotgunstep1"
+
+/obj/item/weaponcrafting/ishotgunconstruction/attackby(var/obj/item/I, mob/user as mob)
+ ..()
+ if(istype(I, /obj/item/weapon/screwdriver))
+ var/obj/item/weaponcrafting/ishotgunconstruction2/C = new /obj/item/weaponcrafting/ishotgunconstruction2
+ user.unEquip(src)
+ user.put_in_hands(C)
+ user << "You screw the pins into place, securing the pipe to the receiver."
+ qdel(src)
+
+/obj/item/weaponcrafting/ishotgunconstruction2
+ name = "very conspicuous metal construction"
+ desc = "A long pipe attached to a trigger assembly."
+ icon = 'icons/obj/improvised.dmi'
+ icon_state = "ishotgunstep1"
+
+/obj/item/weaponcrafting/ishotgunconstruction2/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W,/obj/item/weaponcrafting/stock))
+ user << "You attach the stock to the receiver-barrel assembly."
+ var/obj/item/weaponcrafting/ishotgunconstruction3/I = new /obj/item/weaponcrafting/ishotgunconstruction3
+ user.unEquip(src)
+ user.put_in_hands(I)
+ del(W)
+ del(src)
+ return
+
+/obj/item/weaponcrafting/ishotgunconstruction3
+ name = "extremely conspicuous metal construction"
+ desc = "A receiver-barrel shotgun assembly with a loose wooden stock. There's no way you can fire it without the stock coming loose."
+ icon = 'icons/obj/improvised.dmi'
+ icon_state = "ishotgunstep2"
+
+/obj/item/weaponcrafting/ishotgunconstruction3/attackby(var/obj/item/I, mob/user as mob)
+ ..()
+ if(istype(I, /obj/item/stack/packageWrap))
+ var/obj/item/stack/packageWrap/C = I
+ if (C.use(5))
+ var/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/W = new /obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised
+ user.unEquip(src)
+ user.put_in_hands(W)
+ user << "You tie the wrapping paper around the stock and the barrel to secure it."
+ qdel(src)
+ else
+ user << "You need at least five feet of wrapping paper to secure the stock."
+ return
+
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
new file mode 100644
index 00000000000..b1eeae11fca
--- /dev/null
+++ b/code/modules/crafting/recipes.dm
@@ -0,0 +1,138 @@
+/datum/table_recipe
+ var/name = "" //in-game display name
+ var/reqs[] = list() //type paths of items consumed associated with how many are needed
+ var/result //type path of item resulting from this craft
+ var/tools[] = list() //type paths of items needed but not consumed
+ var/time = 30 //time in deciseconds
+ var/parts[] = list() //type paths of items that will be placed in the result
+ var/chem_catalists[] = list() //like tools but for reagents
+
+
+/datum/table_recipe/IED
+ name = "IED"
+ result = /obj/item/weapon/grenade/iedcasing
+ reqs = list(/datum/reagent/fuel = 50,
+ /obj/item/stack/cable_coil = 1,
+ /obj/item/device/assembly/igniter = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans = 1)
+ parts = list(/obj/item/weapon/reagent_containers/food/drinks/cans = 1)
+ time = 80
+
+/datum/table_recipe/stunprod
+ name = "Stunprod"
+ result = /obj/item/weapon/melee/baton/cattleprod
+ reqs = list(/obj/item/weapon/restraints/handcuffs/cable = 1,
+ /obj/item/stack/rods = 1,
+ /obj/item/weapon/wirecutters = 1,
+ /obj/item/weapon/stock_parts/cell = 1)
+ time = 80
+ parts = list(/obj/item/weapon/stock_parts/cell = 1)
+
+/datum/table_recipe/ed209
+ name = "ED209"
+ result = /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/advtaser = 1,
+ /obj/item/weapon/stock_parts/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 = /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 = /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 = /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 = /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 = /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
+
+/datum/table_recipe/meteorshot
+ name = "Meteorshot Shell"
+ result = /obj/item/ammo_casing/shotgun/meteorshot
+ reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
+ /obj/item/weapon/rcd_ammo = 1,
+ /obj/item/weapon/stock_parts/manipulator = 2)
+ tools = list(/obj/item/weapon/screwdriver)
+ time = 5
+
+/datum/table_recipe/pulseslug
+ name = "Pulse Slug Shell"
+ result = /obj/item/ammo_casing/shotgun/pulseslug
+ reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
+ /obj/item/weapon/stock_parts/capacitor/adv = 2,
+ /obj/item/weapon/stock_parts/micro_laser/ultra = 1)
+ tools = list(/obj/item/weapon/screwdriver)
+ time = 5
+
+/datum/table_recipe/dragonsbreath
+ name = "Dragonsbreath Shell"
+ result = /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath
+ reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
+ /datum/reagent/phosphorus = 5,)
+ tools = list(/obj/item/weapon/screwdriver)
+ time = 5
+
+/datum/table_recipe/frag12
+ name = "FRAG-12 Shell"
+ result = /obj/item/ammo_casing/shotgun/frag12
+ reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1,
+ /datum/reagent/glycerol = 5,
+ /datum/reagent/sacid = 5,
+ /datum/reagent/pacid = 5,)
+ tools = list(/obj/item/weapon/screwdriver)
+ time = 5
+
+/datum/table_recipe/ishotgun
+ name = "Improvised Shotgun"
+ result = /obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised
+ reqs = list(/obj/item/weaponcrafting/receiver = 1,
+ /obj/item/pipe = 1,
+ /obj/item/weaponcrafting/stock = 1,
+ /obj/item/stack/packageWrap = 5,)
+ tools = list(/obj/item/weapon/screwdriver)
+ time = 200
\ No newline at end of file
diff --git a/code/modules/crafting/table.dm b/code/modules/crafting/table.dm
new file mode 100644
index 00000000000..1d4bfa561e9
--- /dev/null
+++ b/code/modules/crafting/table.dm
@@ -0,0 +1,200 @@
+#define TABLECRAFT_MAX_ITEMS 30
+
+/obj/structure/table
+ var/list/table_contents = list()
+
+/obj/structure/table/MouseDrop(atom/over)
+ if(over != usr)
+ return
+ interact(usr)
+
+/obj/structure/table/proc/check_contents(datum/table_recipe/R)
+ check_table()
+ main_loop:
+ for(var/A in R.reqs)
+ for(var/B in table_contents)
+ if(ispath(B, A))
+ if(table_contents[B] >= R.reqs[A])
+ continue main_loop
+ return 0
+ for(var/A in R.chem_catalists)
+ if(table_contents[A] < R.chem_catalists[A])
+ return 0
+ return 1
+
+/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
+ else
+ if(istype(I, /obj/item/weapon/reagent_containers))
+ var/obj/item/weapon/reagent_containers/RC = I
+ if(RC.flags & OPENCONTAINER)
+ for(var/datum/reagent/A in RC.reagents.reagent_list)
+ table_contents[A.type] += A.volume
+ table_contents[I.type] += 1
+
+/obj/structure/table/proc/check_tools(mob/user, datum/table_recipe/R)
+ 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 += table_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
+
+/obj/structure/table/proc/construct_item(mob/user, datum/table_recipe/R)
+ check_table()
+ if(check_contents(R) && check_tools(user, R))
+ if(do_after(user, R.time))
+ if(!check_contents(R) || !check_tools(user, R))
+ return 0
+ var/atom/movable/I = new R.result (loc)
+ var/list/parts = del_reqs(R, I)
+ 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()
+ return 1
+ return 0
+
+/obj/structure/table/proc/del_reqs(datum/table_recipe/R, atom/movable/resultobject)
+ var/list/Deletion = list()
+ var/amt
+ var/reagenttransfer = 0
+ if(istype(resultobject,/obj/item/weapon/reagent_containers))
+ reagenttransfer = 1
+ 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 table_contents)
+ if(ispath(B, A))
+ while(amt > 0)
+ S = locate(B) in 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 table_contents)
+ if(ispath(B, A))
+ while(amt > 0)
+ I = locate(B) in loc
+ Deletion.Add(I)
+ I.loc = null //remove it from the table loc so that we don't locate the same item every time (will be relocated inside the crafted item in construct_item())
+ amt--
+ if(reagenttransfer && istype(I,/obj/item/weapon/reagent_containers))
+ var/obj/item/weapon/reagent_containers/RC = I
+ RC.reagents.trans_to(resultobject, RC.reagents.total_volume)
+ break item_loop
+ else
+ var/datum/reagent/RG = new A
+ reagent_loop:
+ for(var/B in table_contents)
+ if(ispath(B, /obj/item/weapon/reagent_containers))
+ var/obj/item/RC = locate(B) in loc
+ if(RC.reagents.has_reagent(RG.id, amt))
+ if(reagenttransfer)
+ RC.reagents.trans_id_to(resultobject,RG.id, amt)
+ else
+ 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)
+ if(reagenttransfer)
+ RC.reagents.trans_id_to(resultobject,RG.id, RG.volume)
+ else
+ RC.reagents.del_reagent(RG.id)
+
+ var/list/partlist = list(R.parts.len)
+ for(var/M in R.parts)
+ partlist[M] = R.parts[M]
+ deletion_loop:
+ for(var/B in Deletion)
+ for(var/A in R.parts)
+ if(istype(B, A))
+ if(partlist[A] > 0) //do we still need a part like that?
+ partlist[A] -= 1
+ continue deletion_loop
+ Deletion.Remove(B)
+ qdel(B)
+
+ return Deletion
+
+/obj/structure/table/interact(mob/user)
+ if(user.stat || user.lying || !Adjacent(user))
+ return
+ check_table()
+ if(!table_contents.len)
+ return
+ user.face_atom(src)
+ var/dat = "Crafting menu
"
+ dat += ""
+ if(busy)
+ dat += "Crafting in progress...
"
+ 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"])
+ if(!check_table_space())
+ usr << "The table is too crowded."
+ return
+ 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
+ interact(usr)
+
+/obj/structure/table/proc/check_table_space()
+ var/Item_amount = 0
+ for(var/obj/item/I in loc)
+ Item_amount++
+ if(Item_amount <= TABLECRAFT_MAX_ITEMS) //is the table crowded?
+ return 1
+
+ #undef TABLECRAFT_MAX_ITEMS
\ No newline at end of file
diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm
index 27a669cf98f..34d21554b07 100644
--- a/code/modules/projectiles/ammunition/ammo_casings.dm
+++ b/code/modules/projectiles/ammunition/ammo_casings.dm
@@ -95,6 +95,12 @@
desc = "An incendiary-coated shotgun slug."
icon_state = "ishell"
projectile_type = "/obj/item/projectile/bullet/incendiary/shell"
+
+/obj/item/ammo_casing/shotgun/frag12
+ name = "FRAG-12 slug"
+ desc = "A high explosive breaching round for a 12 gauge shotgun."
+ icon_state = "heshell"
+ projectile_type = /obj/item/projectile/bullet/frag12
/obj/item/ammo_casing/shotgun/incendiary/dragonsbreath
name = "dragonsbreath shell"
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index e2e643a1111..f143e5bbcdb 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -205,4 +205,9 @@ obj/item/projectile/kinetic/New()
/obj/item/effect/kinetic_blast/New()
spawn(4)
- del(src)
\ No newline at end of file
+ del(src)
+
+/obj/item/projectile/bullet/frag12
+ name ="explosive slug"
+ damage = 25
+ weaken = 5
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index 7f3689cc99b..ea9b0b6023c 100755
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -1,157 +1,189 @@
/obj/structure/bigDelivery
- desc = "A big wrapped package."
name = "large parcel"
+ desc = "A big wrapped package."
icon = 'icons/obj/storage.dmi'
icon_state = "deliverycloset"
- var/obj/wrapped = null
density = 1
- var/sortTag = 0
- flags = NOBLUDGEON
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
+ var/obj/wrapped = null
+ var/giftwrapped = 0
+ var/sortTag = 0
- attack_hand(mob/user as mob)
- if(wrapped) //sometimes items can disappear. For example, bombs. --rastaf0
- wrapped.loc = (get_turf(src.loc))
- if(istype(wrapped, /obj/structure/closet))
- var/obj/structure/closet/O = wrapped
- O.welded = 0
- del(src)
- return
- attackby(obj/item/W as obj, mob/user as mob)
- if(istype(W, /obj/item/device/destTagger))
- var/obj/item/device/destTagger/O = W
+/obj/structure/bigDelivery/attack_hand(mob/user as mob)
+ qdel(src)
- if(src.sortTag != O.currTag)
- var/tag = uppertext(TAGGERLOCATIONS[O.currTag])
- user << "\blue *[tag]*"
- src.sortTag = O.currTag
- playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1)
+/obj/structure/bigDelivery/Destroy()
+ if(wrapped) //sometimes items can disappear. For example, bombs. --rastaf0
+ wrapped.loc = (get_turf(loc))
+ if(istype(wrapped, /obj/structure/closet))
+ var/obj/structure/closet/O = wrapped
+ O.welded = 0
+ var/turf/T = get_turf(src)
+ for(var/atom/movable/AM in contents)
+ AM.loc = T
+ ..()
+
+/obj/structure/bigDelivery/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/device/destTagger))
+ var/obj/item/device/destTagger/O = W
+
+ if(sortTag != O.currTag)
+ var/tag = uppertext(TAGGERLOCATIONS[O.currTag])
+ user << "*[tag]*"
+ sortTag = O.currTag
+ playsound(loc, 'sound/machines/twobeep.ogg', 100, 1)
+
+ else if(istype(W, /obj/item/weapon/pen))
+ var/str = copytext(sanitize(input(user,"Label text?","Set label","")),1,MAX_NAME_LEN)
+ if(!str || !length(str))
+ user << "Invalid text."
+ return
+ user.visible_message("[user] labels [src] as [str].")
+ name = "[name] ([str])"
+
+ else if(istype(W, /obj/item/stack/wrapping_paper) && !giftwrapped)
+ var/obj/item/stack/wrapping_paper/WP = W
+ if(WP.use(3))
+ user.visible_message("[user] wraps the package in festive paper!")
+ giftwrapped = 1
+ if(istype(wrapped, /obj/structure/closet/crate))
+ icon_state = "giftcrate"
+ else
+ icon_state = "giftcloset"
+ if(WP.amount <= 0 && !WP.loc) //if we used our last wrapping paper, drop a cardboard tube
+ new /obj/item/weapon/c_tube( get_turf(user) )
+ else
+ user << "You need more paper."
- else if(istype(W, /obj/item/weapon/pen))
- var/str = sanitize(copytext(input(usr,"Label text?","Set label",""),1,MAX_NAME_LEN))
- if(!str || !length(str))
- usr << "\red Invalid text."
- return
- for(var/mob/M in viewers())
- M << "\blue [user] labels [src] as [str]."
- src.name = "[src.name] ([str])"
- return
/obj/item/smallDelivery
- desc = "A small wrapped package."
name = "small parcel"
+ desc = "A small wrapped package."
icon = 'icons/obj/storage.dmi'
icon_state = "deliverycrateSmall"
var/obj/item/wrapped = null
+ var/giftwrapped = 0
var/sortTag = 0
- attack_self(mob/user as mob)
- if (src.wrapped) //sometimes items can disappear. For example, bombs. --rastaf0
- wrapped.loc = user.loc
- if(ishuman(user))
- user.put_in_hands(wrapped)
- else
- wrapped.loc = get_turf_loc(src)
+/obj/item/smallDelivery/attack_self(mob/user as mob)
+ if(wrapped && wrapped.loc) //sometimes items can disappear. For example, bombs. --rastaf0
+ wrapped.loc = user.loc
+ if(ishuman(user))
+ user.put_in_hands(wrapped)
+ else
+ wrapped.loc = get_turf(src)
- del(src)
- return
-
- attackby(obj/item/W as obj, mob/user as mob)
- if(istype(W, /obj/item/device/destTagger))
- var/obj/item/device/destTagger/O = W
-
- if(src.sortTag != O.currTag)
- var/tag = uppertext(TAGGERLOCATIONS[O.currTag])
- user << "\blue *[tag]*"
- src.sortTag = O.currTag
- playsound(src.loc, 'sound/machines/twobeep.ogg', 100, 1)
-
- else if(istype(W, /obj/item/weapon/pen))
- var/str = sanitize(copytext(input(usr,"Label text?","Set label",""),1,MAX_NAME_LEN))
- if(!str || !length(str))
- usr << "\red Invalid text."
- return
- for(var/mob/M in viewers())
- M << "\blue [user] labels [src] as [str]."
- src.name = "[src.name] ([str])"
- return
+ qdel(src)
-/obj/item/weapon/packageWrap
+/obj/item/smallDelivery/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/device/destTagger))
+ var/obj/item/device/destTagger/O = W
+
+ if(sortTag != O.currTag)
+ var/tag = uppertext(TAGGERLOCATIONS[O.currTag])
+ user << "*[tag]*"
+ sortTag = O.currTag
+ playsound(loc, 'sound/machines/twobeep.ogg', 100, 1)
+
+ else if(istype(W, /obj/item/weapon/pen))
+ var/str = copytext(sanitize(input(user,"Label text?","Set label","")),1,MAX_NAME_LEN)
+ if(!str || !length(str))
+ user << "Invalid text."
+ return
+ user.visible_message("[user] labels [src] as [str].")
+ name = "[name] ([str])"
+
+ else if(istype(W, /obj/item/stack/wrapping_paper) && !giftwrapped)
+ var/obj/item/stack/wrapping_paper/WP = W
+ if(WP.use(1))
+ icon_state = "giftcrate[wrapped.w_class]"
+ giftwrapped = 1
+ user.visible_message("[user] wraps the package in festive paper!")
+ if(WP.amount <= 0 && !WP.loc) //if we used our last wrapping paper, drop a cardboard tube
+ new /obj/item/weapon/c_tube( get_turf(user) )
+ else
+ user << "You need more paper."
+
+
+
+/obj/item/stack/packageWrap
name = "package wrapper"
icon = 'icons/obj/items.dmi'
icon_state = "deliveryPaper"
- w_class = 3.0
- var/amount = 25.0
+ flags = NOBLUDGEON
+ amount = 25
+ max_amount = 25
- afterattack(var/obj/target as obj, mob/user as mob, proximity)
- if(!proximity) return
- if(!istype(target)) //this really shouldn't be necessary (but it is). -Pete
- return
- if(istype(target, /obj/item/smallDelivery) || istype(target,/obj/structure/bigDelivery) \
- || istype(target, /obj/item/weapon/gift) || istype(target, /obj/item/weapon/evidencebag))
- return
- if(target.anchored)
- return
- if(target in user)
- return
-
- user.attack_log += text("\[[time_stamp()]\] Has used [src.name] on \ref[target]")
+/obj/item/stack/packageWrap/afterattack(var/obj/target as obj, mob/user as mob, proximity)
+ if(!proximity) return
+ if(!istype(target)) //this really shouldn't be necessary (but it is). -Pete
+ return
+ if(istype(target, /obj/item/smallDelivery) || istype(target,/obj/structure/bigDelivery) \
+ || istype(target, /obj/item/weapon/evidencebag) || istype(target, /obj/structure/closet/body_bag))
+ return
+ if(target.anchored)
+ return
+ if(target in user)
+ return
- if (istype(target, /obj/item) && !(istype(target, /obj/item/weapon/storage) && !istype(target,/obj/item/weapon/storage/box)))
- var/obj/item/O = target
- if (src.amount > 1)
- var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(O.loc)) //Aaannd wrap it up!
- if(!istype(O.loc, /turf))
- if(user.client)
- user.client.screen -= O
- P.wrapped = O
- O.loc = P
- var/i = round(O.w_class)
- if(i in list(1,2,3,4,5))
- P.icon_state = "deliverycrate[i]"
- P.add_fingerprint(usr)
- O.add_fingerprint(usr)
- src.add_fingerprint(usr)
- src.amount -= 1
- else if (istype(target, /obj/structure/closet/crate))
- var/obj/structure/closet/crate/O = target
- if (src.amount > 3 && !O.opened)
- var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
- P.icon_state = "deliverycrate"
- P.wrapped = O
- O.loc = P
- src.amount -= 3
- else if(src.amount < 3)
- user << "\blue You need more paper."
- else if (istype (target, /obj/structure/closet))
- var/obj/structure/closet/O = target
- if (src.amount > 3 && !O.opened)
- var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
- P.wrapped = O
- O.welded = 1
- O.loc = P
- src.amount -= 3
- else if(src.amount < 3)
- user << "\blue You need more paper."
+
+ if(istype(target, /obj/item) && !(istype(target, /obj/item/weapon/storage) && !istype(target,/obj/item/weapon/storage/box)))
+ var/obj/item/O = target
+ if(use(1))
+ var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(O.loc)) //Aaannd wrap it up!
+ if(!istype(O.loc, /turf))
+ if(user.client)
+ user.client.screen -= O
+ P.wrapped = O
+ O.loc = P
+ var/i = round(O.w_class)
+ if(i in list(1,2,3,4,5))
+ P.icon_state = "deliverycrate[i]"
+ P.w_class = i
+ P.add_fingerprint(usr)
+ O.add_fingerprint(usr)
+ add_fingerprint(usr)
else
- user << "\blue The object you are trying to wrap is unsuitable for the sorting machinery!"
- if (src.amount <= 0)
- new /obj/item/weapon/c_tube( src.loc )
- del(src)
return
+ else if(istype(target, /obj/structure/closet/crate))
+ var/obj/structure/closet/crate/O = target
+ if(O.opened)
+ return
+ if(use(3))
+ var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
+ P.icon_state = "deliverycrate"
+ P.wrapped = O
+ O.loc = P
+ else
+ user << "You need more paper."
+ return
+ else if(istype (target, /obj/structure/closet))
+ var/obj/structure/closet/O = target
+ if(O.opened)
+ return
+ if(use(3))
+ var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
+ P.wrapped = O
+ O.welded = 1
+ O.loc = P
+ else
+ user << "You need more paper."
+ return
+ else
+ user << "The object you are trying to wrap is unsuitable for the sorting machinery."
return
- examine()
- if(src in usr)
- usr << "\blue There are [amount] units of package wrap left!"
- ..()
- return
+ user.visible_message("[user] wraps [target].")
+ user.attack_log += text("\[[time_stamp()]\] Has used [name] on [target]")
+ if(amount <= 0 && !src.loc) //if we used our last wrapping paper, drop a cardboard tube
+ new /obj/item/weapon/c_tube( get_turf(user) )
+ return
/obj/item/device/destTagger
name = "destination tagger"
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 399f226e15c..51b007cf7ab 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -78,6 +78,16 @@
build_path = /obj/item/weapon/gun/energy/lasercannon
locked = 1
category = list("Weapons")
+
+/datum/design/receiver
+ name = "Modular Receiver"
+ desc = "A prototype modular receiver and trigger assembly for a variety of firearms."
+ id = "receiver"
+ req_tech = list("combat" = 5, "materials" = 4)
+ build_type = PROTOLATHE
+ materials = list("$metal" = 6500, "$silver" = 500)
+ build_path = /obj/item/weaponcrafting/receiver
+ category = list("Weapons")
/datum/design/plasmapistol
name = "Plasma Pistol"
diff --git a/icons/obj/improvised.dmi b/icons/obj/improvised.dmi
new file mode 100644
index 00000000000..a6dfa330e8c
Binary files /dev/null and b/icons/obj/improvised.dmi differ
diff --git a/maps/cyberiad.dmm b/maps/cyberiad.dmm
index 7593acf08e4..d9ea2465791 100644
--- a/maps/cyberiad.dmm
+++ b/maps/cyberiad.dmm
@@ -1984,7 +1984,7 @@
"aMh" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/wall,/area)
"aMi" = (/obj/machinery/door/airlock/maintenance{name = "Library Maintenance"; req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/fsmaint2)
"aMj" = (/obj/item/device/radio/intercom{pixel_y = 25},/obj/structure/table/woodentable,/obj/item/weapon/dice/d20,/obj/item/weapon/dice,/turf/simulated/floor/wood,/area/library)
-"aMk" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/obj/structure/table/woodentable,/obj/item/weapon/paper_bin{pixel_x = 1; pixel_y = 9},/obj/item/weapon/packageWrap,/turf/simulated/floor/wood,/area/library)
+"aMk" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/obj/structure/table/woodentable,/obj/item/weapon/paper_bin{pixel_x = 1; pixel_y = 9},/obj/item/stack/packageWrap,/turf/simulated/floor/wood,/area/library)
"aMl" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/turf/simulated/floor/wood,/area/library)
"aMm" = (/obj/machinery/door/airlock/maintenance{name = "Crematorium Maintenance"; req_access_txt = "27"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/fsmaint2)
"aMn" = (/obj/structure/closet/wardrobe/chaplain_black,/obj/item/device/radio/intercom{pixel_y = 25},/turf/simulated/floor{icon_state = "grimy"},/area/chapel/office)
@@ -2025,7 +2025,7 @@
"aMW" = (/obj/structure/stool{pixel_y = 8},/obj/effect/landmark/start{name = "Civilian"},/turf/simulated/floor,/area/storage/primary)
"aMX" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/turf/simulated/floor,/area/storage/primary)
"aMY" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor,/area/storage/primary)
-"aMZ" = (/obj/structure/table,/obj/item/weapon/weldingtool,/obj/item/weapon/crowbar,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/turf/simulated/floor,/area/storage/primary)
+"aMZ" = (/obj/structure/table,/obj/item/weapon/weldingtool,/obj/item/weapon/crowbar,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/turf/simulated/floor,/area/storage/primary)
"aNa" = (/obj/structure/sign/securearea,/turf/simulated/wall/r_wall,/area/security/nuke_storage)
"aNb" = (/obj/machinery/door/airlock/vault{icon_state = "door_locked"; locked = 1; req_access_txt = "53"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{icon_state = "vault"; dir = 5},/area/security/nuke_storage)
"aNc" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable{d2 = 4; icon_state = "0-4"},/turf/simulated/floor,/area/gateway)
@@ -2318,7 +2318,7 @@
"aSD" = (/obj/machinery/alarm{pixel_y = 23},/turf/simulated/floor,/area/hallway/primary/central/ne)
"aSE" = (/turf/simulated/floor,/area/hallway/primary/central/ne)
"aSF" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 4},/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar)
-"aSG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/table/reinforced,/obj/item/weapon/packageWrap,/obj/item/weapon/pen/blue{pixel_x = 0; pixel_y = 4},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/structure/disposalpipe/segment{dir = 4},/obj/item/weapon/book/manual/barman_recipes,/obj/item/clothing/suit/jacket,/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar)
+"aSG" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/table/reinforced,/obj/item/stack/packageWrap,/obj/item/weapon/pen/blue{pixel_x = 0; pixel_y = 4},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/structure/disposalpipe/segment{dir = 4},/obj/item/weapon/book/manual/barman_recipes,/obj/item/clothing/suit/jacket,/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar)
"aSH" = (/obj/structure/disposalpipe/segment{dir = 4},/mob/living/carbon/monkey{tag = "icon-punpun1"; name = "Pun Pun"; icon_state = "punpun1"},/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar)
"aSI" = (/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar)
"aSJ" = (/turf/simulated/floor{icon_state = "grimy"},/area/crew_quarters/bar)
@@ -2888,7 +2888,7 @@
"bdB" = (/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/condiment/saltshaker{pixel_x = -2; pixel_y = 4},/obj/item/weapon/reagent_containers/food/condiment/peppermill{pixel_x = 2; pixel_y = 6},/turf/simulated/floor/wood,/area/crew_quarters/bar)
"bdC" = (/obj/structure/closet/secure_closet/freezer/kitchen,/turf/simulated/floor{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/kitchen)
"bdD" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/table,/turf/simulated/floor{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/kitchen)
-"bdE" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/condiment/enzyme{layer = 5},/obj/item/weapon/packageWrap,/turf/simulated/floor{icon_state = "cafeteria"; dir = 2},/area/crew_quarters/kitchen)
+"bdE" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/condiment/enzyme{layer = 5},/obj/item/stack/packageWrap,/turf/simulated/floor{icon_state = "cafeteria"; dir = 2},/area/crew_quarters/kitchen)
"bdF" = (/obj/structure/table,/obj/item/weapon/storage/box/donkpockets{pixel_x = 3; pixel_y = 3},/obj/item/weapon/reagent_containers/glass/beaker{pixel_x = 5},/turf/simulated/floor{icon_state = "cafeteria"; dir = 2},/area/crew_quarters/kitchen)
"bdG" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/condiment/saltshaker{pixel_x = -3; pixel_y = 0},/obj/item/weapon/reagent_containers/food/condiment/peppermill{pixel_x = 3},/turf/simulated/floor{icon_state = "cafeteria"; dir = 2},/area/crew_quarters/kitchen)
"bdH" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/turf/simulated/floor{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/kitchen)
@@ -3228,8 +3228,8 @@
"bkd" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor,/area/quartermaster/office)
"bke" = (/turf/simulated/floor,/area/quartermaster/office)
"bkf" = (/obj/item/weapon/storage/box,/obj/structure/table,/obj/item/weapon/storage/box,/obj/item/weapon/storage/box,/obj/item/device/radio/intercom{broadcasting = 0; listening = 1; name = "Station Intercom (General)"; pixel_y = 20},/turf/simulated/floor{icon_state = "arrival"; dir = 1},/area/quartermaster/office)
-"bkg" = (/obj/structure/table,/obj/item/weapon/wrapping_paper,/obj/item/weapon/wrapping_paper,/obj/machinery/requests_console{department = "Cargo Bay"; departmentType = 2; pixel_y = 30},/turf/simulated/floor{icon_state = "arrival"; dir = 1},/area/quartermaster/office)
-"bkh" = (/obj/structure/table,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/turf/simulated/floor{icon_state = "arrival"; dir = 5},/area/quartermaster/office)
+"bkg" = (/obj/structure/table,/obj/machinery/requests_console{department = "Cargo Bay"; departmentType = 2; pixel_y = 30},/turf/simulated/floor{icon_state = "arrival"; dir = 1},/area/quartermaster/office)
+"bkh" = (/obj/structure/table,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/turf/simulated/floor{icon_state = "arrival"; dir = 5},/area/quartermaster/office)
"bki" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = -32; pixel_y = 0},/turf/simulated/floor{dir = 8; icon_state = "browncorner"},/area/hallway/primary/central/west)
"bkj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor,/area/hallway/primary/central/west)
"bkk" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/poddoor/shutters{density = 0; dir = 8; icon_state = "shutter0"; id = "heads_meeting"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area)
@@ -3816,7 +3816,7 @@
"bvt" = (/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/toxins/lab)
"bvu" = (/obj/machinery/r_n_d/protolathe,/turf/simulated/floor{dir = 5; icon_state = "warning"},/area/toxins/lab)
"bvv" = (/obj/machinery/hologram/holopad,/turf/simulated/floor{icon_state = "white"},/area/toxins/lab)
-"bvw" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 32; pixel_y = 0},/obj/structure/table,/obj/item/weapon/packageWrap,/obj/item/weapon/packageWrap,/obj/item/weapon/pen,/obj/item/weapon/hand_labeler,/turf/simulated/floor{icon_state = "white"},/area/toxins/lab)
+"bvw" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 32; pixel_y = 0},/obj/structure/table,/obj/item/stack/packageWrap,/obj/item/weapon/pen,/obj/item/weapon/hand_labeler,/turf/simulated/floor{icon_state = "white"},/area/toxins/lab)
"bvx" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/weapon/tank/oxygen,/obj/item/weapon/storage/belt/utility,/obj/item/clothing/mask/breath,/turf/simulated/floor/plating,/area/maintenance/asmaint2)
"bvy" = (/obj/machinery/airlock_sensor{frequency = 1380; id_tag = "admin_shuttle_dock_sensor"; pixel_x = -30; pixel_y = 8},/turf/simulated/floor{dir = 10; icon_state = "warning"},/area/hallway/secondary/entry)
"bvz" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1380; id_tag = "admin_shuttle_dock_pump"},/turf/simulated/floor{dir = 6; icon_state = "warning"},/area/hallway/secondary/entry)
@@ -3863,7 +3863,7 @@
"bwo" = (/obj/machinery/chem_dispenser,/turf/simulated/floor{icon_state = "white"},/area/medical/chemistry)
"bwp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{icon_state = "white"},/area/medical/chemistry)
"bwq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/disposalpipe/segment,/turf/simulated/floor{icon_state = "white"},/area/medical/chemistry)
-"bwr" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/table/reinforced,/obj/item/weapon/packageWrap,/obj/item/device/mass_spectrometer/adv,/turf/simulated/floor{icon_state = "white"},/area/medical/chemistry)
+"bwr" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/table/reinforced,/obj/item/stack/packageWrap,/obj/item/device/mass_spectrometer/adv,/turf/simulated/floor{icon_state = "white"},/area/medical/chemistry)
"bws" = (/obj/structure/sign/redcross{desc = "The Star of Life, a symbol of Medical Aid."; icon_state = "lifestar"; name = "Medbay"},/turf/simulated/wall/r_wall,/area)
"bwt" = (/turf/simulated/floor{tag = "icon-whiteblue (SOUTHWEST)"; icon_state = "whiteblue"; dir = 10},/area/medical/reception)
"bwu" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{tag = "icon-whiteblue"; icon_state = "whiteblue"},/area/medical/reception)
@@ -3940,7 +3940,7 @@
"bxN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor,/area/hallway/primary/central/sw)
"bxO" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 1; on = 1},/obj/item/device/radio/intercom{dir = 4; name = "Station Intercom (General)"; pixel_x = 27},/turf/simulated/floor{dir = 2; icon_state = "redcorner"},/area/hallway/primary/central/sw)
"bxP" = (/obj/machinery/computer/secure_data,/obj/machinery/flasher_button{id = "hopflash"; pixel_x = 6; pixel_y = 36},/obj/machinery/door_control{id = "hopqueue"; name = "Queue Privacy Shutters Control"; pixel_x = -4; pixel_y = 25; req_access_txt = "28"},/obj/machinery/door_control{id = "hop"; name = "Privacy Shutters Control"; pixel_x = 6; pixel_y = 25; req_access_txt = "28"},/obj/machinery/light_switch{pixel_x = -4; pixel_y = 36},/turf/simulated/floor{dir = 9; icon_state = "blue"},/area/crew_quarters/heads)
-"bxQ" = (/obj/structure/table,/obj/machinery/newscaster/security_unit{pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/media/receiver/boombox,/obj/item/weapon/packageWrap,/obj/item/weapon/hand_labeler,/turf/simulated/floor,/area/crew_quarters/heads)
+"bxQ" = (/obj/structure/table,/obj/machinery/newscaster/security_unit{pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/media/receiver/boombox,/obj/item/stack/packageWrap,/obj/item/weapon/hand_labeler,/turf/simulated/floor,/area/crew_quarters/heads)
"bxR" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/machinery/recharger/wallcharger{pixel_x = 0; pixel_y = 30},/turf/simulated/floor,/area/crew_quarters/heads)
"bxS" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/power/apc{dir = 1; name = "Head of Personnel APC"; pixel_y = 24},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/photocopier,/turf/simulated/floor,/area/crew_quarters/heads)
"bxT" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/simulated/floor,/area/crew_quarters/heads)
@@ -4340,7 +4340,7 @@
"bFx" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/obj/effect/decal/warning_stripes/south,/turf/simulated/floor,/area/teleporter)
"bFy" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/effect/decal/warning_stripes/south,/turf/simulated/floor,/area/teleporter)
"bFz" = (/obj/effect/decal/warning_stripes/south,/turf/simulated/floor,/area/teleporter)
-"bFA" = (/obj/machinery/shieldwallgen,/obj/structure/window/basic{dir = 8},/obj/effect/decal/warning_stripes/yellow/hollow,/turf/simulated/floor,/area/teleporter)
+"bFA" = (/obj/machinery/shieldwallgen,/obj/effect/decal/warning_stripes/yellow/hollow,/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor,/area/teleporter)
"bFB" = (/obj/machinery/shieldwallgen,/obj/effect/decal/warning_stripes/yellow/hollow,/turf/simulated/floor,/area/teleporter)
"bFC" = (/obj/structure/closet/crate,/turf/simulated/floor,/area/teleporter)
"bFD" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/sign/securearea{pixel_x = -32; pixel_y = 0},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{icon_state = "blue"; dir = 8},/area/hallway/primary/central/sw)
@@ -5491,7 +5491,7 @@
"cbE" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_medical{id_tag = null; name = "Secondary Storage"; req_access_txt = "39"},/turf/simulated/floor,/area/medical/biostorage)
"cbF" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/door/airlock/maintenance{name = "Medbay Maintenance Access"; req_access_txt = "5"},/turf/simulated/floor/plating,/area/maintenance/asmaint)
"cbG" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/sign/redcross{desc = "The Star of Life, a symbol of Medical Aid."; icon_state = "lifestar"; name = "Medbay"},/turf/simulated/wall,/area)
-"cbH" = (/obj/machinery/light,/obj/structure/table,/obj/item/weapon/packageWrap,/obj/item/weapon/hand_labeler,/turf/simulated/floor{icon_state = "white"},/area/toxins/telesci)
+"cbH" = (/obj/machinery/light,/obj/structure/table,/obj/item/stack/packageWrap,/obj/item/weapon/hand_labeler,/turf/simulated/floor{icon_state = "white"},/area/toxins/telesci)
"cbI" = (/obj/machinery/power/apc{cell_type = 5000; dir = 2; name = "Bridge APC"; pixel_y = -24},/obj/structure/cable,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/table,/obj/item/device/radio,/turf/simulated/floor{icon_state = "white"},/area/toxins/telesci)
"cbJ" = (/obj/machinery/camera{c_tag = "Research Telescience"; dir = 1; network = list("Research","SS13")},/obj/structure/disposalpipe/trunk{dir = 4},/obj/machinery/disposal,/turf/simulated/floor{icon_state = "white"},/area/toxins/telesci)
"cbK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor{icon_state = "white"},/area/toxins/telesci)
diff --git a/paradise.dme b/paradise.dme
index 3b01e089723..b4e9cc5423e 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -192,8 +192,6 @@
#include "code\datums\sun.dm"
#include "code\datums\supplypacks.dm"
#include "code\datums\uplink_item.dm"
-#include "code\datums\crafting\crafting.dm"
-#include "code\datums\crafting\recipes.dm"
#include "code\datums\helper_datums\construction_datum.dm"
#include "code\datums\helper_datums\events.dm"
#include "code\datums\helper_datums\global_iterator.dm"
@@ -1026,6 +1024,9 @@
#include "code\modules\computer3\computers\robot.dm"
#include "code\modules\computer3\computers\security.dm"
#include "code\modules\computer3\computers\welcome.dm"
+#include "code\modules\crafting\guncrafting.dm"
+#include "code\modules\crafting\recipes.dm"
+#include "code\modules\crafting\table.dm"
#include "code\modules\customitems\item_defines.dm"
#include "code\modules\customitems\item_spawning.dm"
#include "code\modules\customitems\definitions\base.dm"