Files
BatrachophrenoandGitHub 5277251959 Tool behaviors port (#21663)
For a robust crafting system, I need a new materials framework.
For a new materials framework, I need to clean up reagents.
To clean up reagents, I need to pare down foods from reagent holders.
To pare down foods from reagent holders, I need to port edibility
components.
To port edibility components, I need to port processing components.
To port processing components, I need to port tool behaviors.

This is all back-end code, no new features or functionality from this.
2026-01-27 08:44:49 +00:00

165 lines
7.3 KiB
Plaintext

/obj/structure/crate_shelf
name = "crate shelf"
desc = "It's a shelf! For storing crates!"
icon = 'icons/obj/structure/crate_shelf.dmi'
icon_state = "shelf_base"
var/shelf_stack = "shelf_stack"
density = TRUE
anchored = TRUE
layer = BELOW_OBJ_LAYER
var/capacity = 3 // Default capacity of the shelf
var/use_delay = 1 SECONDS // Default interaction delay of the shelf
var/list/shelf_contents
var/vertical_offset = 10 // Vertical pixel offset of shelving-related things. Set to 10 by default due to this leaving more of the crate on-screen to be clicked.
var/manipulating = FALSE
var/obj/item/stack/dismantle_mat = /obj/item/stack/rods
build_amt = 10
// For testing only.
/obj/structure/crate_shelf/tall
capacity = 12
/obj/structure/crate_shelf/mechanics_hints()
. = list()
. += ..()
. += "Drag a crate on to the shelf, to put it on it."
. += "Drag a crate from the shelf to the ground to remove it."
/obj/structure/crate_shelf/Initialize(mapload)
. = ..()
LAZYSETLEN(shelf_contents, capacity)
update_icon()
return mapload ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_NORMAL
/obj/structure/crate_shelf/LateInitialize()
. = ..()
var/next_free
for(var/obj/I in loc)
if (!istype(I, /obj/structure/closet/crate))
continue
next_free = LAZYFIND(shelf_contents, null)
if(!next_free)
continue
put_in(I, next_free)
/obj/structure/crate_shelf/update_icon()
ClearOverlays()
var/stack_layer // This is used to generate the sprite layering of the shelf pieces.
var/stack_offset // This is used to generate the vertical offset of the shelf pieces.
for(var/i in 1 to (capacity - 1))
stack_layer = BELOW_OBJ_LAYER + (0.02 * i) - 0.01 // Make each shelf piece render above the last, but below the crate that should be on it.
stack_offset = vertical_offset * i // Make each shelf piece physically above the last.
var/image/I = image(icon, icon_state = shelf_stack, layer = stack_layer, pixel_y = stack_offset)
AddOverlays(I)
/obj/structure/crate_shelf/Destroy()
LAZYCLEARLIST(shelf_contents)
return ..()
/obj/structure/crate_shelf/attackby(obj/item/attacking_item, mob/user, params)
. = ..()
if(attacking_item.tool_behaviour == TOOL_WRENCH)
dismantle(attacking_item, user)
/obj/structure/crate_shelf/dismantle(obj/item/W, mob/user)
// if(!LAZYLEN(shelf_contents))
var/empty = TRUE
for(var/c in shelf_contents)
if(c != null)
empty = FALSE
if(!empty)
to_chat(user, SPAN_NOTICE("Remove any crates from \the [src] before dismantling it."))
return
if(manipulating)
return
manipulating = TRUE
user.visible_message("<b>[user]</b> begins dismantling \the [src].",
SPAN_NOTICE("You begin dismantling \the [src]."))
if(!W.use_tool(src, user, 2 SECONDS, volume = 50))
manipulating = FALSE
return
user.visible_message("\The [user] dismantles \the [src].",
SPAN_NOTICE("You dismantle \the [src]."))
new dismantle_mat(src.loc, 10)
qdel(src)
/obj/structure/crate_shelf/proc/relay_container_resist_act(mob/living/user, obj/structure/closet/crate)
to_chat(user, SPAN_NOTICE("You begin attempting to knock [crate] out of [src]."))
visible_message(SPAN_DANGER("\The [crate] begins to shake violently!"), SPAN_DANGER("You hear the sound of metal thrashing around nearby."), intent_message = THUNK_SOUND)
crate.shake_animation()
if(do_after(user, 20 SECONDS, target = crate))
if(!user || user.stat != CONSCIOUS || user.loc != crate || crate.loc != src)
return // If the user is in a strange condition, return early.
crate.shake_animation()
visible_message(SPAN_WARNING("\The [crate] falls off the [src]!"), SPAN_NOTICE("You hear a thud."), intent_message = THUNK_SOUND)
crate.forceMove(loc) // Drop the crate onto the shelf,
step_rand(crate, 1) // Then try to push it somewhere.
crate.layer = initial(crate.layer) // Reset the crate back to having the default layer, otherwise we might get strange interactions.
crate.pixel_y = initial(crate.pixel_y) // Reset the crate back to having no offset, otherwise it will be floating.
shelf_contents[shelf_contents.Find(crate)] = null // Remove the reference to the crate from the list.
handle_visuals()
/obj/structure/crate_shelf/proc/handle_visuals()
vis_contents = contents // It really do be that shrimple.
return
/obj/structure/crate_shelf/proc/load(obj/structure/closet/crate/crate, mob/user)
// Check if the shelf has an empty spot, notify the player if not.
var/next_free = LAZYFIND(shelf_contents, null)
if(!next_free)
to_chat(user, SPAN_NOTICE("The shelf is full."))
balloon_alert(user, "shelf full!")
return FALSE
visible_message("\The [user] starts to put \the [crate] on \the [src].")
if(do_after(user, use_delay, target = crate))
if(shelf_contents[next_free] != null)
// Something has been added to the shelf while we were waiting, abort!
visible_message("\The [user] stops putting \the [crate] on \the [src].")
to_chat(user, SPAN_NOTICE("Something else was added to the shelf first."))
return FALSE
if(crate.opened) // If the crate is open, try to close it.
if(!crate.close())
visible_message("\The [user] stops putting \the [crate] on \the [src].")
to_chat(user, SPAN_NOTICE("The crate couldn't be closed."))
return FALSE // If we fail to close it, don't load it into the shelf.
put_in(crate, next_free)
visible_message("\The [user] puts \the [crate] on \the [src].")
return TRUE
visible_message("\The [user] stops putting \the [crate] on \the [src].")
return FALSE // If the do_after() is interrupted, return FALSE!
/obj/structure/crate_shelf/proc/put_in(obj/structure/closet/crate/crate, var/next_free)
LAZYSET(shelf_contents, next_free, crate)
crate.forceMove(src) // Insert the crate into the shelf.
crate.pixel_y = vertical_offset * (next_free - 1) // Adjust the vertical offset of the crate to look like it's on the shelf.
crate.layer = BELOW_OBJ_LAYER + 0.02 * (next_free - 1) // Adjust the layer of the crate to look like it's in the shelf.
handle_visuals()
/obj/structure/crate_shelf/proc/unload(obj/structure/closet/crate/crate, mob/user, turf/unload_turf)
if(!unload_turf)
unload_turf = get_turf(user) // If a turf somehow isn't passed into the proc, put it at the user's feet.
if(!unload_turf.Enter(crate)) // If moving the crate from the shelf to the desired turf would bump, don't do it! Thanks Kapu1178 for the help here. - Generic DM
to_chat(user, SPAN_NOTICE("There is no room for the crate."))
return FALSE
visible_message("\The [user] starts unloading \the [crate] from \the [src].")
if(do_after(user, use_delay, target = crate))
if(!LAZYFIND(shelf_contents, crate))
visible_message("\The [user] stops unloading \the [crate] from \the [src].")
to_chat(user, SPAN_NOTICE("The crate can't be moved."))
return FALSE // If something has happened to the crate while we were waiting, abort!
crate.layer = initial(crate.layer) // Reset the crate back to having the default layer, otherwise we might get strange interactions.
crate.pixel_y = initial(crate.pixel_y) // Reset the crate back to having no offset, otherwise it will be floating.
crate.forceMove(unload_turf)
shelf_contents[shelf_contents.Find(crate)] = null // We do this instead of removing it from the list to preserve the order of the shelf.
handle_visuals()
visible_message("\The [user] unloads \the [crate] from \the [src].")
return TRUE
visible_message("\The [user] stops unloading \the [crate] from \the [src].")
return FALSE // If the do_after() is interrupted, return FALSE!