From bf29ca396f201c63b6f68465a4899581d5dc6a75 Mon Sep 17 00:00:00 2001 From: Will <7099514+Willburd@users.noreply.github.com> Date: Thu, 26 Mar 2026 22:10:06 -0400 Subject: [PATCH] Shovel digging refactor (#19345) * fixes per pile lootable counts * shovel digging element * retooled to flag * take two * proc that * sand digging * collapse that system in too * allow base loot * desc * potat * fix that * no making that on rocks * oops * var version * prevent that dupe * fixes --------- Co-authored-by: Cameron Lennox --- code/__defines/turfs.dm | 5 ++ code/datums/elements/lootable/_lootable.dm | 24 +++++-- code/game/turfs/simulated/floor_attackby.dm | 4 ++ code/game/turfs/simulated/outdoors/dirt.dm | 2 +- code/game/turfs/simulated/outdoors/grass.dm | 2 +- .../turfs/simulated/outdoors/ironsand_vr.dm | 1 + .../game/turfs/simulated/outdoors/outdoors.dm | 72 +++++-------------- .../simulated/outdoors/survival_action_vr.dm | 48 +++++-------- code/game/turfs/turf.dm | 8 ++- code/game/turfs/turf_shoveling.dm | 51 +++++++++++++ code/game/turfs/unsimulated/beach.dm | 18 +++++ code/modules/mining/mine_turfs.dm | 3 + .../subtypes/animal/alien animals/stardog.dm | 1 - vorestation.dme | 1 + 14 files changed, 143 insertions(+), 97 deletions(-) create mode 100644 code/game/turfs/turf_shoveling.dm diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm index eb83eeb1c0..2bc3dd645e 100644 --- a/code/__defines/turfs.dm +++ b/code/__defines/turfs.dm @@ -9,6 +9,7 @@ #define TURF_IS_FRAGILE 256 #define TURF_ACID_IMMUNE 512 #define TURF_UNSHIELDABLE 1024 +#define TURF_CAN_DIG_SHOVEL 2048 // The 0x800000 is blocked by INITIALIZED, do NOT use it! //Used for floor/wall smoothing @@ -50,3 +51,7 @@ ///Returns all turfs in a zlevel #define Z_TURFS(ZLEVEL) block(1, 1, ZLEVEL, world.maxx, world.maxy, ZLEVEL) + +/// Digging loot with a shovel +#define TURF_DIG_LOOT_ENDLESS 0 +#define TURF_DIG_LOOT_EXHAUSTED 100 diff --git a/code/datums/elements/lootable/_lootable.dm b/code/datums/elements/lootable/_lootable.dm index b4856b7c53..b8d4c5e23a 100644 --- a/code/datums/elements/lootable/_lootable.dm +++ b/code/datums/elements/lootable/_lootable.dm @@ -4,9 +4,9 @@ var/chance_rare = 1 // Ditto, but for rare_loot list. var/chance_gamma = 0 // Singledrop global loot table shared with all piles. - var/allow_multiple_looting = FALSE // If true, the same person can loot multiple times. Mostly for debugging. + var/allow_multiple_looting = TRUE // If true, the same person can loot multiple times. Mostly for debugging. var/loot_depletion = FALSE // If true, loot piles can be 'depleted' after a certain number of searches by different players, where no more loot can be obtained. - var/loot_left = 0 // When this reaches zero, and loot_depleted is true, you can't obtain anymore loot. + var/loot_left = 0 // Maximum number of times a pile can be looted before no loot will remain for anyone var/delete_on_depletion = FALSE // If true, and if the loot gets depleted as above, the pile is deleted. var/list/unlucky_loot = list() // Unlucky is the worst tier. Only people with the unlucky trait can get this stuff. Primed grenades, dangerous syringes, etc. @@ -14,6 +14,8 @@ var/list/uncommon_loot = list() // Uncommon is actually maybe some useful items, usually the reason someone bothers looking inside. var/list/rare_loot = list() // Rare is really powerful, or at least unique items. + var/static/list/piles_looted = list() // Keeps track of the number of times a specific pile has been looted if the specific lootable type has loot_depletion on + /datum/element/lootable/Attach(atom/target) . = ..() if(!isatom(target)) @@ -22,15 +24,19 @@ /datum/element/lootable/Detach(atom/target) . = ..() + if(loot_depletion) + piles_looted -= REF(target) UnregisterSignal(target, COMSIG_LOOT_REWARD) /// Calculates and drops loot, the source's turf is where it will be dropped, L is the searching mob, and searched_by is a passed list for storing who has searched a loot pile. /datum/element/lootable/proc/loot(atom/source,mob/living/L,var/list/searched_by, wake_chance = 0) SIGNAL_HANDLER // The loot's all gone. - if(loot_depletion && loot_left <= 0) - to_chat(L, span_warning("\The [source] has been picked clean.")) - return + if(loot_depletion) + var/looted_count = piles_looted[REF(source)] + if(looted_count >= loot_left) + to_chat(L, span_warning("\The [source] has been picked clean.")) + return // You got unlucky. if(chance_nothing && prob(chance_nothing)) @@ -100,8 +106,12 @@ // Check if we should delete on depletion if(!loot_depletion) return - loot_left-- - if(loot_left > 0) + // Add to looted piles if not already one + if(!(REF(source) in piles_looted)) + piles_looted[REF(source)] = 0 + // Increase the looted count till we've hit our limit + piles_looted[REF(source)] += 1 + if(piles_looted[REF(source)] < loot_left) return to_chat(L, span_warning("You seem to have gotten the last of the spoils in \the [source].")) if(delete_on_depletion) diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm index caa0875b49..680f40ae00 100644 --- a/code/game/turfs/simulated/floor_attackby.dm +++ b/code/game/turfs/simulated/floor_attackby.dm @@ -3,6 +3,10 @@ if(!C || !user) return 0 + // Check parent signals + if(..()) + return + if(isliving(user) && istype(C, /obj/item)) var/mob/living/L = user if(L.a_intent != I_HELP) diff --git a/code/game/turfs/simulated/outdoors/dirt.dm b/code/game/turfs/simulated/outdoors/dirt.dm index 887ca46fe7..010b1463e2 100644 --- a/code/game/turfs/simulated/outdoors/dirt.dm +++ b/code/game/turfs/simulated/outdoors/dirt.dm @@ -5,4 +5,4 @@ edge_blending_priority = 2 turf_layers = list(/turf/simulated/floor/outdoors/rocks) initial_flooring = /datum/decl/flooring/dirt - can_dig = TRUE + flags = TURF_CAN_DIG_SHOVEL diff --git a/code/game/turfs/simulated/outdoors/grass.dm b/code/game/turfs/simulated/outdoors/grass.dm index 155565fcb3..5500123236 100644 --- a/code/game/turfs/simulated/outdoors/grass.dm +++ b/code/game/turfs/simulated/outdoors/grass.dm @@ -3,7 +3,7 @@ icon_state = "grass0" edge_blending_priority = 4 initial_flooring = /datum/decl/flooring/grass/outdoors // VOREStation Edit - can_dig = TRUE + flags = TURF_CAN_DIG_SHOVEL turf_layers = list( /turf/simulated/floor/outdoors/rocks, /turf/simulated/floor/outdoors/dirt diff --git a/code/game/turfs/simulated/outdoors/ironsand_vr.dm b/code/game/turfs/simulated/outdoors/ironsand_vr.dm index ee167df7b1..1f7e65a084 100644 --- a/code/game/turfs/simulated/outdoors/ironsand_vr.dm +++ b/code/game/turfs/simulated/outdoors/ironsand_vr.dm @@ -5,6 +5,7 @@ icon_state = "ironsand1" edge_blending_priority = 1 initial_flooring = /datum/decl/flooring/outdoors/ironsand + flags = TURF_CAN_DIG_SHOVEL /datum/decl/flooring/outdoors/ironsand name = "iron sand" diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm index 8cc5fb4306..8146b17aae 100644 --- a/code/game/turfs/simulated/outdoors/outdoors.dm +++ b/code/game/turfs/simulated/outdoors/outdoors.dm @@ -24,67 +24,21 @@ GLOBAL_LIST_EMPTY(turf_edge_cache) // When a turf gets demoted or promoted, this list gets adjusted. The top-most layer is the layer on the bottom of the list, due to how pop() works. var/list/turf_layers = list(/turf/simulated/floor/outdoors/rocks) - var/can_dig = FALSE - var/loot_count - -/turf/simulated/floor/outdoors/proc/get_loot_type() - if(loot_count && prob(60)) - return pick( \ - 12;/obj/item/reagent_containers/food/snacks/worm, \ - 1;/obj/item/material/knife/machete/hatchet/stone \ - ) - -/turf/simulated/floor/outdoors/Initialize(mapload) - . = ..() - if(can_dig && prob(33)) - loot_count = rand(1,3) - -/turf/simulated/floor/outdoors/attackby(obj/item/C, mob/user) - - if(can_dig && istype(C, /obj/item/shovel)) - var/obj/item/shovel/our_shovel = C - if(our_shovel.grave_mode) - if(contents.len > 0) - to_chat(user, span_warning("You can't dig here!")) - return - to_chat(user, span_notice("\The [user] begins digging into \the [src] with \the [C].")) - var/delay = (5 SECONDS * C.toolspeed) - user.setClickCooldown(delay) - if(do_after(user, delay, target = src)) - new/obj/structure/closet/grave/dirthole(src) - to_chat(user, span_notice("You dug up a hole!")) - return - else - to_chat(user, span_notice("\The [user] begins digging into \the [src] with \the [C].")) - var/delay = (3 SECONDS * C.toolspeed) - user.setClickCooldown(delay) - if(do_after(user, delay, target = src)) - if(!(locate(/obj/machinery/portable_atmospherics/hydroponics/soil) in contents)) - var/obj/machinery/portable_atmospherics/hydroponics/soil/soil = new(src) - user.visible_message(span_notice("\The [src] digs \a [soil] into \the [src].")) - else - var/loot_type = get_loot_type() - if(loot_type) - loot_count-- - var/obj/item/loot = new loot_type(src) - to_chat(user, span_notice("You dug up \a [loot]!")) - else - to_chat(user, span_notice("You didn't find anything of note in \the [src].")) - return - - . = ..() -/* VOREStation remove - handled by parent -/turf/simulated/floor/Initialize(mapload) - if(is_outdoors()) - SSplanets.addTurf(src) - . = ..() -*/ /turf/simulated/floor/Destroy() if(is_outdoors()) SSplanets.removeTurf(src) return ..() +/turf/simulated/floor/outdoors/get_dig_loot_type(mob/user, obj/item/W) + return pick( \ + 12;/obj/item/reagent_containers/food/snacks/worm, \ + 1;/obj/item/material/knife/machete/hatchet/stone \ + ) + +/turf/simulated/floor/outdoors/shovel_can_cultivate() + return TRUE + // Turfs can decide if they should be indoors or outdoors. // By default they choose based on their area's setting. // This helps cut down on ten billion `/outdoors` subtypes being needed. @@ -130,7 +84,7 @@ GLOBAL_LIST_EMPTY(turf_edge_cache) icon_state = "mud_dark" edge_blending_priority = 3 initial_flooring = /datum/decl/flooring/mud - can_dig = TRUE + flags = TURF_CAN_DIG_SHOVEL /turf/simulated/floor/outdoors/rocks name = "rocks" @@ -138,6 +92,11 @@ GLOBAL_LIST_EMPTY(turf_edge_cache) icon_state = "rock" edge_blending_priority = 1 initial_flooring = /datum/decl/flooring/rock + dig_exhaustion_chance = TURF_DIG_LOOT_ENDLESS + flags = TURF_CAN_DIG_SHOVEL + +/turf/simulated/floor/outdoors/rocks/shovel_can_cultivate() + return FALSE // Nope, no growing stuff on rocks /turf/simulated/floor/outdoors/rocks/caves outdoors = OUTDOORS_NO @@ -215,6 +174,7 @@ GLOBAL_LIST_EMPTY(turf_edge_cache) icon_state = "dirt0" edge_blending_priority = 2 initial_flooring = /datum/decl/flooring/outdoors/newdirt + flags = TURF_CAN_DIG_SHOVEL /datum/decl/flooring/outdoors/newdirt name = "dirt" diff --git a/code/game/turfs/simulated/outdoors/survival_action_vr.dm b/code/game/turfs/simulated/outdoors/survival_action_vr.dm index 64882ef79b..5d92166313 100644 --- a/code/game/turfs/simulated/outdoors/survival_action_vr.dm +++ b/code/game/turfs/simulated/outdoors/survival_action_vr.dm @@ -26,39 +26,27 @@ GLOBAL_LIST_INIT(has_rocks, list("dirt5", "dirt6", "dirt7", "dirt8", "dirt9")) if(do_after(user, 5 SECONDS, target = src)) new /obj/machinery/portable_atmospherics/hydroponics/soil(src) -/turf/simulated/floor/outdoors - var/rock_chance = 0 +/turf/simulated/floor/outdoors/newdirt/get_dig_loot_type(mob/user, obj/item/W) + if(prob(5)) + return /obj/item/stack/material/flint + if(prob(2)) + return pick(/obj/fruitspawner/potato, /obj/fruitspawner/carrot) + . = ..() -/turf/simulated/floor/outdoors/proc/rock_gathering(var/mob/user as mob) - if(locate(/obj) in src) - to_chat(user, span_notice("The [name] isn't clear.")) - return - user.visible_message("[user] starts digging around in \the [src]...", "You start digging around in \the [src]...") - if(do_after(user, 5 SECONDS, target = src)) - if(prob(rock_chance)) - var/obj/item/stack/material/flint/R = new(get_turf(src), rand(1,4)) - to_chat(user, span_notice("You found some [R]")) - R.pixel_x = rand(-6,6) - R.pixel_y = rand(-6,6) - else - to_chat(user, span_notice("You didn't find anything...")) - else - return +/turf/simulated/floor/outdoors/dirt/get_dig_loot_type(mob/user, obj/item/W) + if(prob(10)) + return /obj/item/stack/material/flint + if(prob(2)) + return pick(/obj/fruitspawner/potato, /obj/fruitspawner/carrot) + . = ..() -/turf/simulated/floor/outdoors/attackby(var/obj/item/O as obj, var/mob/user as mob) - if(istype(O, /obj/item/shovel) && rock_chance) - rock_gathering(user) - else - return ..() +/turf/simulated/floor/outdoors/rocks/get_dig_loot_type(mob/user, obj/item/W) + return /obj/item/stack/material/flint -/turf/simulated/floor/outdoors/newdirt - rock_chance = 5 -/turf/simulated/floor/outdoors/dirt - rock_chance = 10 -/turf/simulated/floor/outdoors/rocks - rock_chance = 100 -/turf/simulated/floor/outdoors/ironsand - rock_chance = 50 +/turf/simulated/floor/outdoors/ironsand/get_dig_loot_type(mob/user, obj/item/W) + if(prob(50)) + return pick(/obj/item/stack/material/flint, /obj/item/ore/iron) + . = ..() /turf/simulated/floor/outdoors/newdirt/examine(var/mob/user) . = ..() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 07c7177584..b81d5683ec 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -26,6 +26,7 @@ var/icon_old = null var/pathweight = 1 // How much does it cost to pathfind over this turf? var/blessed = 0 // Has the turf been blessed? + var/dig_exhaustion_chance = 60 // Chance that the digging loot will be exhausted, if set to TURF_DIG_LOOT_EXHAUSTED then the turf is exhausted of loot. if set to TURF_DIG_LOOT_ENDLESS it will never run out. var/list/decals @@ -161,7 +162,12 @@ step(user.pulling, get_dir(user.pulling.loc, src)) return 1 -/turf/attackby(obj/item/W as obj, mob/user as mob) +/turf/attackby(obj/item/W, mob/user) + // Check if this turf can be dug up, check initial because we remove the flag when we've exhausted all loot, but still want to keep dig functionality + if((flags & TURF_CAN_DIG_SHOVEL) && !density && istype(W, /obj/item/shovel)) + handle_turf_dig(user, W) + return TRUE + // Collect objects on turf if the bag supports scooping stuff up if(istype(W, /obj/item/storage)) var/obj/item/storage/S = W if(S.use_to_pickup && S.collection_mode) diff --git a/code/game/turfs/turf_shoveling.dm b/code/game/turfs/turf_shoveling.dm new file mode 100644 index 0000000000..2d1b5b00dc --- /dev/null +++ b/code/game/turfs/turf_shoveling.dm @@ -0,0 +1,51 @@ +/turf/proc/handle_turf_dig(mob/user, obj/item/shovel/our_shovel) + SHOULD_NOT_OVERRIDE(TRUE) + + // Grave digging + if(our_shovel.grave_mode) + shovel_dig_grave(user, our_shovel) + return + + // Loot and garden digging + to_chat(user, span_notice("\The [user] begins digging into \the [src] with \the [our_shovel].")) + if(do_after(user, 3 SECONDS * our_shovel.toolspeed, target = src)) + if(shovel_can_cultivate() && !(locate(/obj/machinery/portable_atmospherics/hydroponics/soil) in contents) && !(locate(/obj/structure/closet/grave/dirthole) in contents)) + var/obj/machinery/portable_atmospherics/hydroponics/soil/soil = new(src) + user.visible_message(span_notice("\The [src] digs \a [soil] into \the [src].")) + return + + // Spawn loot + if(dig_exhaustion_chance >= TURF_DIG_LOOT_EXHAUSTED) + to_chat(user, span_warning("There is nothing more to be found in \the [src].")) + return + var/loot_type = get_dig_loot_type(user, our_shovel) + if(!loot_type) + to_chat(user, span_notice("You didn't find anything of note in \the [src].")) + return + var/obj/item/loot = new loot_type(src) + to_chat(user, span_notice("You dug up \a [loot]!")) + + // Check if we should be exhausted of loot + if(dig_exhaustion_chance && prob(dig_exhaustion_chance)) + dig_exhaustion_chance = TURF_DIG_LOOT_EXHAUSTED + +/turf/proc/shovel_dig_grave(mob/user, obj/item/shovel/our_shovel) + if(length(contents)) + to_chat(user, span_warning("You can't dig here!")) + return + // Make a grave + to_chat(user, span_notice("\The [user] begins digging into \the [src] with \the [our_shovel].")) + var/delay = (5 SECONDS * our_shovel.toolspeed) + user.setClickCooldown(delay) + if(do_after(user, delay, target = src)) + if(!(locate(/obj/structure/closet/grave/dirthole) in contents)) + new /obj/structure/closet/grave/dirthole(src) + to_chat(user, span_notice("You dug up a hole!")) + +/// If a turf has any loot when dug with a shovel +/turf/proc/get_dig_loot_type(mob/user, obj/item/W) + return null + +/// If a turf supports making growbeds +/turf/proc/shovel_can_cultivate() + return FALSE diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm index ff704a2dcc..f82aebd842 100644 --- a/code/game/turfs/unsimulated/beach.dm +++ b/code/game/turfs/unsimulated/beach.dm @@ -30,6 +30,24 @@ name = "Sand" icon_state = "sand" initial_flooring = /datum/decl/flooring/sand + flags = TURF_CAN_DIG_SHOVEL // Can dig but can't cultivate + +/turf/simulated/floor/beach/sand/get_dig_loot_type(mob/user, obj/item/W) + if(prob(2)) + // Things of note that might wash up on a beach + return pick(/obj/item/coin/silver, + /obj/item/coin/gold, + /obj/item/coin/copper, + /obj/item/clothing/shoes/sandal, + /obj/item/cell/empty, + /obj/item/stack/cable_coil/cut, + /obj/item/ore/iron, + /obj/item/stack/material/wood, + /obj/item/stack/material/stick, + /obj/item/stack/material/flint, + /obj/item/stack/material/smolebricks, + ) + return null /turf/simulated/floor/beach/sand/desert icon = 'icons/turf/desert.dmi' diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 09fe0551db..fceb66f33c 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -373,6 +373,9 @@ GLOBAL_LIST_EMPTY(mining_overlay_cache) if(istype(W, /obj/item/shovel)) var/obj/item/shovel/S = W + if(S.grave_mode) + shovel_dig_grave(user, S) + return valid_tool = 1 digspeed = S.digspeed diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm index 4adc2eed25..c4ca1dae9c 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm @@ -370,7 +370,6 @@ icon_state = "fur0" edge_blending_priority = 4 initial_flooring = /datum/decl/flooring/fur - can_dig = FALSE var/tree_chance = 25 var/tree_color = null var/tree_type = /obj/structure/flora/tree/fur diff --git a/vorestation.dme b/vorestation.dme index c91ed035f9..e43d7c82f6 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2107,6 +2107,7 @@ #include "code\game\turfs\turf.dm" #include "code\game\turfs\turf_changing.dm" #include "code\game\turfs\turf_flick_animations.dm" +#include "code\game\turfs\turf_shoveling.dm" #include "code\game\turfs\unsimulated.dm" #include "code\game\turfs\weird_turfs_vr.dm" #include "code\game\turfs\flooring\flooring.dm"