diff --git a/code/__HELPERS/abstract_types.dm b/code/__HELPERS/abstract_types.dm index ecf8fb35bb4..e2013ad4bbe 100644 --- a/code/__HELPERS/abstract_types.dm +++ b/code/__HELPERS/abstract_types.dm @@ -10,6 +10,13 @@ return abstracts +// The time complexity of these two procs is really bad, sitting at O(n * m). +// And yet, the overhead is ridiculously small for some reason. We never figured out why. +// So doing list subtraction instead of filtering is faster in all cases, at least for now. +// If we ever breach like 3000-5000 abstract types, that will likely change. +// As of right now we're at 272 or so, with subtraction being ~10x faster. +// Curse this language, for you shall live in hell alongside me. + /// Like subtypesof, but automatically excludes abstract typepaths /proc/valid_subtypesof(datum/sometype) return subtypesof(sometype) - get_abstract_types() diff --git a/code/_globalvars/lists/girder_wall_recipes.dm b/code/_globalvars/lists/girder_wall_recipes.dm new file mode 100644 index 00000000000..d4a015c6a4e --- /dev/null +++ b/code/_globalvars/lists/girder_wall_recipes.dm @@ -0,0 +1,121 @@ +GLOBAL_LIST_INIT(main_girder_wall_recipes, init_main_girder_wall_recipes()) +GLOBAL_LIST_INIT(material_girder_wall_recipes, init_material_girder_wall_recipes()) + +/// Initializes the main, false and tram wall types using three lists of wall types. +/proc/init_main_girder_wall_recipes() + return create_girder_wall_recipes( + wall_types = list( + /turf/closed/wall, + /turf/closed/wall/metal_foam_base, + /turf/closed/wall/r_wall, + /turf/closed/wall/r_wall/plastitanium, + /turf/closed/wall/mineral/gold, + /turf/closed/wall/mineral/silver, + /turf/closed/wall/mineral/diamond, + /turf/closed/wall/mineral/bananium, + /turf/closed/wall/mineral/sandstone, + /turf/closed/wall/mineral/uranium, + /turf/closed/wall/mineral/plasma, + /turf/closed/wall/mineral/wood, + /turf/closed/wall/mineral/wood/nonmetal, + /turf/closed/wall/mineral/bamboo, + /turf/closed/wall/mineral/iron, + /turf/closed/wall/mineral/snow, + /turf/closed/wall/mineral/abductor, + /turf/closed/wall/mineral/titanium, + /turf/closed/wall/mineral/plastitanium, + /turf/closed/wall/mineral/cult, + /turf/closed/wall/mineral/bronze, + /turf/closed/wall/material, + ), + falsewall_types = list( + /obj/structure/falsewall, + /obj/structure/falsewall/reinforced, + /obj/structure/falsewall/gold, + /obj/structure/falsewall/silver, + /obj/structure/falsewall/diamond, + /obj/structure/falsewall/bananium, + /obj/structure/falsewall/sandstone, + /obj/structure/falsewall/uranium, + /obj/structure/falsewall/plasma, + /obj/structure/falsewall/wood, + /obj/structure/falsewall/bamboo, + /obj/structure/falsewall/iron, + /obj/structure/falsewall/abductor, + /obj/structure/falsewall/titanium, + /obj/structure/falsewall/plastitanium, + /obj/structure/falsewall/material, + ), + tram_types = list( + /obj/structure/tram, + /obj/structure/tram/alt/gold, + /obj/structure/tram/alt/silver, + /obj/structure/tram/alt/diamond, + /obj/structure/tram/alt/bananium, + /obj/structure/tram/alt/sandstone, + /obj/structure/tram/alt/uranium, + /obj/structure/tram/alt/plasma, + /obj/structure/tram/alt/wood, + /obj/structure/tram/alt/bamboo, + /obj/structure/tram/alt/iron, + /obj/structure/tram/alt/abductor, + /obj/structure/tram/alt/titanium, + /obj/structure/tram/alt/plastitanium, + ) + ) + +/// Initializes the normal and false girder material wall recipes using two lists of material wall types. +/proc/init_material_girder_wall_recipes() + return create_girder_wall_recipes( + wall_types = list(/turf/closed/wall/material), + falsewall_types = list(/obj/structure/falsewall/material) + ) + +/// Returns a list of newly created [/datum/girder_wall_recipe] instances from the given wall type lists. +/proc/create_girder_wall_recipes(list/wall_types, list/falsewall_types, list/tram_types) + var/list/recipes = list() + + for (var/turf/closed/wall/wall_type as anything in wall_types) + add_girder_wall_recipe( + recipes = recipes, + wall_type = wall_type, + stack_type = wall_type::sheet_type, + stack_amount = wall_type::sheet_amount, + girder_type = wall_type::girder_type, + girder_state = wall_type::girder_state, + make_delay = wall_type::make_delay, + start_alert = "adding plating..." + ) + + for (var/obj/structure/falsewall/falsewall_type as anything in falsewall_types) + add_girder_wall_recipe( + recipes = recipes, + wall_type = falsewall_type, + stack_type = falsewall_type::mineral, + stack_amount = falsewall_type::mineral_amount, + girder_type = falsewall_type::girder_type, + girder_state = GIRDER_DISPLACED, + make_delay = 2 SECONDS, + start_alert = "concealing entrance..." + ) + + for (var/obj/structure/tram/tram_type as anything in tram_types) + add_girder_wall_recipe( + recipes = recipes, + wall_type = tram_type, + stack_type = tram_type::mineral, + stack_amount = tram_type::mineral_amount, + girder_type = tram_type::girder_type, + girder_state = GIRDER_TRAM, + make_delay = 4 SECONDS, + start_alert = "adding plating..." + ) + + return recipes + +/// Adds a new [/datum/girder_wall_recipe] instance to the given recipe list from the given recipe arguments. +/proc/add_girder_wall_recipe(list/recipes, wall_type, stack_type, stack_amount, girder_type, girder_state, make_delay, start_alert) + if (!ispath(stack_type, /obj/item/stack)) + CRASH("Attempted to create a girder wall recipe for wall type ([wall_type]) with an invalid stack type ([stack_type])") + + recipes += new /datum/girder_wall_recipe(wall_type, stack_type, stack_amount, girder_type, girder_state, make_delay, start_alert) diff --git a/code/datums/elements/uses_girder_wall_recipes.dm b/code/datums/elements/uses_girder_wall_recipes.dm new file mode 100644 index 00000000000..b313f78200e --- /dev/null +++ b/code/datums/elements/uses_girder_wall_recipes.dm @@ -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 diff --git a/code/datums/girder_wall_recipe.dm b/code/datums/girder_wall_recipe.dm new file mode 100644 index 00000000000..4e0845ffc35 --- /dev/null +++ b/code/datums/girder_wall_recipe.dm @@ -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 diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 2fea89c4605..1601626e044 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -81,32 +81,7 @@ AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) register_context() -/obj/structure/barricade/wooden/item_interaction(mob/living/user, obj/item/stack/sheet/mineral/wood/our_wood, list/modifiers) - if(user.combat_mode) - return ITEM_INTERACT_SKIP_TO_ATTACK - - if(!istype(our_wood, /obj/item/stack/sheet/mineral/wood)) - return NONE - - if(our_wood.amount < 5) - balloon_alert(user, "not enough wood!") - to_chat(user, span_warning("You need at least five wooden planks to make a barricade!")) - return ITEM_INTERACT_BLOCKING - - - to_chat(user, span_notice("You start adding [our_wood] to [src]...")) - playsound(src, 'sound/items/hammering_wood.ogg', 50, vary = TRUE) - if(!do_after(user, 5 SECONDS, target=src)) - balloon_alert(user, "interrupted!") - return ITEM_INTERACT_BLOCKING - - if(!our_wood.use(drop_amount)) - return ITEM_INTERACT_BLOCKING - - var/turf/cur_turf = get_turf(src) - cur_turf.place_on_top(/turf/closed/wall/mineral/wood/nonmetal) - qdel(src) - return ITEM_INTERACT_SUCCESS + AddElement(/datum/element/uses_girder_wall_recipes) /obj/structure/barricade/wooden/crowbar_act(mob/living/user, obj/item/tool) balloon_alert(user, "deconstructing barricade...") diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index f3394e21e19..0f96caf617e 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -324,6 +324,7 @@ /obj/structure/foamedmetal/Initialize(mapload) . = ..() air_update_turf(TRUE, TRUE) + AddElement(/datum/element/uses_girder_wall_recipes) /obj/structure/foamedmetal/Destroy() air_update_turf(TRUE, FALSE) @@ -349,37 +350,6 @@ to_chat(user, span_warning("You hit [src] but bounce off it!")) playsound(src.loc, 'sound/items/weapons/tap.ogg', 100, TRUE) -/obj/structure/foamedmetal/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) - ///A speed modifier for how fast the wall is build - var/platingmodifier = 1 - if(HAS_TRAIT(user, TRAIT_QUICK_BUILD)) - platingmodifier = 0.7 - if(next_beep <= world.time) - next_beep = world.time + 1 SECONDS - playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) - add_fingerprint(user) - - if(!istype(W, /obj/item/stack/sheet)) - return ..() - - var/obj/item/stack/sheet/sheet_for_plating = W - if(istype(sheet_for_plating, /obj/item/stack/sheet/iron)) - if(sheet_for_plating.get_amount() < 2) - to_chat(user, span_warning("You need two sheets of iron to finish a wall on [src]!")) - return - to_chat(user, span_notice("You start adding plating to the foam structure...")) - if (do_after(user, 40 * platingmodifier, target = src)) - if(!sheet_for_plating.use(2)) - return - to_chat(user, span_notice("You add the plating.")) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall/metal_foam_base) - transfer_fingerprints_to(T) - qdel(src) - return - - add_hiddenprint(user) - /// A metal foam variant which produces slightly sturdier walls. /obj/effect/particle_effect/fluid/foam/metal/iron name = "iron foam" diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index f51bfafa2e5..d8fde1fa91e 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -12,20 +12,27 @@ smoothing_groups = SMOOTH_GROUP_GIRDER canSmoothWith = SMOOTH_GROUP_GIRDER + SMOOTH_GROUP_WALLS custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2) + + /// The stack type required to construct and dropped upon deconstructing the girder. + var/stack_type = /obj/item/stack/sheet/iron + /// The stack amount required to construct and dropped upon deconstructing the girder. + var/stack_amount = 2 + /// Always drops the stack in full, even when demolished rather than disassembled. + var/always_drop_stack = FALSE + + /// The current state of the girder. Used for construction. var/state = GIRDER_NORMAL - var/girderpasschance = 20 // percentage chance that a projectile passes through the girder. - var/can_displace = TRUE //If the girder can be moved around by wrenching it - var/next_beep = 0 //Prevents spamming of the construction sound - /// The material cost to construct something on the girder - var/static/list/construction_cost = list( - /obj/item/stack/sheet/iron = 2, - /obj/item/stack/rods = 5, - /obj/item/stack/sheet/plasteel = 2, - /obj/item/stack/sheet/bronze = 2, - /obj/item/stack/sheet/runed_metal = 1, - /obj/item/stack/sheet/titaniumglass = 2, - exotic_material = 2 // this needs to be refactored properly - ) + /// Whether the girder can be unanchored by wrenching it. + var/can_displace = TRUE + /// Whether the girder can be welded apart. (for cult and bronze girders) + var/can_weld_apart = FALSE + + /// The percentage chance (0-100) that a projectile passes through the girder. + var/projectile_pass_chance = 20 + +/obj/structure/girder/Initialize(mapload) + . = ..() + AddElement(/datum/element/uses_girder_wall_recipes) /obj/structure/girder/examine(mob/user) . = ..() @@ -39,378 +46,106 @@ . += span_notice("The bolts are wrenched in place.") if(GIRDER_DISPLACED) . += span_notice("The bolts are loosened, but the screws are holding [src] together.") - if(GIRDER_DISASSEMBLED) - . += span_notice("[src] is disassembled! You probably shouldn't be able to see this examine message.") if(GIRDER_TRAM) . += span_notice("[src] is designed for tram usage. Deconstructed with a screwdriver!") + if (can_weld_apart) + . += span_notice("The frame looks weak enough to be welded apart.") + else + . += span_notice("The frame could be sliced apart with a plasmacutter.") -/obj/structure/girder/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) - - add_fingerprint(user) - - if(istype(W, /obj/item/gun/energy/plasmacutter)) - balloon_alert(user, "slicing apart...") - if(W.use_tool(src, user, 40, volume=100)) - if(state == GIRDER_TRAM) - var/obj/item/stack/sheet/mineral/titanium/M = new (user.loc, 2) - if(!QDELETED(M)) - M.add_fingerprint(user) - else - var/obj/item/stack/sheet/iron/M = new (loc, 2) - if(!QDELETED(M)) - M.add_fingerprint(user) - qdel(src) +/obj/structure/girder/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if (user.combat_mode) return + if (istype(tool, /obj/item/stack/sheet/plasteel)) + if (try_construction_step(user, tool, 5 SECONDS, req_state = GIRDER_NORMAL, start_alert = "reinforcing frame...")) + replace_girder(/obj/structure/girder/reinforced) + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING - if(isstack(W)) - var/obj/item/stack/stack = W - if(!stack.usable_for_construction) - balloon_alert(user, "can't make walls with it!") - return - - if(iswallturf(loc) || (locate(/obj/structure/falsewall) in src.loc.contents)) - balloon_alert(user, "wall already present!") - return - if(!isfloorturf(src.loc) && state != GIRDER_TRAM) - balloon_alert(user, "need floor!") - return - if(state == GIRDER_TRAM) - if(!locate(/obj/structure/transport/linear/tram) in src.loc.contents) - balloon_alert(user, "need tram floors!") - return - - make_wall(stack, user) - return - - if(istype(W, /obj/item/pipe)) - var/obj/item/pipe/P = W - if (P.pipe_type in list(0, 1, 5)) //simple pipes, simple bends, and simple manifolds. - if(!user.transfer_item_to_turf(P, drop_location())) - return - balloon_alert(user, "inserted pipe") - return - - return ..() - -/obj/structure/girder/proc/make_wall(obj/item/stack/stack, mob/user) - var/speed_modifier = 1 - if(HAS_TRAIT(user, TRAIT_QUICK_BUILD)) - speed_modifier = 0.7 - if(next_beep <= world.time) - next_beep = world.time + 10 - playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) - - if(istype(stack, /obj/item/stack/rods)) - var/obj/item/stack/rods/rod = stack - var/amount = construction_cost[rod.type] - if(state == GIRDER_DISPLACED) - if(rod.get_amount() < amount) - balloon_alert(user, "need [amount] rods!") - return - balloon_alert(user, "concealing entrance...") - if(do_after(user, 2 SECONDS, target = src)) - if(rod.get_amount() < amount) - return - rod.use(amount) - var/obj/structure/falsewall/iron/FW = new (loc) - transfer_fingerprints_to(FW) - qdel(src) - return - - if(state == GIRDER_REINF) - balloon_alert(user, "need plasteel sheet!") - return - - if(rod.get_amount() < amount) - balloon_alert(user, "need [amount] rods!") - return - balloon_alert(user, "adding rods...") - if(do_after(user, 4 SECONDS, target = src)) - if(rod.get_amount() < amount) - return - rod.use(amount) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall/mineral/iron) - transfer_fingerprints_to(T) - qdel(src) - return - - else if(istype(stack, /obj/item/stack/sheet/iron)) - var/amount = construction_cost[/obj/item/stack/sheet/iron] - if(state == GIRDER_DISPLACED) - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "concealing entrance...") - if(do_after(user, 20 * speed_modifier, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/obj/structure/falsewall/F = new (loc) - transfer_fingerprints_to(F) - qdel(src) - return - else if(state == GIRDER_REINF) - balloon_alert(user, "need plasteel sheet!") - return - else if(state == GIRDER_TRAM) - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "adding plating...") - if (do_after(user, 4 SECONDS, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/obj/structure/tram/alt/iron/tram_wall = new(loc) - transfer_fingerprints_to(tram_wall) - qdel(src) - return - else - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "adding plating...") - if (do_after(user, 40 * speed_modifier, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall) - transfer_fingerprints_to(T) - qdel(src) - return - - else if(istype(stack, /obj/item/stack/sheet/titaniumglass) && state == GIRDER_TRAM) - var/amount = construction_cost[/obj/item/stack/sheet/titaniumglass] - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "adding panel...") - if (do_after(user, 2 SECONDS, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/obj/structure/tram/tram_wall = new(loc) - transfer_fingerprints_to(tram_wall) - qdel(src) - return - - else if(istype(stack, /obj/item/stack/sheet/plasteel)) - var/amount = construction_cost[/obj/item/stack/sheet/plasteel] - if(state == GIRDER_DISPLACED) - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "concealing entrance...") - if(do_after(user, 2 SECONDS, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/obj/structure/falsewall/reinforced/FW = new (loc) - transfer_fingerprints_to(FW) - qdel(src) - return - else if(state == GIRDER_REINF) - amount = 1 // hur dur let's make plasteel have different construction amounts 4norasin - if(stack.get_amount() < amount) - return - balloon_alert(user, "adding plating...") - if(do_after(user, 50 * speed_modifier, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall/r_wall) - transfer_fingerprints_to(T) - qdel(src) - return - else - amount = 1 // hur dur x2 - if(stack.get_amount() < amount) - return - balloon_alert(user, "reinforcing frame...") - if(do_after(user, 60 * speed_modifier, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/obj/structure/girder/reinforced/R = new (loc) - transfer_fingerprints_to(R) - qdel(src) - return - - else if(istype(stack, /obj/item/stack/sheet/mineral/plastitanium)) - if(state == GIRDER_REINF) - if(stack.get_amount() < 1) - return - balloon_alert(user, "adding plating...") - if(do_after(user, 50 * speed_modifier, target = src)) - if(stack.get_amount() < 1) - return - stack.use(1) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall/r_wall/plastitanium) - transfer_fingerprints_to(T) - qdel(src) - return - // No return here because generic material construction handles making normal plastitanium walls - - else if(!stack.has_unique_girder && stack.material_type) - if(istype(src, /obj/structure/girder/reinforced)) - balloon_alert(user, "need plasteel or plastitanium!") - return - - var/material - if(istype(stack, /obj/item/stack/sheet)) - var/obj/item/stack/sheet/sheet = stack - material = sheet.construction_path_type - var/amount = construction_cost["exotic_material"] - if(state == GIRDER_TRAM) - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - var/tram_wall_type = text2path("/obj/structure/tram/alt/[material]") - if(!tram_wall_type) - balloon_alert(user, "need titanium glass or mineral!") - return - balloon_alert(user, "adding plating...") - if (do_after(user, 4 SECONDS, target = src)) - if(stack.get_amount() < amount) - return - var/obj/structure/tram/tram_wall - tram_wall = new tram_wall_type(loc) - stack.use(amount) - transfer_fingerprints_to(tram_wall) - qdel(src) - return - if(state == GIRDER_DISPLACED) - var/falsewall_type = text2path("/obj/structure/falsewall/[material]") - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "concealing entrance...") - if(do_after(user, 2 SECONDS, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/obj/structure/falsewall/falsewall - if(falsewall_type) - falsewall = new falsewall_type (loc) - else - var/obj/structure/falsewall/material/mat_falsewall = new(loc) - var/list/material_list = list() - material_list[GET_MATERIAL_REF(stack.material_type)] = SHEET_MATERIAL_AMOUNT * 2 - if(material_list) - mat_falsewall.set_custom_materials(material_list) - falsewall = mat_falsewall - transfer_fingerprints_to(falsewall) - qdel(src) - return - else - if(stack.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "adding plating...") - if (do_after(user, 4 SECONDS, target = src)) - if(stack.get_amount() < amount) - return - stack.use(amount) - var/turf/T = get_turf(src) - if(stack.walltype) - T.place_on_top(stack.walltype) - else - var/turf/newturf = T.place_on_top(/turf/closed/wall/material) - var/list/material_list = list() - material_list[GET_MATERIAL_REF(stack.material_type)] = SHEET_MATERIAL_AMOUNT * 2 - if(material_list) - newturf.set_custom_materials(material_list) - - transfer_fingerprints_to(T) - qdel(src) - return - -// Screwdriver behavior for girders /obj/structure/girder/screwdriver_act(mob/user, obj/item/tool) - if(..()) - return TRUE + . = ITEM_INTERACT_BLOCKING + switch (state) + if (GIRDER_TRAM) + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_TRAM, start_alert = "disassembling frame...")) + deconstruct(disassembled = TRUE) + return ITEM_INTERACT_SUCCESS + if (GIRDER_DISPLACED) + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_DISPLACED, start_alert = "disassembling frame...")) + deconstruct(disassembled = TRUE) + return ITEM_INTERACT_SUCCESS + if (GIRDER_REINF) + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_REINF, start_alert = "unsecuring support struts...")) + state = GIRDER_REINF_STRUTS + return ITEM_INTERACT_SUCCESS + if (GIRDER_REINF_STRUTS) + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_REINF_STRUTS, start_alert = "securing support struts...")) + state = GIRDER_REINF + return ITEM_INTERACT_SUCCESS - . = FALSE - if(state == GIRDER_TRAM) - balloon_alert(user, "disassembling frame...") - if(tool.use_tool(src, user, 4 SECONDS, volume=100)) - if(state != GIRDER_TRAM) - return - state = GIRDER_DISASSEMBLED - var/obj/item/stack/sheet/mineral/titanium/material = new (user.loc, 2) - if (!QDELETED(material)) - material.add_fingerprint(user) - qdel(src) - return TRUE - - if(state == GIRDER_DISPLACED) - balloon_alert(user, "disassembling frame...") - if(tool.use_tool(src, user, 40, volume=100)) - if(state != GIRDER_DISPLACED) - return - state = GIRDER_DISASSEMBLED - var/obj/item/stack/sheet/iron/M = new (loc, 2) - if (!QDELETED(M)) - M.add_fingerprint(user) - qdel(src) - return TRUE - - else if(state == GIRDER_REINF) - balloon_alert(user, "unsecuring support struts...") - if(tool.use_tool(src, user, 40, volume=100)) - if(state != GIRDER_REINF) - return - state = GIRDER_REINF_STRUTS - return TRUE - - else if(state == GIRDER_REINF_STRUTS) - balloon_alert(user, "securing support struts...") - if(tool.use_tool(src, user, 40, volume=100)) - if(state != GIRDER_REINF_STRUTS) - return - state = GIRDER_REINF - return TRUE - -// Wirecutter behavior for girders /obj/structure/girder/wirecutter_act(mob/user, obj/item/tool) - . = ..() - if(state == GIRDER_REINF_STRUTS) - balloon_alert(user, "removing inner grille...") - if(tool.use_tool(src, user, 40, volume=100)) - new /obj/item/stack/sheet/plasteel(get_turf(src)) - var/obj/structure/girder/G = new (loc) - transfer_fingerprints_to(G) - qdel(src) - return TRUE + . = ITEM_INTERACT_BLOCKING + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_REINF_STRUTS, start_alert = "removing inner grille...")) + new /obj/item/stack/sheet/plasteel(get_turf(src)) + replace_girder(/obj/structure/girder) + return ITEM_INTERACT_SUCCESS /obj/structure/girder/wrench_act(mob/user, obj/item/tool) - . = ..() - if(state == GIRDER_DISPLACED) - if(!isfloorturf(loc)) - balloon_alert(user, "needs floor!") + . = ITEM_INTERACT_BLOCKING + if (!can_displace) + balloon_alert(user, "no bolts!") + return + switch (state) + if (GIRDER_NORMAL) + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_NORMAL, start_alert = "unsecuring frame...")) + replace_girder(/obj/structure/girder/displaced) + return ITEM_INTERACT_SUCCESS + if (GIRDER_DISPLACED) + if (try_construction_step(user, tool, 4 SECONDS, req_state = GIRDER_DISPLACED, start_alert = "securing frame...")) + replace_girder(/obj/structure/girder) + return ITEM_INTERACT_SUCCESS - balloon_alert(user, "securing frame...") - if(tool.use_tool(src, user, 40, volume=100)) - var/obj/structure/girder/G = new (loc) - transfer_fingerprints_to(G) - qdel(src) - return TRUE - else if(state == GIRDER_NORMAL && can_displace) - balloon_alert(user, "unsecuring frame...") - if(tool.use_tool(src, user, 40, volume=100)) - var/obj/structure/girder/displaced/D = new (loc) - transfer_fingerprints_to(D) - qdel(src) - return TRUE +/obj/structure/girder/welder_act(mob/living/user, obj/item/tool) + . = ITEM_INTERACT_BLOCKING + // Plasmacutters can always slice apart girders. + if (!can_weld_apart && !istype(tool, /obj/item/gun/energy/plasmacutter)) + balloon_alert(user, "can't weld apart!") + return + if (try_construction_step(user, tool, 4 SECONDS, start_alert = "slicing apart...")) + deconstruct(disassembled = TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/structure/girder/proc/try_construction_step(mob/living/user, obj/item/tool, delay, req_state, req_floor, start_alert, volume = 100) + if (!check_state(user, req_state, req_floor)) + return FALSE + + balloon_alert(user, start_alert) + + add_fingerprint(user) + tool.add_fingerprint(user) + + return tool.use_tool(src, user, delay, volume = volume, extra_checks = CALLBACK(src, PROC_REF(check_state), user, req_state, req_floor)) + +/obj/structure/girder/proc/check_state(mob/living/user, req_state, req_anchored, req_floor) + if (!isnull(req_state) && req_state != state) + return FALSE + if (req_floor && !isfloorturf(loc)) + balloon_alert(user, "needs a floor!") + return FALSE + return TRUE + +// We do this instead of state handling because of the large number of variables we would otherwise need to keep track of. +// That said, ultimately, it would be a better solution for all of it to just be [/obj/structure/girder] at base. +// For example right now if you paint a girder and use a wrench on it, it will magically lose that paint. +/obj/structure/girder/proc/replace_girder(girder_type) + var/obj/structure/girder/new_girder = new girder_type(loc) + transfer_fingerprints_to(new_girder) + new_girder.update_integrity(new_girder.max_integrity * (atom_integrity / max_integrity)) + qdel(src) /obj/structure/girder/CanAllowThrough(atom/movable/mover, border_dir) . = ..() if((mover.pass_flags & PASSGRILLE) || isprojectile(mover)) - return prob(girderpasschance) + return prob(projectile_pass_chance) /obj/structure/girder/CanAStarPass(to_dir, datum/can_pass_info/pass_info) if(!density) @@ -420,12 +155,14 @@ return FALSE /obj/structure/girder/atom_deconstruct(disassembled = TRUE) - var/remains = pick(/obj/item/stack/rods, /obj/item/stack/sheet/iron) - new remains(loc) + if (disassembled || always_drop_stack) + new stack_type(drop_location(), stack_amount) + else + var/remains = pick(/obj/item/stack/rods, stack_type) + new remains(drop_location()) /obj/structure/girder/narsie_act() - new /obj/structure/girder/cult(loc) - qdel(src) + replace_girder(/obj/structure/girder/cult) /obj/structure/girder/displaced name = "displaced girder" @@ -433,7 +170,7 @@ icon_state = "displaced" anchored = FALSE state = GIRDER_DISPLACED - girderpasschance = 25 + projectile_pass_chance = 25 max_integrity = 120 smoothing_flags = NONE smoothing_groups = null @@ -445,7 +182,7 @@ icon_state = "reinforced-0" base_icon_state = "reinforced" state = GIRDER_REINF - girderpasschance = 0 + projectile_pass_chance = 0 max_integrity = 350 /obj/structure/girder/tram @@ -458,6 +195,7 @@ smoothing_flags = NONE smoothing_groups = null canSmoothWith = null + stack_type = /obj/item/stack/sheet/mineral/titanium /obj/structure/girder/tram/corner name = "tram frame corner" @@ -474,43 +212,14 @@ smoothing_groups = null canSmoothWith = null custom_materials = list(/datum/material/runedmetal = SHEET_MATERIAL_AMOUNT) - -/obj/structure/girder/cult/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) - add_fingerprint(user) - if(W.tool_behaviour == TOOL_WELDER) - if(!W.tool_start_check(user, amount=1)) - return - - balloon_alert(user, "slicing apart...") - if(W.use_tool(src, user, 40, volume=50)) - var/obj/item/stack/sheet/runed_metal/R = new(drop_location(), 1) - transfer_fingerprints_to(R) - qdel(src) - - else if(istype(W, /obj/item/stack/sheet/runed_metal)) - var/obj/item/stack/sheet/runed_metal/R = W - var/amount = construction_cost[R.type] - if(R.get_amount() < amount) - balloon_alert(user, "need [amount] sheet!") - return - balloon_alert(user, "adding plating...") - if(do_after(user, 5 SECONDS, target = src)) - if(R.get_amount() < amount) - return - R.use(amount) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall/mineral/cult) - qdel(src) - - else - return ..() + stack_type = /obj/item/stack/sheet/runed_metal + stack_amount = 1 + always_drop_stack = TRUE + can_weld_apart = TRUE /obj/structure/girder/cult/narsie_act() return -/obj/structure/girder/cult/atom_deconstruct(disassembled = TRUE) - new /obj/item/stack/sheet/runed_metal(drop_location()) - /obj/structure/girder/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) switch(the_rcd.mode) if(RCD_TURF) @@ -550,32 +259,7 @@ smoothing_groups = null canSmoothWith = null custom_materials = list(/datum/material/bronze = SHEET_MATERIAL_AMOUNT * 2) - -/obj/structure/girder/bronze/attackby(obj/item/W, mob/living/user, list/modifiers, list/attack_modifiers) - add_fingerprint(user) - if(W.tool_behaviour == TOOL_WELDER) - if(!W.tool_start_check(user, amount = 0, heat_required = HIGH_TEMPERATURE_REQUIRED)) - return - balloon_alert(user, "slicing apart...") - if(W.use_tool(src, user, 40, volume=50)) - var/obj/item/stack/sheet/bronze/B = new(drop_location(), 2) - transfer_fingerprints_to(B) - qdel(src) - - else if(istype(W, /obj/item/stack/sheet/bronze)) - var/obj/item/stack/sheet/bronze/B = W - var/amount = construction_cost[B.type] - if(B.get_amount() < amount) - balloon_alert(user, "need [amount] sheets!") - return - balloon_alert(user, "adding plating...") - if(do_after(user, 5 SECONDS, target = src)) - if(B.get_amount() < amount) - return - B.use(amount) - var/turf/T = get_turf(src) - T.place_on_top(/turf/closed/wall/mineral/bronze) - qdel(src) - - else - return ..() + stack_type = /obj/item/stack/sheet/bronze + stack_amount = 1 + always_drop_stack = TRUE + can_weld_apart = TRUE diff --git a/code/game/turfs/closed/wall/mineral_walls.dm b/code/game/turfs/closed/wall/mineral_walls.dm index d06f83e6853..02e40a4054e 100644 --- a/code/game/turfs/closed/wall/mineral_walls.dm +++ b/code/game/turfs/closed/wall/mineral_walls.dm @@ -190,6 +190,8 @@ desc = "A solidly wooden wall. It's a bit weaker than a wall made with metal." girder_type = /obj/structure/barricade/wooden hardness = 67 //a bit weaker than iron (60) + sheet_amount = 5 + make_delay = 5 SECONDS /turf/closed/wall/mineral/bamboo name = "bamboo wall" diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm index 525b9540b65..2fd14fda880 100644 --- a/code/game/turfs/closed/wall/reinf_walls.dm +++ b/code/game/turfs/closed/wall/reinf_walls.dm @@ -12,6 +12,8 @@ sheet_type = /obj/item/stack/sheet/plasteel sheet_amount = 1 girder_type = /obj/structure/girder/reinforced + girder_state = GIRDER_REINF + make_delay = 5 SECONDS explosive_resistance = 2 rad_insulation = RAD_HEAVY_INSULATION rust_resistance = RUST_RESISTANCE_REINFORCED diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index ed29d3cebe4..2501b3767b3 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -24,16 +24,23 @@ ///lower numbers are harder. Used to determine the probability of a hulk smashing through. var/hardness = 40 var/slicing_duration = 100 //default time taken to slice the wall - var/sheet_type = /obj/item/stack/sheet/iron - var/sheet_amount = 2 - var/girder_type = /obj/structure/girder /// A turf that will replace this turf when this turf is destroyed var/decon_type /// If we added a leaning component to ourselves var/added_leaning = FALSE - var/list/dent_decals + /// The type of sheet this wall requires for construction and drops upon deconstruction. + var/sheet_type = /obj/item/stack/sheet/iron + /// The amount of sheets this wall requires for construction and drops upon deconstruction. + var/sheet_amount = 2 + /// The type of girder this wall requires for construction and drops upon deconstruction. + var/girder_type = /obj/structure/girder + /// The girder state this wall requires for construction and drops upon deconstruction. + var/girder_state = GIRDER_NORMAL + /// How long this wall takes to make by using its sheet type on a girder. + var/make_delay = 4 SECONDS + /turf/closed/wall/Initialize(mapload) . = ..() if(!can_engrave) diff --git a/tgstation.dme b/tgstation.dme index d0fc3aa433b..88350149c0e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -573,6 +573,7 @@ #include "code\_globalvars\lists\disposals.dm" #include "code\_globalvars\lists\engineering.dm" #include "code\_globalvars\lists\ghost.dm" +#include "code\_globalvars\lists\girder_wall_recipes.dm" #include "code\_globalvars\lists\icons.dm" #include "code\_globalvars\lists\keybindings.dm" #include "code\_globalvars\lists\languages.dm" @@ -844,6 +845,7 @@ #include "code\datums\embedding.dm" #include "code\datums\emotes.dm" #include "code\datums\ert.dm" +#include "code\datums\girder_wall_recipe.dm" #include "code\datums\hailer_phrase.dm" #include "code\datums\holocall.dm" #include "code\datums\hotkeys_help.dm" @@ -1689,6 +1691,7 @@ #include "code\datums\elements\update_icon_blocker.dm" #include "code\datums\elements\update_icon_updates_onmob.dm" #include "code\datums\elements\uplink_reimburse.dm" +#include "code\datums\elements\uses_girder_wall_recipes.dm" #include "code\datums\elements\venomous.dm" #include "code\datums\elements\volatile_gas_storage.dm" #include "code\datums\elements\voucher_redeemer.dm"