From e6a147e3da2881ecec1cc1bfe9bb3b68f5d4c265 Mon Sep 17 00:00:00 2001
From: Divulf <134484326+Divulf@users.noreply.github.com>
Date: Thu, 7 Mar 2024 03:42:49 +1300
Subject: [PATCH] Puts some of the stack crafting code onto the stack recipe
datum. (#24252)
* Puts some of the stack crafting code onto the stack recipe datum to allow for more and easier customization of what happens when a recipe is crafted.
* Very important spacing.
* Better returns.
* Removed \the macro, fixed bug in message that occurs when lacking resources for a construction.
* The do_after() should probably be on do_build()
---
code/game/objects/items/stacks/stack.dm | 68 ++------------
.../game/objects/items/stacks/stack_recipe.dm | 91 +++++++++++++++++--
2 files changed, 87 insertions(+), 72 deletions(-)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 9a23693e8cd..59fbda65aa8 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -213,75 +213,19 @@
message_admins("[key_name_admin(usr)] just attempted to href exploit sheet crafting with an invalid multiplier. Ban highly advised.")
multiplier = 1
- if(get_amount() < R.req_amount * multiplier)
- if(R.req_amount * multiplier > 1)
- to_chat(usr, "You haven't got enough [src] to build \the [R.req_amount * multiplier] [R.title]\s!")
- else
- to_chat(usr, "You haven't got enough [src] to build \the [R.title]!")
- return FALSE
-
- if(R.window_checks && !valid_window_location(get_turf(src), usr.dir))
- to_chat(usr, "\The [R.title] won't fit here!")
- return FALSE
-
- if(R.one_per_turf && (locate(R.result_type) in get_turf(src)))
- to_chat(usr, "There is another [R.title] here!")
- return FALSE
-
- if(R.on_floor && !issimulatedturf(get_turf(src)))
- to_chat(usr, "\The [R.title] must be constructed on the floor!")
- return FALSE
- if(R.on_floor_or_lattice && !(issimulatedturf(get_turf(src)) || locate(/obj/structure/lattice) in get_turf(src)))
- to_chat(usr, "\The [R.title] must be constructed on the floor or lattice!")
- return FALSE
-
- if(R.cult_structure)
- if(usr.holy_check())
- return
- if(!is_level_reachable(usr.z))
- to_chat(usr, "The energies of this place interfere with the metal shaping!")
- return
- if(locate(/obj/structure/cult) in get_turf(src))
- to_chat(usr, "There is a structure here!")
- return FALSE
-
- if(R.time)
- to_chat(usr, "Building [R.title]...")
- if(!do_after(usr, R.time, target = loc))
- return FALSE
-
- if(R.cult_structure && locate(/obj/structure/cult) in get_turf(src)) //Check again after do_after to prevent queuing construction exploit.
- to_chat(usr, "There is a structure here!")
- return FALSE
-
- if(get_amount() < R.req_amount * multiplier)
+ if(!R.try_build(usr, src, multiplier))
return
-
- var/atom/O
- if(R.max_res_amount > 1) //Is it a stack?
- O = new R.result_type(get_turf(src), R.res_amount * multiplier)
- else
- O = new R.result_type(get_turf(src))
- O.setDir(usr.dir)
- use(R.req_amount * multiplier)
- updateUsrDialog()
-
- R.post_build(src, O)
+ var/obj/O
+ O = R.do_build(usr, src, multiplier, O)
+ if(!O)
+ return
+ R.post_build(usr, src, O)
if(amount < 1) // Just in case a stack's amount ends up fractional somehow
var/oldsrc = src
src = null //dont kill proc after qdel()
usr.unEquip(oldsrc, 1)
qdel(oldsrc)
- if(isitem(O))
- usr.put_in_hands(O)
-
- O.add_fingerprint(usr)
- //BubbleWrap - so newly formed boxes are empty
- if(isstorage(O))
- for(var/obj/item/I in O)
- qdel(I)
- //BubbleWrap END
if(src && usr.machine == src) //do not reopen closed window
spawn(0)
diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm
index 67e80bd9156..13acf7b06e4 100644
--- a/code/game/objects/items/stacks/stack_recipe.dm
+++ b/code/game/objects/items/stacks/stack_recipe.dm
@@ -28,34 +28,104 @@
src.window_checks = window_checks
src.cult_structure = cult_structure
-/datum/stack_recipe/proc/post_build(obj/item/stack/S, obj/result)
- return
+/// Returns TRUE if the recipe can be built, otherwise returns FALSE. This proc is only meant as a series of tests to check if construction is possible; the actual creation of the resulting atom should be handled in do_build()
+/datum/stack_recipe/proc/try_build(mob/user, obj/item/stack/S, multiplier)
+ if(S.get_amount() < req_amount * multiplier)
+ if(req_amount * multiplier > 1)
+ to_chat(user, "You haven't got enough [S] to build [res_amount * multiplier] [title]\s!")
+ else
+ to_chat(user, "You haven't got enough [S] to build [title]!")
+ return FALSE
+
+ if(window_checks && !valid_window_location(get_turf(S), user.dir))
+ to_chat(user, "[title] won't fit here!")
+ return FALSE
+
+ if(one_per_turf && (locate(result_type) in get_turf(S)))
+ to_chat(user, "There is another [title] here!")
+ return FALSE
+
+ if(on_floor && !issimulatedturf(get_turf(S)))
+ to_chat(user, "[title] must be constructed on the floor!")
+ return FALSE
+ if(on_floor_or_lattice && !(issimulatedturf(get_turf(S)) || locate(/obj/structure/lattice) in get_turf(S)))
+ to_chat(user, "[title] must be constructed on the floor or lattice!")
+ return FALSE
+
+ if(cult_structure)
+ if(user.holy_check())
+ return FALSE
+ if(!is_level_reachable(user.z))
+ to_chat(user, "The energies of this place interfere with the metal shaping!")
+ return FALSE
+ if(locate(/obj/structure/cult) in get_turf(S))
+ to_chat(user, "There is a structure here!")
+ return FALSE
+
+ return TRUE
+
+/// Creates the atom defined by the recipe. Should always return the object it creates or FALSE. This proc assumes that the construction is already possible; for checking whether a recipe *can* be built before construction, use try_build()
+/datum/stack_recipe/proc/do_build(mob/user, obj/item/stack/S, multiplier, atom/O)
+ if(time)
+ to_chat(user, "Building [title]...")
+ if(!do_after(user, time, target = S.loc))
+ return FALSE
+
+ if(cult_structure && locate(/obj/structure/cult) in get_turf(S)) //Check again after do_after to prevent queuing construction exploit.
+ to_chat(user, "There is a structure here!")
+ return FALSE
+
+ if(S.get_amount() < req_amount * multiplier) // Check they still have enough.
+ return FALSE
+
+ if(max_res_amount > 1) //Is it a stack?
+ O = new result_type(get_turf(S), res_amount * multiplier)
+ else
+ O = new result_type(get_turf(S))
+ O.setDir(user.dir)
+ S.use(req_amount * multiplier)
+ S.updateUsrDialog()
+ return O
+
+/// What should be done after the object is built? obj/item/stack/O might not actually be a stack, but this proc needs access to merge() to work, which is on obj/item/stack, so declare it as obj/item/stack anyways.
+/datum/stack_recipe/proc/post_build(mob/user, obj/item/stack/S, obj/item/stack/O)
+ O.add_fingerprint(user)
+
+ if(isitem(O))
+ if(isstack(O) && istype(O, user.get_inactive_hand()))
+ O.merge(user.get_inactive_hand())
+ user.put_in_hands(O)
+
+ //BubbleWrap - so newly formed boxes are empty
+ if(isstorage(O))
+ for(var/obj/item/I in O)
+ qdel(I)
+ //BubbleWrap END
/* Special Recipes */
/datum/stack_recipe/cable_restraints
-/datum/stack_recipe/cable_restraints/post_build(obj/item/stack/S, obj/result)
+/datum/stack_recipe/cable_restraints/post_build(mob/user, obj/item/stack/S, obj/result)
if(istype(result, /obj/item/restraints/handcuffs/cable))
result.color = S.color
..()
-
/datum/stack_recipe/dangerous
-/datum/stack_recipe/dangerous/post_build(obj/item/stack/S, obj/result)
- var/turf/targ = get_turf(usr)
- message_admins("[title] made by [key_name_admin(usr)](?) in [get_area(usr)] [ADMIN_COORDJMP(targ)]!",0,1)
- log_game("[title] made by [key_name_admin(usr)] at [get_area(usr)] [targ.x], [targ.y], [targ.z].")
+/datum/stack_recipe/dangerous/post_build(mob/user, obj/item/stack/S, obj/result)
+ var/turf/targ = get_turf(user)
+ message_admins("[title] made by [key_name_admin(user)](?) in [get_area(user)] [ADMIN_COORDJMP(targ)]!",0,1)
+ log_game("[title] made by [key_name_admin(user)] at [get_area(user)] [targ.x], [targ.y], [targ.z].")
..()
/datum/stack_recipe/rods
-/datum/stack_recipe/rods/post_build(obj/item/stack/S, obj/result)
+/datum/stack_recipe/rods/post_build(mob/user, obj/item/stack/S, obj/result)
if(istype(result, /obj/item/stack/rods))
var/obj/item/stack/rods/R = result
R.update_icon()
..()
/datum/stack_recipe/window
-/datum/stack_recipe/window/post_build(obj/item/stack/S, obj/result)
+/datum/stack_recipe/window/post_build(mob/user, obj/item/stack/S, obj/result)
if(istype(result, /obj/structure/windoor_assembly))
var/obj/structure/windoor_assembly/W = result
W.ini_dir = W.dir
@@ -64,6 +134,7 @@
W.ini_dir = W.dir
W.anchored = FALSE
W.state = WINDOW_OUT_OF_FRAME
+ ..()
/*
* Recipe list datum