mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
Refactor girders and wall construction (#94364)
## About The Pull Request This PR refactors wall construction on girders, wooden barricades and metal foam to use a centralized element, which listens to item interaction signals and attempts to make any available wall recipe. This change is an atomized prerequisite to my blueprinting system, since that system requires a sane way to dynamically change the speed at which walls are built. This PR will later be expanded to refactor girder construction steps in general. I also added `proc/valid_typesof(base_type)` as a side effect of my previous attempts at refactoring this stuff. There's now what amounts to a code comment easter egg in the same file, because DM is wacko and you're going to get cursed now too. :) ## Why It's Good For The Game The old system had ~20 bespoke yet highly similar wall construction steps. Some of the wall recipes were also concatenated from a string on the used stack type. To put it bluntly, the code was fucking horrible. Same thing goes for the rest of the girder construction steps, they were all bespoke. ## Changelog 🆑 refactor: Refactored girders and wall construction. Report any bugs. tweak: Some niche wall types might have their wall delay changed by like 2 seconds. This doesn't affect normal walls, reinforced walls, falsewalls or any other important wall types. /🆑
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/// An element for girders, wall barricades, etc. that makes them use wall construction recipes.
|
||||
/// Only really meant for recipes where you click on the girder with a stack of materials to make a wall.
|
||||
/datum/element/uses_girder_wall_recipes
|
||||
|
||||
/datum/element/uses_girder_wall_recipes/Attach(datum/target)
|
||||
. = ..()
|
||||
if (!isstructure(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
RegisterSignals(target, list(COMSIG_ATOM_ITEM_INTERACTION, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY), PROC_REF(on_item_interaction))
|
||||
|
||||
/datum/element/uses_girder_wall_recipes/Detach(datum/target, ...)
|
||||
UnregisterSignal(target, list(COMSIG_ATOM_ITEM_INTERACTION, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY))
|
||||
return ..()
|
||||
|
||||
/datum/element/uses_girder_wall_recipes/proc/on_item_interaction(obj/structure/structure, mob/living/user, obj/item/stack/stack, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
if (!isstack(stack))
|
||||
return NONE
|
||||
if (!stack.usable_for_construction)
|
||||
structure.balloon_alert(user, "unusable material!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
var/datum/girder_wall_recipe/main_recipe = get_main_recipe(structure, stack)
|
||||
|
||||
if (main_recipe)
|
||||
INVOKE_ASYNC(src, PROC_REF(attempt_recipe), structure, user, stack, main_recipe, is_material_recipe = FALSE)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if (stack.has_unique_girder)
|
||||
structure.balloon_alert(user, "needs a different girder!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
// Plasteel is used for reinforcing girders.
|
||||
if (istype(structure, /obj/structure/girder) && istype(stack, /obj/item/stack/sheet/plasteel))
|
||||
return NONE
|
||||
|
||||
var/datum/girder_wall_recipe/material_recipe = get_material_recipe(structure, stack)
|
||||
|
||||
if (material_recipe)
|
||||
INVOKE_ASYNC(src, PROC_REF(attempt_recipe), structure, user, stack, material_recipe, is_material_recipe = TRUE)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
/// Returns the main wall recipe of the stack for the structure, if any.
|
||||
/datum/element/uses_girder_wall_recipes/proc/get_main_recipe(obj/structure/structure, obj/item/stack/stack)
|
||||
for (var/datum/girder_wall_recipe/recipe as anything in GLOB.main_girder_wall_recipes)
|
||||
if (!istype(stack, recipe.stack_type))
|
||||
continue
|
||||
if (!istype(structure, recipe.girder_type))
|
||||
continue
|
||||
if (!check_girder_state(structure, recipe))
|
||||
continue
|
||||
return recipe
|
||||
|
||||
/// Returns the material wall recipe of the stack for the structure, if any.
|
||||
/datum/element/uses_girder_wall_recipes/proc/get_material_recipe(obj/structure/structure, obj/item/stack/stack)
|
||||
for (var/datum/girder_wall_recipe/recipe as anything in GLOB.material_girder_wall_recipes)
|
||||
if (!istype(structure, recipe.girder_type))
|
||||
continue
|
||||
if (!check_girder_state(structure, recipe))
|
||||
continue
|
||||
return recipe
|
||||
|
||||
/// Has the user attempt the wall recipe asynchronously.
|
||||
/// Assumes that the structure and stack are of valid types for the recipe.
|
||||
/datum/element/uses_girder_wall_recipes/proc/attempt_recipe_async(obj/structure/structure, mob/living/user, obj/item/stack/stack, datum/girder_wall_recipe/recipe, is_material_recipe)
|
||||
INVOKE_ASYNC(src, PROC_REF(attempt_recipe), structure, user, stack, recipe, is_material_recipe)
|
||||
|
||||
/// Has the user attempt the wall recipe.
|
||||
/// Assumes that the structure and stack are of valid types for the recipe.
|
||||
/datum/element/uses_girder_wall_recipes/proc/attempt_recipe(obj/structure/structure, mob/living/user, obj/item/stack/stack, datum/girder_wall_recipe/recipe, is_material_recipe)
|
||||
if (!check_recipe(structure, user, recipe))
|
||||
return
|
||||
if (!stack.tool_start_check(user, recipe.stack_amount))
|
||||
return
|
||||
|
||||
user.visible_message(
|
||||
message = span_notice("\The [user] start[user.p_s()] building a wall on \the [structure]."),
|
||||
self_message = span_notice("You start building a wall on \the [structure]."),
|
||||
blind_message = span_hear("You hear a series of clangs."),
|
||||
)
|
||||
|
||||
structure.add_fingerprint(user)
|
||||
stack.add_fingerprint(user)
|
||||
|
||||
if (!stack.use_tool(structure, user, recipe.make_delay, recipe.stack_amount, extra_checks = CALLBACK(src, PROC_REF(check_recipe), structure, user, recipe)))
|
||||
return
|
||||
|
||||
var/atom/wall
|
||||
if (ispath(recipe.wall_type, /turf))
|
||||
var/turf/structure_turf = get_turf(structure)
|
||||
wall = structure_turf.place_on_top(recipe.wall_type)
|
||||
else if (ispath(recipe.wall_type, /obj))
|
||||
wall = new recipe.wall_type(structure.drop_location())
|
||||
else
|
||||
CRASH("Attempted a girder wall recipe with an invalid wall type ([recipe.wall_type])")
|
||||
|
||||
user.visible_message(
|
||||
message = span_notice("\The [user] finish[user.p_es()] building \a [wall] on \the [structure]."),
|
||||
self_message = span_notice("You finish building \a [wall] on \the [structure]."),
|
||||
)
|
||||
|
||||
structure.transfer_fingerprints_to(wall)
|
||||
qdel(structure)
|
||||
|
||||
if (is_material_recipe)
|
||||
wall.set_custom_materials(stack.mats_per_unit, recipe.stack_amount)
|
||||
|
||||
/// Checks if the user can do the wall recipe.
|
||||
/datum/element/uses_girder_wall_recipes/proc/check_recipe(obj/structure/structure, mob/living/user, datum/girder_wall_recipe/recipe)
|
||||
if(iswallturf(structure.loc) || (locate(/obj/structure/falsewall) in structure.loc.contents))
|
||||
structure.balloon_alert(user, "wall already present!")
|
||||
return FALSE
|
||||
if (!ispath(recipe.wall_type, /obj/structure/tram))
|
||||
if (!isfloorturf(structure.loc))
|
||||
structure.balloon_alert(user, "need floor!")
|
||||
return FALSE
|
||||
else if (!(locate(/obj/structure/transport/linear/tram) in structure.loc.contents))
|
||||
structure.balloon_alert(user, "need tram floor!")
|
||||
return FALSE
|
||||
if (!check_girder_state(structure, recipe))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Checks if the girder state of the structure matches the required girder state of the wall recipe.
|
||||
/datum/element/uses_girder_wall_recipes/proc/check_girder_state(obj/structure/structure, datum/girder_wall_recipe/recipe)
|
||||
if (istype(structure, /obj/structure/girder))
|
||||
var/obj/structure/girder/girder = structure
|
||||
if (girder.state != recipe.girder_state)
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -0,0 +1,27 @@
|
||||
/// Contains recipe data for constructing a specific type of wall on a girder.
|
||||
/// Only the [/datum/element/uses_girder_wall_recipes] should be using these.
|
||||
/datum/girder_wall_recipe
|
||||
/// The wall type this recipe is for. Can be a turf or an object.
|
||||
var/wall_type
|
||||
/// The type of stack required for this recipe.
|
||||
var/stack_type
|
||||
/// The amount of stack items required for this recipe.
|
||||
var/stack_amount
|
||||
/// The [/obj/structure] type required for this recipe.
|
||||
var/girder_type
|
||||
/// The [/obj/structure/girder/var/state] required for this recipe.
|
||||
/// Ignored if [var/girder] is not of type [/obj/structure/girder].
|
||||
var/girder_state
|
||||
/// The amount of time it takes to make this recipe in deciseconds.
|
||||
var/make_delay
|
||||
/// The starting balloon alert text for this recipe.
|
||||
var/start_alert
|
||||
|
||||
/datum/girder_wall_recipe/New(wall_type, stack_type, stack_amount, girder_type, girder_state, make_delay, start_alert)
|
||||
src.wall_type = wall_type
|
||||
src.stack_type = stack_type
|
||||
src.stack_amount = stack_amount
|
||||
src.girder_type = girder_type
|
||||
src.girder_state = girder_state
|
||||
src.make_delay = make_delay
|
||||
src.start_alert = start_alert
|
||||
Reference in New Issue
Block a user