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 <killer65311@gmail.com>
This commit is contained in:
Will
2026-03-26 22:10:06 -04:00
committed by GitHub
co-authored by Cameron Lennox
parent 3fc4d84466
commit bf29ca396f
14 changed files with 143 additions and 97 deletions
+5
View File
@@ -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
+17 -7
View File
@@ -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)
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
@@ -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"
+16 -56
View File
@@ -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"
@@ -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)
. = ..()
+7 -1
View File
@@ -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)
+51
View File
@@ -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
+18
View File
@@ -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'
+3
View File
@@ -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
@@ -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
+1
View File
@@ -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"