diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index a4ee7cc3cc..e8e91b73f0 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -198,6 +198,7 @@
#define COMSIG_LIVING_EXTINGUISHED "living_extinguished" //from base of mob/living/ExtinguishMob() (/mob/living)
#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" //from base of mob/living/electrocute_act(): (shock_damage)
#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: ()
+#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login" //sent when a mob/login() finishes: (client)
#define COMSIG_LIVING_GUN_PROCESS_FIRE "living_gun_process_fire" //from base of /obj/item/gun/proc/process_fire(): (atom/target, params, zone_override)
// /mob/living/carbon signals
diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm
index dba9a59748..e9f325fb10 100644
--- a/code/_onclick/hud/generic_dextrous.dm
+++ b/code/_onclick/hud/generic_dextrous.dm
@@ -50,11 +50,6 @@
zone_select.update_icon()
static_inventory += zone_select
- using = new /obj/screen/craft
- using.icon = ui_style
- using.hud = src
- static_inventory += using
-
using = new /obj/screen/area_creator
using.icon = ui_style
using.hud = src
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 23e820457c..a6d7286e80 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -91,13 +91,6 @@
var/obj/screen/using
var/obj/screen/inventory/inv_box
- using = new /obj/screen/craft
- using.icon = ui_style
- if(!widescreenlayout) // CIT CHANGE
- using.screen_loc = ui_boxcraft // CIT CHANGE
- using.hud = src
- static_inventory += using
-
using = new/obj/screen/language_menu
using.icon = ui_style
if(!widescreenlayout) // CIT CHANGE
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index c8926507bc..14e1794b4d 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -66,12 +66,6 @@
icon_state = "craft"
screen_loc = ui_crafting
-/obj/screen/craft/Click()
- var/mob/living/M = usr
- if(isobserver(usr))
- return
- M.OpenCraftingMenu()
-
/obj/screen/area_creator
name = "create new area"
icon = 'icons/mob/screen_midnight.dmi'
diff --git a/code/modules/crafting/craft.dm b/code/datums/components/crafting/craft.dm
similarity index 86%
rename from code/modules/crafting/craft.dm
rename to code/datums/components/crafting/craft.dm
index 9f14b07bb5..8e42c48a8a 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/datums/components/crafting/craft.dm
@@ -1,4 +1,17 @@
-/datum/personal_crafting
+/datum/component/personal_crafting/Initialize()
+ if(!ismob(parent))
+ return COMPONENT_INCOMPATIBLE
+ RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, .proc/create_mob_button)
+
+/datum/component/personal_crafting/proc/create_mob_button(mob/user, client/CL)
+ var/datum/hud/H = user.hud_used
+ var/obj/screen/craft/C = new()
+ C.icon = H.ui_style
+ H.static_inventory += C
+ CL.screen += C
+ RegisterSignal(C, COMSIG_CLICK, .proc/component_ui_interact)
+
+/datum/component/personal_crafting
var/busy
var/viewing_category = 1 //typical powergamer starting on the Weapons tab
var/viewing_subcategory = 1
@@ -38,9 +51,6 @@
var/display_craftable_only = FALSE
var/display_compact = TRUE
-
-
-
/* This is what procs do:
get_environment - gets a list of things accessable for crafting by user
get_surroundings - takes a list of things and makes a list of key-types to values-amounts of said type in the list
@@ -50,16 +60,15 @@
del_reqs - takes recipe and a user, loops over the recipes reqs var and tries to find everything in the list make by get_environment and delete it/add to parts list, then returns the said list
*/
-
-
-
-/datum/personal_crafting/proc/check_contents(datum/crafting_recipe/R, list/contents)
+/datum/component/personal_crafting/proc/check_contents(datum/crafting_recipe/R, list/contents)
contents = contents["other"]
main_loop:
for(var/A in R.reqs)
var/needed_amount = R.reqs[A]
for(var/B in contents)
if(ispath(B, A))
+ if (R.blacklist.Find(B))
+ continue
if(contents[B] >= R.reqs[A])
continue main_loop
else
@@ -74,7 +83,7 @@
return 0
return 1
-/datum/personal_crafting/proc/get_environment(mob/user)
+/datum/component/personal_crafting/proc/get_environment(mob/user)
. = list()
for(var/obj/item/I in user.held_items)
. += I
@@ -89,8 +98,10 @@
if(AM.flags_1 & HOLOGRAM_1)
continue
. += AM
+ for(var/slot in list(SLOT_R_STORE, SLOT_L_STORE))
+ . += user.get_item_by_slot(slot)
-/datum/personal_crafting/proc/get_surroundings(mob/user)
+/datum/component/personal_crafting/proc/get_surroundings(mob/user)
. = list()
.["tool_behaviour"] = list()
.["other"] = list()
@@ -111,7 +122,7 @@
.["other"][A.type] += A.volume
.["other"][I.type] += 1
-/datum/personal_crafting/proc/check_tools(mob/user, datum/crafting_recipe/R, list/contents)
+/datum/component/personal_crafting/proc/check_tools(mob/user, datum/crafting_recipe/R, list/contents)
if(!R.tools.len)
return TRUE
var/list/possible_tools = list()
@@ -142,7 +153,7 @@
return FALSE
return TRUE
-/datum/personal_crafting/proc/construct_item(mob/user, datum/crafting_recipe/R)
+/datum/component/personal_crafting/proc/construct_item(mob/user, datum/crafting_recipe/R)
var/list/contents = get_surroundings(user)
var/send_feedback = 1
if(check_contents(R, contents))
@@ -156,9 +167,11 @@
var/list/parts = del_reqs(R, user)
var/atom/movable/I = new R.result (get_turf(user.loc))
I.CheckParts(parts, R)
+ if(isitem(I))
+ user.put_in_hands(I)
if(send_feedback)
SSblackbox.record_feedback("tally", "object_crafted", 1, I.type)
- log_craft("[I] crafted by [user] at [loc_name(I.loc)]")
+ log_craft("[I] crafted by [user] at [loc_name(I.loc)]")
return 0
return "."
return ", missing tool."
@@ -189,7 +202,7 @@
del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already
*/
-/datum/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, mob/user)
+/datum/component/personal_crafting/proc/del_reqs(datum/crafting_recipe/R, mob/user)
var/list/surroundings
var/list/Deletion = list()
. = list()
@@ -287,15 +300,18 @@
Deletion.Cut(Deletion.len)
qdel(DL)
+/datum/component/personal_crafting/proc/component_ui_interact(obj/screen/craft/image, location, control, params, user)
+ if(user == parent)
+ ui_interact(user)
-/datum/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state)
+/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "personal_crafting", "Crafting Menu", 700, 800, master_ui, state)
ui.open()
-/datum/personal_crafting/ui_data(mob/user)
+/datum/component/personal_crafting/ui_data(mob/user)
var/list/data = list()
var/list/subs = list()
var/cur_subcategory = CAT_NONE
@@ -331,21 +347,20 @@
return data
-/datum/personal_crafting/ui_act(action, params)
+/datum/component/personal_crafting/ui_act(action, params)
if(..())
return
switch(action)
if("make")
- var/datum/crafting_recipe/TR = locate(params["recipe"])
+ var/datum/crafting_recipe/TR = locate(params["recipe"]) in GLOB.crafting_recipes
busy = TRUE
- ui_interact(usr) //explicit call to show the busy display
+ ui_interact(usr)
var/fail_msg = construct_item(usr, TR)
if(!fail_msg)
to_chat(usr, "[TR.name] constructed.")
else
to_chat(usr, "Construction failed[fail_msg]")
busy = FALSE
- ui_interact(usr)
if("forwardCat") //Meow
viewing_category = next_cat(FALSE)
. = TRUE
@@ -365,21 +380,20 @@
display_compact = !display_compact
. = TRUE
-
//Next works nicely with modular arithmetic
-/datum/personal_crafting/proc/next_cat(readonly = TRUE)
+/datum/component/personal_crafting/proc/next_cat(readonly = TRUE)
if (!readonly)
viewing_subcategory = 1
. = viewing_category % categories.len + 1
-/datum/personal_crafting/proc/next_subcat()
+/datum/component/personal_crafting/proc/next_subcat()
if(islist(subcategories[viewing_category]))
var/list/subs = subcategories[viewing_category]
. = viewing_subcategory % subs.len + 1
//Previous can go fuck itself
-/datum/personal_crafting/proc/prev_cat(readonly = TRUE)
+/datum/component/personal_crafting/proc/prev_cat(readonly = TRUE)
if (!readonly)
viewing_subcategory = 1
if(viewing_category == categories.len)
@@ -389,7 +403,7 @@
if(. <= 0)
. = categories.len
-/datum/personal_crafting/proc/prev_subcat()
+/datum/component/personal_crafting/proc/prev_subcat()
if(islist(subcategories[viewing_category]))
var/list/subs = subcategories[viewing_category]
if(viewing_subcategory == subs.len)
@@ -402,7 +416,7 @@
. = null
-/datum/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R)
+/datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R)
var/list/data = list()
data["name"] = R.name
data["ref"] = "[REF(R)]"
@@ -441,3 +455,4 @@
if(!learned_recipes)
learned_recipes = list()
learned_recipes |= R
+
\ No newline at end of file
diff --git a/code/modules/crafting/glassware.dm b/code/datums/components/crafting/glassware.dm
similarity index 100%
rename from code/modules/crafting/glassware.dm
rename to code/datums/components/crafting/glassware.dm
diff --git a/code/modules/crafting/guncrafting.dm b/code/datums/components/crafting/guncrafting.dm
similarity index 100%
rename from code/modules/crafting/guncrafting.dm
rename to code/datums/components/crafting/guncrafting.dm
diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm
new file mode 100644
index 0000000000..2b6f1a5b81
--- /dev/null
+++ b/code/datums/components/crafting/recipes.dm
@@ -0,0 +1,25 @@
+/datum/crafting_recipe
+ var/name = "" //in-game display name
+ var/list/reqs = list() //type paths of items consumed associated with how many are needed
+ var/list/blacklist = list() //type paths of items explicitly not allowed as an ingredient
+ var/result //type path of item resulting from this craft
+ var/list/tools = list() //type paths of items needed but not consumed
+ var/time = 30 //time in deciseconds
+ var/list/parts = list() //type paths of items that will be placed in the result
+ var/list/chem_catalysts = list() //like tools but for reagents
+ var/category = CAT_NONE //where it shows up in the crafting UI
+ var/subcategory = CAT_NONE
+ var/always_availible = TRUE //Set to FALSE if it needs to be learned first.
+
+/datum/crafting_recipe/New()
+ if(!(result in reqs))
+ blacklist += result
+
+/**
+ * Run custom pre-craft checks for this recipe
+ *
+ * user: The /mob that initiated the crafting
+ * collected_requirements: A list of lists of /obj/item instances that satisfy reqs. Top level list is keyed by requirement path.
+ */
+/datum/crafting_recipe/proc/check_requirements(mob/user, list/collected_requirements)
+ return TRUE
diff --git a/code/modules/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm
similarity index 100%
rename from code/modules/crafting/recipes/recipes_clothing.dm
rename to code/datums/components/crafting/recipes/recipes_clothing.dm
diff --git a/code/modules/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
similarity index 100%
rename from code/modules/crafting/recipes/recipes_misc.dm
rename to code/datums/components/crafting/recipes/recipes_misc.dm
diff --git a/code/modules/crafting/recipes/recipes_primal.dm b/code/datums/components/crafting/recipes/recipes_primal.dm
similarity index 100%
rename from code/modules/crafting/recipes/recipes_primal.dm
rename to code/datums/components/crafting/recipes/recipes_primal.dm
diff --git a/code/modules/crafting/recipes/recipes_robot.dm b/code/datums/components/crafting/recipes/recipes_robot.dm
similarity index 100%
rename from code/modules/crafting/recipes/recipes_robot.dm
rename to code/datums/components/crafting/recipes/recipes_robot.dm
diff --git a/code/modules/crafting/recipes/recipes_weapon_and_ammo.dm b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm
similarity index 99%
rename from code/modules/crafting/recipes/recipes_weapon_and_ammo.dm
rename to code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm
index a519f00fe9..06f79396b8 100644
--- a/code/modules/crafting/recipes/recipes_weapon_and_ammo.dm
+++ b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm
@@ -18,6 +18,10 @@
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
+/datum/crafting_recipe/strobeshield/New()
+ ..()
+ blacklist |= subtypesof(/obj/item/shield/riot/)
+
/datum/crafting_recipe/makeshiftshield
name = "Makeshift Metal Shield"
result = /obj/item/shield/makeshift
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
deleted file mode 100644
index 2987b52338..0000000000
--- a/code/modules/crafting/recipes.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-/datum/crafting_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_catalysts[] = list() //like tools but for reagents
- var/category = CAT_NONE //where it shows up in the crafting UI
- var/subcategory = CAT_NONE
- var/always_availible = TRUE //Set to FALSE if it needs to be learned first.
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 0f3b3dc6d3..c57091c0aa 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -25,8 +25,7 @@
create_internal_organs() //most of it is done in set_species now, this is only for parent call
physiology = new()
- handcrafting = new()
-
+ AddComponent(/datum/component/personal_crafting)
. = ..()
if(CONFIG_GET(flag/disable_stambuffer))
@@ -45,10 +44,6 @@
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
return ..()
-
-/mob/living/carbon/human/OpenCraftingMenu()
- handcrafting.ui_interact(src)
-
/mob/living/carbon/human/prepare_data_huds()
//Update med hud images...
..()
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 595d60004c..36d9ca541b 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -59,7 +59,6 @@
var/custom_species = null
- var/datum/personal_crafting/handcrafting
var/datum/physiology/physiology
var/list/datum/bioware = list()
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 8b2ef507d9..1b1cab13bb 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -81,7 +81,6 @@
var/dextrous = FALSE //If the creature has, and can use, hands
var/dextrous_hud_type = /datum/hud/dextrous
- var/datum/personal_crafting/handcrafting
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever), AI_Z_OFF (Temporarily off due to nonpresence of players)
var/can_have_ai = TRUE //once we have become sentient, we can never go back
@@ -98,7 +97,6 @@
/mob/living/simple_animal/Initialize()
. = ..()
GLOB.simple_animals[AIStatus] += src
- handcrafting = new()
if(gender == PLURAL)
gender = pick(MALE,FEMALE)
if(!real_name)
@@ -106,6 +104,8 @@
if(!loc)
stack_trace("Simple animal being instantiated in nullspace")
update_simplemob_varspeed()
+ if(dextrous)
+ AddComponent(/datum/component/personal_crafting)
/mob/living/simple_animal/Destroy()
GLOB.simple_animals[AIStatus] -= src
@@ -471,10 +471,6 @@
/mob/living/simple_animal/get_idcard(hand_first = TRUE)
return ..() || access_card
-/mob/living/simple_animal/OpenCraftingMenu()
- if(dextrous)
- handcrafting.ui_interact(src)
-
/mob/living/simple_animal/can_hold_items()
return dextrous
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 4c39d51d90..c266bbddd3 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -53,3 +53,5 @@
CB.Invoke()
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
+ SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
+
diff --git a/tgstation.dme b/tgstation.dme
index ee457b102e..3e3a04b8a9 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -405,6 +405,15 @@
#include "code\datums\components\virtual_reality.dm"
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\wet_floor.dm"
+#include "code\datums\components\crafting\craft.dm"
+#include "code\datums\components\crafting\glassware.dm"
+#include "code\datums\components\crafting\guncrafting.dm"
+#include "code\datums\components\crafting\recipes.dm"
+#include "code\datums\components\crafting\recipes\recipes_clothing.dm"
+#include "code\datums\components\crafting\recipes\recipes_misc.dm"
+#include "code\datums\components\crafting\recipes\recipes_primal.dm"
+#include "code\datums\components\crafting\recipes\recipes_robot.dm"
+#include "code\datums\components\crafting\recipes\recipes_weapon_and_ammo.dm"
#include "code\datums\components\fantasy\_fantasy.dm"
#include "code\datums\components\fantasy\affix.dm"
#include "code\datums\components\fantasy\prefixes.dm"
@@ -1698,15 +1707,6 @@
#include "code\modules\clothing\under\jobs\Plasmaman\engineering.dm"
#include "code\modules\clothing\under\jobs\Plasmaman\medsci.dm"
#include "code\modules\clothing\under\jobs\Plasmaman\security.dm"
-#include "code\modules\crafting\craft.dm"
-#include "code\modules\crafting\glassware.dm"
-#include "code\modules\crafting\guncrafting.dm"
-#include "code\modules\crafting\recipes.dm"
-#include "code\modules\crafting\recipes\recipes_clothing.dm"
-#include "code\modules\crafting\recipes\recipes_misc.dm"
-#include "code\modules\crafting\recipes\recipes_primal.dm"
-#include "code\modules\crafting\recipes\recipes_robot.dm"
-#include "code\modules\crafting\recipes\recipes_weapon_and_ammo.dm"
#include "code\modules\detectivework\detective_work.dm"
#include "code\modules\detectivework\evidence.dm"
#include "code\modules\detectivework\scanner.dm"