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