diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_ore_vent.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_ore_vent.dmm
new file mode 100644
index 00000000000..51584f90f86
--- /dev/null
+++ b/_maps/RandomRuins/IceRuins/icemoon_surface_ore_vent.dmm
@@ -0,0 +1,27 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"l" = (
+/turf/open/misc/asteroid/snow/icemoon,
+/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters)
+"L" = (
+/obj/structure/ore_vent/random/icebox,
+/turf/open/misc/asteroid/snow/icemoon,
+/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters)
+
+(1,1,1) = {"
+a
+l
+a
+"}
+(2,1,1) = {"
+l
+L
+l
+"}
+(3,1,1) = {"
+a
+l
+a
+"}
diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_ore_vent.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_ore_vent.dmm
new file mode 100644
index 00000000000..db409d08c8c
--- /dev/null
+++ b/_maps/RandomRuins/IceRuins/icemoon_underground_ore_vent.dmm
@@ -0,0 +1,27 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"l" = (
+/turf/open/misc/asteroid/snow/icemoon,
+/area/icemoon/underground/unexplored)
+"L" = (
+/obj/structure/ore_vent/random/icebox/lower,
+/turf/open/misc/asteroid/snow/icemoon,
+/area/icemoon/underground/unexplored)
+
+(1,1,1) = {"
+a
+l
+a
+"}
+(2,1,1) = {"
+l
+L
+l
+"}
+(3,1,1) = {"
+a
+l
+a
+"}
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ore_vent.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ore_vent.dmm
new file mode 100644
index 00000000000..6379b7f084b
--- /dev/null
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ore_vent.dmm
@@ -0,0 +1,27 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/template_noop,
+/area/template_noop)
+"l" = (
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
+"L" = (
+/obj/structure/ore_vent/random,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
+
+(1,1,1) = {"
+a
+l
+a
+"}
+(2,1,1) = {"
+l
+L
+l
+"}
+(3,1,1) = {"
+a
+l
+a
+"}
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index 3a7cbc96fe0..ee703769c61 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -18081,11 +18081,13 @@
/area/station/engineering/atmos/storage/gas)
"gDR" = (
/obj/structure/disposalpipe/segment,
-/obj/structure/table/greyscale,
-/obj/item/folder/yellow,
/obj/machinery/light/small/directional/south,
-/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"gEc" = (
/obj/structure/closet/emcloset,
/turf/open/floor/plating,
@@ -20111,8 +20113,9 @@
"hlA" = (
/obj/machinery/airalarm/directional/north,
/obj/machinery/newscaster/directional/west,
+/obj/structure/chair,
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"hlJ" = (
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{
dir = 4
@@ -20715,6 +20718,15 @@
/obj/machinery/light/small/directional/south,
/turf/open/floor/iron,
/area/station/security/tram)
+"hvY" = (
+/obj/machinery/door/airlock/mining{
+ name = "Mining Office"
+ },
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/turf/open/floor/iron/smooth,
+/area/station/cargo/miningfoundry)
"hwe" = (
/obj/machinery/hydroponics/constructable,
/obj/effect/turf_decal/tile/blue/half,
@@ -21008,6 +21020,7 @@
"hAN" = (
/obj/structure/cable,
/obj/effect/decal/cleanable/dirt,
+/obj/machinery/airalarm/directional/west,
/turf/open/floor/iron/smooth,
/area/station/cargo/warehouse)
"hAQ" = (
@@ -21580,6 +21593,31 @@
},
/obj/structure/table,
/obj/item/clothing/mask/cigarette,
+/obj/item/toy/toy_dagger,
+/obj/item/clothing/head/collectable/paper,
+/obj/item/toy/figure/roboticist{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/toy/figure/syndie{
+ pixel_y = 5;
+ pixel_x = -6
+ },
+/obj/item/toy/figure/md{
+ pixel_x = 10
+ },
+/obj/item/toy/figure/hop{
+ pixel_x = 2;
+ pixel_y = -2
+ },
+/obj/item/toy/figure/ian{
+ pixel_x = -5;
+ pixel_y = -1
+ },
+/obj/item/toy/figure/lawyer{
+ pixel_x = -10
+ },
+/obj/item/toy/figure/detective,
/turf/open/floor/plating,
/area/station/maintenance/port/fore)
"hMr" = (
@@ -21601,11 +21639,6 @@
/obj/effect/turf_decal/tile/brown/opposingcorners,
/obj/structure/closet/crate,
/obj/effect/spawner/random/engineering/flashlight,
-/obj/effect/spawner/random/engineering/flashlight,
-/obj/item/stack/cable_coil{
- pixel_x = 3;
- pixel_y = -7
- },
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"hMz" = (
@@ -22215,6 +22248,9 @@
},
/turf/open/floor/iron/dark/smooth_large,
/area/station/command/meeting_room)
+"hZI" = (
+/turf/closed/wall,
+/area/station/cargo/miningfoundry)
"hZP" = (
/obj/structure/cable,
/obj/structure/sign/poster/official/random/directional/north,
@@ -22907,6 +22943,12 @@
/obj/effect/landmark/start/security_officer,
/turf/open/floor/iron,
/area/station/security/tram)
+"imD" = (
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/turf/closed/wall,
+/area/station/cargo/miningfoundry)
"imE" = (
/obj/effect/mapping_helpers/broken_floor,
/obj/effect/landmark/atmospheric_sanity/ignore_area,
@@ -24195,10 +24237,13 @@
/turf/open/floor/plating,
/area/station/maintenance/fore/greater)
"iKV" = (
-/obj/effect/mapping_helpers/broken_floor,
/obj/machinery/light/small/directional/north,
+/obj/machinery/conveyor_switch{
+ id = "mining";
+ pixel_x = -10
+ },
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"iLc" = (
/obj/effect/turf_decal/siding/red{
dir = 4
@@ -24370,7 +24415,7 @@
},
/obj/effect/mapping_helpers/airlock/abandoned,
/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"iNO" = (
/obj/effect/turf_decal/stripes/white/line{
dir = 6
@@ -25554,11 +25599,8 @@
/turf/open/floor/iron,
/area/station/commons)
"jkw" = (
-/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/table/greyscale,
-/obj/item/folder/ancient_paperwork,
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"jkz" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
dir = 8
@@ -25589,10 +25631,12 @@
/obj/structure/disposalpipe/segment{
dir = 6
},
-/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/chair,
+/obj/structure/railing{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2,
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"jlt" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -26504,14 +26548,21 @@
"jCR" = (
/obj/structure/cable,
/obj/machinery/power/apc/auto_name/directional/north,
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
- dir = 8
- },
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron/smooth,
/area/station/cargo/warehouse)
"jCW" = (
-/obj/machinery/airalarm/directional/east,
-/turf/open/floor/plating,
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/white/line{
+ dir = 4
+ },
+/turf/open/floor/iron/smooth,
/area/station/cargo/warehouse)
"jDa" = (
/obj/machinery/holopad,
@@ -27346,6 +27397,12 @@
/obj/machinery/light/small/directional/east,
/obj/machinery/light_switch/directional/east,
/obj/effect/mapping_helpers/turn_off_lights_with_lightswitch,
+/obj/effect/turf_decal/stripes/corner{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/white/corner{
+ dir = 4
+ },
/turf/open/floor/iron/smooth,
/area/station/cargo/warehouse)
"jPq" = (
@@ -28419,8 +28476,12 @@
},
/obj/effect/mapping_helpers/broken_floor,
/obj/structure/sign/poster/random/directional/east,
-/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/obj/machinery/conveyor{
+ id = "mining"
+ },
+/obj/machinery/bouldertech/brm,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"kkm" = (
/obj/machinery/door/airlock/medical/glass{
name = "Primary Treatment Centre"
@@ -31236,9 +31297,14 @@
/obj/structure/cable,
/obj/effect/turf_decal/tile/brown/opposingcorners,
/obj/effect/decal/cleanable/dirt,
-/obj/item/kirbyplants/random,
/obj/machinery/power/apc/auto_name/directional/north,
/obj/machinery/light_switch/directional/east,
+/obj/structure/rack,
+/obj/item/stack/cable_coil{
+ pixel_x = 3;
+ pixel_y = -7
+ },
+/obj/effect/spawner/random/engineering/flashlight,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"lgV" = (
@@ -33080,6 +33146,13 @@
dir = 4
},
/area/station/hallway/primary/central/fore)
+"lNs" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
+ dir = 1
+ },
+/turf/open/floor/iron/smooth,
+/area/station/cargo/warehouse)
"lNw" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
@@ -35396,19 +35469,17 @@
/turf/open/floor/iron,
/area/station/hallway/primary/central/fore)
"mDC" = (
-/obj/structure/closet/crate{
- name = "Game Supplies"
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/white/line{
+ dir = 8
},
-/obj/item/toy/figure/lawyer,
-/obj/item/toy/figure/ian,
-/obj/item/toy/figure/hop,
-/obj/item/toy/figure/syndie,
-/obj/item/toy/figure/roboticist,
-/obj/item/toy/figure/md,
-/obj/item/clothing/head/collectable/paper,
-/obj/item/toy/toy_dagger,
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"mDG" = (
/obj/effect/turf_decal/tile/dark_red/half/contrasted{
dir = 1
@@ -36468,6 +36539,10 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/ash,
+/obj/item/storage/dice{
+ pixel_x = -16;
+ pixel_y = -6
+ },
/turf/open/floor/iron,
/area/station/maintenance/port/fore)
"mXt" = (
@@ -40565,9 +40640,11 @@
/area/station/medical/medbay/central)
"owQ" = (
/obj/effect/decal/cleanable/dirt,
-/obj/structure/chair/stool/directional/east,
-/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/obj/machinery/power/apc/auto_name/directional/west,
+/obj/structure/cable,
+/obj/effect/turf_decal/delivery,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"owR" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/turf_decal/tile/neutral{
@@ -43782,9 +43859,29 @@
/turf/open/floor/iron/dark/smooth_large,
/area/station/security/execution/education)
"pBV" = (
-/obj/structure/filingcabinet/filingcabinet,
+/obj/effect/mapping_helpers/broken_floor,
+/obj/structure/rack,
+/obj/item/clothing/ears/earmuffs{
+ pixel_x = -3;
+ pixel_y = -2
+ },
+/obj/item/clothing/ears/earmuffs{
+ pixel_x = -8;
+ pixel_y = 11
+ },
+/obj/item/clothing/ears/earmuffs{
+ pixel_x = 4;
+ pixel_y = 6
+ },
+/obj/item/pickaxe,
+/obj/effect/turf_decal/stripes/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/white/corner{
+ dir = 8
+ },
/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"pCa" = (
/obj/structure/disposalpipe/segment{
dir = 6
@@ -45239,6 +45336,11 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark/herringbone,
/area/station/service/abandoned_gambling_den/gaming)
+"pYR" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
+/turf/open/floor/wood,
+/area/station/cargo/miningfoundry)
"pYY" = (
/obj/structure/disposalpipe/segment{
dir = 9
@@ -45322,6 +45424,9 @@
/turf/open/floor/iron/dark,
/area/station/science/server)
"qbg" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron/smooth,
/area/station/cargo/warehouse)
"qbj" = (
@@ -45357,10 +45462,14 @@
/area/station/service/hydroponics/garden/monastery)
"qbu" = (
/obj/effect/decal/cleanable/dirt,
-/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/chair/stool/directional/east,
+/obj/structure/cable,
+/obj/structure/railing/corner/end{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"qbw" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
@@ -45440,12 +45549,10 @@
/area/station/hallway/secondary/entry)
"qcN" = (
/obj/effect/decal/cleanable/dirt,
-/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/table/greyscale,
-/obj/item/folder/red,
-/obj/item/toy/figure/detective,
+/obj/structure/railing,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"qcQ" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -45457,15 +45564,15 @@
"qcU" = (
/obj/structure/disposalpipe/segment,
/obj/effect/decal/cleanable/dirt,
-/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/table/greyscale,
-/obj/item/folder/white,
-/obj/item/storage/dice{
- pixel_x = -16;
- pixel_y = -6
+/obj/structure/railing{
+ dir = 6
+ },
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/item/kirbyplants/organic/applebush{
+ pixel_y = 5
},
/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"qcX" = (
/obj/structure/flora/bush/flowers_yw/style_random,
/obj/structure/window/reinforced/spawner/directional/east,
@@ -46971,10 +47078,9 @@
/turf/open/floor/plating,
/area/station/maintenance/port/greater)
"qBb" = (
-/obj/item/kirbyplants/organic/applebush,
/obj/machinery/light_switch/directional/north,
-/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"qBc" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -47856,11 +47962,14 @@
/area/station/medical/chemistry)
"qQt" = (
/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/table/greyscale,
-/obj/item/folder/blue,
/obj/structure/sign/poster/random/directional/south,
-/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/obj/machinery/bouldertech/refinery/smelter,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"qQv" = (
/turf/open/floor/iron,
/area/station/security/prison/rec)
@@ -49156,7 +49265,7 @@
"rjP" = (
/obj/structure/disposalpipe/segment,
/turf/closed/wall,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningfoundry)
"rkb" = (
/obj/effect/turf_decal/siding/wood{
dir = 4
@@ -49922,6 +50031,11 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron,
/area/station/engineering/storage/tech)
+"rxe" = (
+/obj/structure/railing/corner/end/flip,
+/obj/effect/mapping_helpers/broken_floor,
+/turf/open/floor/plating,
+/area/station/cargo/miningfoundry)
"rxo" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -54558,6 +54672,8 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/machinery/firealarm/directional/east,
+/obj/effect/turf_decal/stripes/corner,
+/obj/effect/turf_decal/stripes/white/corner,
/turf/open/floor/iron/smooth,
/area/station/cargo/warehouse)
"sTR" = (
@@ -57218,6 +57334,9 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron,
/area/station/hallway/secondary/recreation)
+"tOr" = (
+/turf/closed/wall/rust,
+/area/station/cargo/miningfoundry)
"tOs" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -57943,10 +58062,14 @@
/turf/open/floor/grass,
/area/station/service/hydroponics/garden/monastery)
"uav" = (
-/obj/structure/chair/stool/directional/west,
/obj/structure/sign/poster/random/directional/south,
-/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/obj/machinery/conveyor{
+ id = "mining";
+ dir = 10
+ },
+/obj/machinery/bouldertech/refinery,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"uax" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -71732,11 +71855,12 @@
/turf/open/floor/plating,
/area/station/maintenance/central/greater)
"ydA" = (
-/obj/effect/mapping_helpers/broken_floor,
-/obj/structure/chair/stool/directional/west,
/obj/structure/sign/poster/random/directional/east,
-/turf/open/floor/wood,
-/area/station/maintenance/port/fore)
+/obj/machinery/conveyor{
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"ydH" = (
/obj/effect/turf_decal/box/corners,
/obj/effect/turf_decal/box/corners{
@@ -86107,7 +86231,7 @@ oPi
xOm
pAU
qbg
-rif
+lNs
rie
ipd
rTA
@@ -86618,10 +86742,10 @@ slY
slY
lbW
dRD
-slY
-slY
-slY
-ueX
+hZI
+hZI
+hvY
+tOr
ibe
ipP
rST
@@ -86874,13 +86998,13 @@ blb
dDB
slY
ohb
-slY
-ueX
+hZI
+tOr
pBV
mDC
-slY
-slY
-slY
+hZI
+hZI
+mTl
rST
sgL
swO
@@ -87131,12 +87255,12 @@ blb
dDB
ueX
xpl
-slY
+hZI
hlA
-qbu
+pYR
qbu
owQ
-slY
+hZI
rFa
rTD
iWb
@@ -87388,12 +87512,12 @@ blb
dDB
slY
mFA
-slY
+hZI
iKV
jkw
qcN
qQt
-slY
+hZI
rFP
rTU
sgR
@@ -87646,7 +87770,7 @@ dDB
slY
xpl
iNL
-kPW
+rxe
jlb
qcU
gDR
@@ -87902,12 +88026,12 @@ mEB
ueX
slY
ohl
-slY
+hZI
qBb
kkl
ydA
uav
-slY
+hZI
rGq
rUt
sgR
@@ -88159,12 +88283,12 @@ hNo
wZF
wZF
had
-slY
-slY
-xZh
-slY
-ueX
-slY
+hZI
+hZI
+imD
+hZI
+tOr
+hZI
xng
pjL
llN
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 7316beb24d5..477daa3b89c 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -11879,8 +11879,14 @@
"cRR" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/structure/table,
-/obj/item/storage/medkit/regular,
/obj/machinery/light/directional/west,
+/obj/item/stack/conveyor/thirty,
+/obj/item/boulder_beacon{
+ pixel_x = -5
+ },
+/obj/item/conveyor_switch_construct{
+ pixel_x = 10
+ },
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"cRT" = (
@@ -26173,9 +26179,14 @@
/area/station/service/abandoned_gambling_den)
"gty" = (
/obj/structure/table/reinforced,
-/obj/item/folder/yellow,
-/obj/item/gps/mining,
+/obj/item/gps/mining{
+ pixel_x = -8
+ },
/obj/effect/turf_decal/tile/brown/anticorner/contrasted,
+/obj/item/storage/medkit/regular{
+ pixel_x = 6;
+ pixel_y = 10
+ },
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"gtG" = (
@@ -67583,7 +67594,14 @@
dir = 4
},
/obj/structure/table/reinforced,
-/obj/item/flashlight/lamp,
+/obj/item/flashlight/lamp{
+ pixel_x = -7;
+ pixel_y = 9
+ },
+/obj/item/folder/yellow{
+ pixel_y = -5;
+ pixel_x = 5
+ },
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"qQE" = (
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index fd33ab1c9ac..442627f9674 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -235,6 +235,7 @@
/obj/effect/turf_decal/delivery,
/obj/machinery/firealarm/directional/north,
/obj/structure/cable,
+/obj/structure/railing/corner/end/flip,
/turf/open/floor/iron,
/area/mine/production)
"afp" = (
@@ -1799,6 +1800,13 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
/turf/open/floor/plating,
/area/station/maintenance/aft/lesser)
+"aDg" = (
+/obj/structure/ore_vent/starter_resources{
+ icon_state = "ore_vent_ice_active";
+ icon_state_tapped = "ore_vent_ice_active"
+ },
+/turf/open/misc/asteroid/snow/icemoon,
+/area/icemoon/underground/explored)
"aDo" = (
/obj/structure/chair/office{
dir = 4
@@ -13547,10 +13555,6 @@
/turf/open/floor/carpet/red,
/area/station/security/prison/work)
"ear" = (
-/obj/machinery/mineral/processing_unit{
- dir = 1
- },
-/obj/structure/window/reinforced/spawner/directional/west,
/obj/effect/turf_decal/stripes/line{
dir = 8
},
@@ -13558,6 +13562,10 @@
dir = 4
},
/obj/machinery/light/small/directional/east,
+/obj/machinery/conveyor{
+ id = "mining_internal"
+ },
+/obj/machinery/bouldertech/refinery,
/turf/open/floor/iron,
/area/mine/production)
"eaw" = (
@@ -18517,6 +18525,7 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
dir = 1
},
+/obj/structure/railing,
/turf/open/floor/iron,
/area/mine/production)
"fFJ" = (
@@ -19711,6 +19720,13 @@
/obj/structure/curtain/cloth,
/turf/open/floor/iron/showroomfloor,
/area/station/security/prison/toilet)
+"fZP" = (
+/obj/item/pickaxe{
+ pixel_x = 12;
+ desc = "Someone left their pickaxe out here, must not have known about the boulder processing machines inside."
+ },
+/turf/open/misc/asteroid/snow/icemoon,
+/area/icemoon/underground/explored)
"fZT" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 4
@@ -19873,7 +19889,6 @@
/obj/machinery/conveyor{
id = "mining_internal"
},
-/obj/structure/window/reinforced/spawner/directional/west,
/obj/effect/turf_decal/stripes/line{
dir = 8
},
@@ -21281,6 +21296,7 @@
/turf/open/floor/iron/dark/smooth_large,
/area/station/medical/virology)
"gzv" = (
+/obj/structure/chair/stool/directional/south,
/turf/open/floor/iron,
/area/mine/production)
"gzw" = (
@@ -25896,6 +25912,17 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/station/medical/morgue)
+"hXe" = (
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining_internal"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/iron,
+/area/mine/production)
"hXC" = (
/obj/structure/chair{
dir = 8
@@ -27652,11 +27679,11 @@
dir = 8;
id = "mining_internal"
},
-/obj/structure/window/reinforced/spawner/directional/north,
/obj/effect/turf_decal/stripes/line{
dir = 1
},
/obj/effect/turf_decal/stripes/line,
+/obj/machinery/bouldertech/refinery/smelter,
/turf/open/floor/iron,
/area/mine/production)
"izw" = (
@@ -28988,6 +29015,7 @@
},
/obj/machinery/power/apc/auto_name/directional/north,
/obj/structure/cable,
+/obj/machinery/bouldertech/brm,
/turf/open/floor/iron,
/area/mine/production)
"iUm" = (
@@ -31549,6 +31577,9 @@
/area/station/commons/storage/mining)
"jLb" = (
/obj/effect/decal/cleanable/dirt,
+/obj/structure/railing/corner/end{
+ dir = 4
+ },
/turf/open/floor/iron,
/area/mine/production)
"jLf" = (
@@ -39688,7 +39719,6 @@
dir = 8;
id = "mining_internal"
},
-/obj/structure/window/reinforced/spawner/directional/north,
/obj/effect/turf_decal/stripes/line{
dir = 1
},
@@ -47008,6 +47038,7 @@
"oqy" = (
/obj/machinery/airalarm/directional/south,
/obj/effect/turf_decal/delivery,
+/obj/effect/decal/cleanable/rubble,
/turf/open/floor/iron,
/area/mine/production)
"oqz" = (
@@ -49379,14 +49410,15 @@
/turf/closed/wall,
/area/station/ai_monitored/turret_protected/aisat/maint)
"pbv" = (
-/obj/structure/window/reinforced/spawner/directional/north,
/obj/machinery/conveyor_switch/oneway{
id = "mining_internal";
name = "mining conveyor";
- pixel_x = 12;
- pixel_y = -6
+ pixel_x = 1;
+ pixel_y = 8
+ },
+/obj/structure/railing{
+ dir = 4
},
-/obj/structure/chair/stool/directional/south,
/turf/open/floor/iron,
/area/mine/production)
"pby" = (
@@ -63076,6 +63108,10 @@
},
/turf/open/floor/iron/dark/textured,
/area/station/hallway/secondary/entry)
+"tkM" = (
+/obj/structure/railing,
+/turf/open/floor/iron,
+/area/mine/production)
"tkP" = (
/obj/effect/turf_decal/stripes/line{
dir = 5
@@ -71018,7 +71054,6 @@
/area/icemoon/underground/explored)
"vNT" = (
/obj/effect/turf_decal/bot,
-/obj/structure/closet/crate/preopen,
/obj/machinery/light/small/directional/north,
/obj/structure/extinguisher_cabinet/directional/north,
/turf/open/floor/iron,
@@ -77783,8 +77818,9 @@
/turf/open/floor/plating,
/area/station/maintenance/port/aft)
"xOM" = (
-/obj/structure/table,
-/obj/machinery/mineral/processing_unit_console,
+/obj/structure/railing{
+ dir = 6
+ },
/turf/open/floor/iron,
/area/mine/production)
"xPu" = (
@@ -164133,7 +164169,7 @@ tDa
sWB
tDa
pql
-gzv
+tkM
izq
uvM
gjq
@@ -164391,7 +164427,7 @@ kZu
afl
pbv
xOM
-izq
+hXe
nWH
hFL
hFL
@@ -168489,7 +168525,7 @@ iDt
rcY
scw
iDt
-iDt
+fZP
scw
scw
scw
@@ -168746,7 +168782,7 @@ iDt
rcY
iDt
scw
-iDt
+aDg
iDt
scw
uWE
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 27f23bc7776..d4a074f05d8 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -873,6 +873,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/disposalpipe/segment,
+/obj/effect/landmark/start/shaft_miner,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"aqG" = (
@@ -4965,6 +4966,12 @@
},
/turf/open/floor/iron,
/area/station/hallway/secondary/service)
+"bMp" = (
+/obj/effect/mapping_helpers/broken_floor,
+/obj/item/food/fortunecookie,
+/obj/structure/safe/floor,
+/turf/open/floor/plating,
+/area/station/maintenance/port/fore)
"bMA" = (
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -5383,6 +5390,8 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
+/obj/effect/spawner/random/entertainment/dice,
+/obj/item/storage/toolbox/emergency,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"bUo" = (
@@ -9923,6 +9932,14 @@
/obj/machinery/light/small/directional/north,
/turf/open/floor/iron/white,
/area/station/science/xenobiology)
+"dJn" = (
+/obj/effect/turf_decal/tile/brown/half/contrasted{
+ dir = 4
+ },
+/obj/structure/closet/emcloset,
+/obj/machinery/firealarm/directional/east,
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"dJo" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -13940,6 +13957,16 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/green/visible,
/turf/closed/wall/r_wall,
/area/station/engineering/supermatter)
+"fed" = (
+/obj/structure/railing{
+ dir = 6
+ },
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/turf_decal/stripes/corner{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"fee" = (
/obj/structure/lattice/catwalk,
/obj/structure/disposalpipe/trunk{
@@ -13951,6 +13978,12 @@
/obj/structure/grille/broken,
/turf/open/space/basic,
/area/space/nearstation)
+"feC" = (
+/obj/structure/cable,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/turf_decal/stripes/line,
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"feF" = (
/obj/structure/extinguisher_cabinet/directional/north,
/obj/structure/cable,
@@ -14646,6 +14679,11 @@
},
/turf/open/floor/iron/white/smooth_large,
/area/station/medical/medbay/central)
+"fow" = (
+/obj/effect/spawner/random/maintenance,
+/obj/machinery/recharge_station,
+/turf/open/floor/plating,
+/area/station/maintenance/port/fore)
"foB" = (
/obj/structure/closet/secure_closet/hydroponics,
/obj/effect/turf_decal/stripes/line{
@@ -22668,6 +22706,13 @@
},
/turf/open/floor/iron/white,
/area/station/medical/pharmacy)
+"inW" = (
+/obj/structure/extinguisher_cabinet/directional/east,
+/obj/machinery/conveyor{
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"inX" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/door/poddoor/shutters/preopen{
@@ -24333,6 +24378,13 @@
},
/turf/open/floor/iron,
/area/station/commons/locker)
+"iPw" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/mapping_helpers/broken_floor,
+/turf/open/floor/plating,
+/area/station/maintenance/port/fore)
"iPx" = (
/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible,
/turf/open/floor/iron,
@@ -25018,6 +25070,17 @@
/obj/structure/window/spawner/directional/west,
/turf/open/floor/iron/dark,
/area/station/medical/storage)
+"iZt" = (
+/obj/effect/turf_decal/tile/brown/half/contrasted{
+ dir = 1
+ },
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/obj/machinery/light/small/directional/south,
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"iZF" = (
/obj/structure/cable,
/obj/effect/turf_decal/trimline/blue/filled/line{
@@ -25894,19 +25957,6 @@
/obj/effect/turf_decal/tile/brown/half/contrasted,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
-"jpI" = (
-/obj/structure/table,
-/obj/effect/spawner/random/entertainment/deck,
-/obj/effect/spawner/random/entertainment/cigarette_pack{
- pixel_x = -6;
- pixel_y = 8
- },
-/obj/effect/turf_decal/tile/brown/anticorner/contrasted{
- dir = 1
- },
-/obj/machinery/light/directional/east,
-/turf/open/floor/iron,
-/area/station/cargo/miningoffice)
"jpO" = (
/obj/machinery/door/airlock/external,
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
@@ -26833,11 +26883,6 @@
},
/turf/open/floor/iron,
/area/station/hallway/primary/port)
-"jFk" = (
-/obj/effect/spawner/random/maintenance,
-/obj/effect/mapping_helpers/broken_floor,
-/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
"jFr" = (
/obj/structure/sign/poster/party_game,
/turf/closed/wall,
@@ -27568,14 +27613,11 @@
/turf/open/floor/plating,
/area/station/maintenance/starboard/fore)
"jRC" = (
-/obj/machinery/door/airlock/maintenance{
- name = "Mining Dock Maintenance"
- },
/obj/structure/cable,
-/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den,
-/obj/effect/mapping_helpers/airlock/access/any/supply/mining,
-/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/obj/structure/railing/corner/end/flip,
+/obj/effect/turf_decal/stripes/corner,
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"jRD" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/effect/turf_decal/tile/neutral/half/contrasted{
@@ -31319,6 +31361,7 @@
/obj/effect/spawner/random/structure/closet_maintenance,
/obj/effect/spawner/random/maintenance,
/obj/effect/spawner/random/maintenance,
+/obj/effect/spawner/random/maintenance,
/turf/open/floor/plating,
/area/station/maintenance/port/fore)
"llk" = (
@@ -32413,9 +32456,10 @@
/turf/open/floor/wood,
/area/station/command/heads_quarters/hop)
"lJo" = (
-/obj/structure/closet/emcloset,
-/obj/machinery/firealarm/directional/east,
/obj/effect/turf_decal/tile/brown/half/contrasted,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/machinery/light/directional/north,
+/obj/effect/landmark/start/shaft_miner,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"lJr" = (
@@ -33545,11 +33589,27 @@
},
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
-"mdW" = (
-/obj/structure/safe/floor,
-/obj/item/food/fortunecookie,
+"mdM" = (
+/obj/structure/cable,
+/obj/effect/mapping_helpers/airlock/access/any/supply/bit_den,
+/obj/machinery/door/airlock/maintenance{
+ name = "Mining Dock Maintenance"
+ },
+/obj/effect/mapping_helpers/airlock/access/any/supply/mining,
/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/area/station/cargo/miningoffice)
+"mdW" = (
+/obj/machinery/airalarm/directional/east,
+/obj/effect/turf_decal/tile/brown/half/contrasted{
+ dir = 1
+ },
+/obj/machinery/conveyor{
+ dir = 10;
+ id = "mining"
+ },
+/obj/machinery/bouldertech/refinery,
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"mei" = (
/obj/machinery/atmospherics/pipe/smart/simple/cyan/visible,
/turf/open/floor/iron,
@@ -35162,13 +35222,15 @@
/turf/open/floor/iron/white,
/area/station/medical/virology)
"mFw" = (
-/obj/structure/table,
/obj/effect/turf_decal/tile/brown/anticorner/contrasted{
dir = 1
},
-/obj/item/storage/box/bandages{
- pixel_x = 4;
- pixel_y = 6
+/obj/machinery/conveyor{
+ dir = 9;
+ id = "mining"
+ },
+/obj/structure/railing{
+ dir = 8
},
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
@@ -37375,12 +37437,12 @@
/turf/open/floor/plating,
/area/station/maintenance/port/greater)
"nsM" = (
-/obj/machinery/recharge_station,
-/obj/effect/turf_decal/stripes/end{
- dir = 4
+/obj/machinery/conveyor{
+ id = "mining"
},
-/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/obj/machinery/bouldertech/brm,
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"nsO" = (
/obj/machinery/computer/records/security,
/obj/effect/turf_decal/tile/red/half/contrasted{
@@ -42177,6 +42239,15 @@
/obj/effect/mapping_helpers/airlock/access/any/service/maintenance,
/turf/open/floor/plating,
/area/station/maintenance/aft/greater)
+"pgF" = (
+/obj/structure/railing/corner/end,
+/obj/effect/turf_decal/delivery,
+/obj/effect/decal/cleanable/rubble,
+/obj/structure/railing/corner/end{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"pgJ" = (
/obj/structure/chair/stool/directional/north,
/obj/machinery/camera/directional/west{
@@ -46025,12 +46096,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/hallway/secondary/entry)
-"qAS" = (
-/obj/effect/turf_decal/tile/brown{
- dir = 4
- },
-/turf/open/floor/iron,
-/area/station/cargo/miningoffice)
"qAX" = (
/obj/effect/turf_decal/trimline/red/filled/line{
dir = 4
@@ -48327,7 +48392,6 @@
/turf/open/floor/iron,
/area/station/science/explab)
"ror" = (
-/obj/effect/spawner/random/structure/crate,
/obj/structure/disposalpipe/segment{
dir = 5
},
@@ -50760,12 +50824,14 @@
/turf/open/floor/iron/white,
/area/station/medical/cryo)
"sfG" = (
-/obj/structure/table,
-/obj/item/storage/toolbox/emergency,
-/obj/machinery/airalarm/directional/east,
-/obj/effect/turf_decal/tile/brown{
+/obj/effect/turf_decal/tile/brown/half/contrasted{
dir = 1
},
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/obj/machinery/bouldertech/refinery/smelter,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"sfK" = (
@@ -51324,6 +51390,15 @@
/obj/effect/turf_decal/tile/yellow/anticorner/contrasted,
/turf/open/floor/iron,
/area/station/engineering/break_room)
+"ssn" = (
+/obj/structure/railing{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"ssr" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/security{
@@ -53799,6 +53874,12 @@
/obj/effect/spawner/random/food_or_drink/seed,
/turf/open/floor/plating,
/area/station/maintenance/starboard/aft)
+"tjg" = (
+/obj/effect/spawner/random/structure/closet_maintenance,
+/obj/item/hand_labeler_refill,
+/obj/effect/spawner/random/maintenance,
+/turf/open/floor/plating,
+/area/station/maintenance/port/fore)
"tjh" = (
/turf/closed/wall,
/area/station/security/brig)
@@ -57312,6 +57393,11 @@
dir = 8
},
/area/station/service/chapel)
+"uul" = (
+/obj/structure/cable,
+/obj/effect/spawner/random/structure/crate,
+/turf/open/floor/plating,
+/area/station/maintenance/port/fore)
"uur" = (
/obj/effect/spawner/random/maintenance,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -57472,12 +57558,7 @@
/turf/open/floor/plating,
/area/station/maintenance/fore)
"uxd" = (
-/obj/structure/table,
-/obj/structure/extinguisher_cabinet/directional/east,
-/obj/effect/spawner/random/entertainment/dice,
-/obj/effect/turf_decal/tile/brown/half/contrasted{
- dir = 8
- },
+/obj/structure/railing,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
"uxf" = (
@@ -62791,11 +62872,6 @@
},
/turf/open/floor/iron/dark,
/area/station/command/heads_quarters/rd)
-"wjH" = (
-/obj/effect/spawner/random/maintenance,
-/obj/structure/rack,
-/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
"wjK" = (
/obj/item/clothing/head/hats/tophat,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -65239,6 +65315,14 @@
/obj/effect/mapping_helpers/broken_floor,
/turf/open/floor/plating,
/area/station/maintenance/port)
+"xfe" = (
+/obj/effect/turf_decal/tile/brown/half/contrasted,
+/obj/machinery/conveyor_switch/oneway{
+ id = "mining";
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"xff" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -65566,11 +65650,19 @@
/turf/open/floor/wood/parquet,
/area/station/medical/psychology)
"xkb" = (
-/obj/item/hand_labeler_refill,
-/obj/structure/rack,
-/obj/machinery/light/small/dim/directional/west,
-/turf/open/floor/plating,
-/area/station/maintenance/port/fore)
+/obj/effect/turf_decal/tile/brown/half/contrasted,
+/obj/effect/spawner/random/entertainment/deck,
+/obj/structure/table,
+/obj/effect/spawner/random/entertainment/cigarette_pack{
+ pixel_x = -6;
+ pixel_y = 8
+ },
+/obj/item/storage/box/bandages{
+ pixel_y = 6;
+ pixel_x = 4
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningoffice)
"xko" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
@@ -66297,6 +66389,7 @@
"xxp" = (
/obj/machinery/airalarm/directional/west,
/obj/effect/mapping_helpers/burnt_floor,
+/obj/machinery/power/port_gen/pacman/pre_loaded,
/turf/open/floor/plating,
/area/station/maintenance/port/fore)
"xxF" = (
@@ -67042,11 +67135,6 @@
},
/turf/open/floor/iron/white,
/area/station/science/ordnance/testlab)
-"xJV" = (
-/obj/effect/landmark/start/shaft_miner,
-/obj/structure/cable,
-/turf/open/floor/iron,
-/area/station/cargo/miningoffice)
"xKk" = (
/obj/machinery/photocopier,
/turf/open/floor/iron/white,
@@ -86630,12 +86718,12 @@ tiK
qvl
jXu
beo
-cSP
+dJn
aZj
-qAS
+cSP
cLj
kRe
-aFd
+pgF
mFw
oor
oor
@@ -86888,10 +86976,10 @@ bSm
jXu
jXu
jXu
-jXu
+hKg
lJo
-xJV
-jpI
+cLj
+kRe
uxd
sfG
oor
@@ -87140,17 +87228,17 @@ twr
gQg
xxp
twr
-sxn
+sHu
xkX
ror
twr
fhn
-jXu
-jXu
+hKg
+xfe
jRC
-jXu
-jXu
-jXu
+ssn
+fed
+iZt
jXu
tBU
kOX
@@ -87400,13 +87488,13 @@ fUr
fUr
fUr
aps
-xgB
-jZW
-jXu
+uul
+fow
+hKg
xkb
-xgB
+feC
nsM
-twr
+inW
mdW
jXu
hvo
@@ -87658,13 +87746,13 @@ cVL
jXu
uur
xgB
-jXu
-jXu
-jFk
-xgB
-sHu
-twr
twr
+hKg
+hKg
+mdM
+hKg
+hKg
+hKg
jXu
jmR
xap
@@ -88173,10 +88261,10 @@ jXu
bSm
sHu
bPM
-sxn
-uUu
+sHu
+tjg
jXu
-rNP
+iPw
rNP
mgv
mWE
@@ -88952,7 +89040,7 @@ rlU
rlU
aaf
jXu
-wjH
+sxn
mgv
cUD
cfv
@@ -89710,7 +89798,7 @@ jXu
uUu
dEH
pOi
-bPM
+bMp
jXu
loQ
fsQ
diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm
index e26ac494a0f..ddca03ffee4 100644
--- a/_maps/map_files/Mining/Lavaland.dmm
+++ b/_maps/map_files/Mining/Lavaland.dmm
@@ -166,6 +166,14 @@
/obj/effect/turf_decal/siding/yellow,
/turf/open/floor/carpet/royalblue,
/area/mine/living_quarters)
+"bq" = (
+/obj/structure/railing{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/stripes/white/line,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"bt" = (
/obj/structure/disposalpipe/segment{
dir = 5
@@ -188,6 +196,7 @@
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 9
},
+/obj/structure/ore_box,
/turf/open/floor/iron/dark,
/area/mine/production)
"by" = (
@@ -520,6 +529,12 @@
/obj/structure/lattice/catwalk/mining,
/turf/open/lava/smooth/lava_land_surface,
/area/lavaland/surface/outdoors)
+"dp" = (
+/obj/structure/ore_vent/starter_resources{
+ icon_state = "ore_vent_active"
+ },
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"dq" = (
/obj/structure/stone_tile{
dir = 4
@@ -609,6 +624,14 @@
},
/turf/open/floor/iron/dark/smooth_edge,
/area/mine/production)
+"dW" = (
+/obj/structure/lattice/catwalk/mining,
+/obj/structure/railing,
+/obj/structure/railing{
+ dir = 1
+ },
+/turf/open/lava/smooth/lava_land_surface,
+/area/lavaland/surface/outdoors)
"ee" = (
/obj/machinery/shower/directional/south,
/obj/machinery/door/window/right/directional/south,
@@ -870,6 +893,7 @@
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 5
},
+/obj/structure/closet/crate/bin,
/turf/open/floor/iron/dark,
/area/mine/production)
"fU" = (
@@ -1693,12 +1717,23 @@
/turf/open/floor/plating,
/area/mine/maintenance/living/north)
"kx" = (
-/obj/machinery/computer/order_console/mining,
/obj/effect/turf_decal/trimline/brown/filled/line,
+/obj/structure/table,
+/obj/item/paper/fluff/stations/lavaland/orm_notice,
/turf/open/floor/iron/dark/smooth_edge{
dir = 1
},
/area/mine/production)
+"ky" = (
+/obj/structure/railing{
+ dir = 6
+ },
+/obj/effect/turf_decal/stripes/corner{
+ dir = 1
+ },
+/obj/machinery/light/directional/south,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"kB" = (
/obj/structure/stone_tile/surrounding_tile,
/obj/structure/stone_tile/surrounding_tile{
@@ -2064,6 +2099,18 @@
},
/turf/open/lava/smooth/lava_land_surface,
/area/lavaland/surface/outdoors)
+"lT" = (
+/obj/structure/railing{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/stripes/white/line{
+ dir = 4
+ },
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"lV" = (
/obj/structure/cable,
/obj/effect/turf_decal/trimline/red/filled/line{
@@ -2129,6 +2176,19 @@
/obj/structure/cable,
/turf/open/floor/iron/dark/textured_large,
/area/mine/hydroponics)
+"mh" = (
+/obj/structure/railing/corner{
+ dir = 4
+ },
+/obj/structure/railing/corner,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/stripes/white/line{
+ dir = 8
+ },
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"mj" = (
/obj/structure/stone_tile/block,
/obj/structure/stone_tile/block{
@@ -2485,13 +2545,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/mine/laborcamp)
-"nt" = (
-/obj/structure/table,
-/obj/effect/turf_decal/trimline/brown/filled/line{
- dir = 6
- },
-/turf/open/floor/iron/dark,
-/area/mine/production)
"nv" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
dir = 8
@@ -3481,11 +3534,10 @@
/turf/open/floor/plating,
/area/mine/storage)
"tO" = (
-/obj/structure/table,
-/obj/item/paper/fluff/stations/lavaland/orm_notice,
/obj/machinery/power/apc/auto_name/directional/south,
/obj/structure/cable,
/obj/effect/turf_decal/trimline/brown/filled/line,
+/obj/structure/table,
/turf/open/floor/iron/dark/smooth_edge{
dir = 1
},
@@ -4258,6 +4310,15 @@
},
/turf/open/floor/iron/checker,
/area/mine/cafeteria)
+"yQ" = (
+/obj/structure/railing{
+ dir = 5
+ },
+/obj/effect/turf_decal/stripes/corner{
+ dir = 8
+ },
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"yR" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -4437,10 +4498,10 @@
/area/lavaland/surface/outdoors)
"Ac" = (
/obj/effect/turf_decal/bot,
-/obj/structure/ore_box,
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 10
},
+/obj/machinery/computer/order_console/mining,
/turf/open/floor/iron/dark,
/area/mine/production)
"Ae" = (
@@ -4557,6 +4618,13 @@
"AX" = (
/turf/open/floor/plating,
/area/mine/laborcamp/security/maintenance)
+"AY" = (
+/obj/structure/lattice/catwalk/mining,
+/obj/structure/railing{
+ dir = 9
+ },
+/turf/open/lava/smooth/lava_land_surface,
+/area/lavaland/surface/outdoors)
"Bb" = (
/obj/machinery/camera/autoname/directional/east{
network = list("mine")
@@ -4944,6 +5012,16 @@
/obj/effect/turf_decal/sand/plating/volcanic,
/turf/open/floor/plating/lavaland_atmos,
/area/mine/maintenance/service/disposals)
+"Ep" = (
+/obj/structure/lattice/catwalk/mining,
+/obj/structure/railing/corner{
+ dir = 8
+ },
+/obj/structure/railing/corner{
+ dir = 1
+ },
+/turf/open/lava/smooth/lava_land_surface,
+/area/lavaland/surface/outdoors)
"Eq" = (
/obj/machinery/door/airlock/security/glass{
name = "Labor Camp Monitoring"
@@ -5288,6 +5366,13 @@
},
/turf/open/misc/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
+"GV" = (
+/obj/structure/lattice/catwalk/mining,
+/obj/structure/railing{
+ dir = 8
+ },
+/turf/open/lava/smooth/lava_land_surface,
+/area/lavaland/surface/outdoors)
"GW" = (
/obj/structure/chair/office{
dir = 1
@@ -5798,6 +5883,13 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plating,
/area/mine/laborcamp/security/maintenance)
+"JO" = (
+/obj/structure/lattice/catwalk/mining,
+/obj/structure/railing{
+ dir = 10
+ },
+/turf/open/lava/smooth/lava_land_surface,
+/area/lavaland/surface/outdoors)
"JP" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -6871,6 +6963,16 @@
},
/turf/open/floor/iron/dark,
/area/mine/mechbay)
+"Qm" = (
+/obj/structure/railing,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/turf_decal/stripes/white/line{
+ dir = 1
+ },
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface/outdoors)
"Qw" = (
/obj/structure/stone_tile/cracked,
/obj/structure/stone_tile{
@@ -7083,6 +7185,7 @@
dir = 1
},
/obj/structure/barricade/wooden/crude,
+/obj/structure/barricade/wooden,
/turf/open/floor/iron/dark,
/area/mine/production)
"RV" = (
@@ -7565,6 +7668,7 @@
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 1
},
+/obj/structure/ore_box,
/turf/open/floor/iron/dark/smooth_edge,
/area/mine/production)
"UZ" = (
@@ -21444,7 +21548,7 @@ uU
uU
uU
uU
-uU
+pU
uU
uU
uU
@@ -21700,8 +21804,8 @@ uU
uU
uU
uU
-uU
-uU
+pU
+pU
pU
uU
uU
@@ -21955,7 +22059,7 @@ uU
uU
uU
uU
-pU
+uU
pU
pU
pU
@@ -45841,9 +45945,9 @@ pU
aj
aj
aj
-aj
-aj
-aj
+AY
+lT
+JO
aj
oA
Lu
@@ -46098,9 +46202,9 @@ aj
aj
aj
aj
-aj
-aj
-aj
+bq
+dp
+Qm
aj
oA
Lz
@@ -46355,9 +46459,9 @@ pU
pU
aj
aj
-aj
-aj
-aj
+yQ
+mh
+ky
NU
NU
NU
@@ -46613,7 +46717,7 @@ pU
pU
aj
aj
-aj
+dW
aj
Le
Lh
@@ -46869,8 +46973,8 @@ pU
pU
AQ
ZM
-ZM
-ZM
+GV
+Ep
ZM
Ki
Uq
@@ -48422,7 +48526,7 @@ RY
RY
dQ
Cg
-nt
+lb
pK
Ob
IL
diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm
index ca051a5a4d7..97a6e439720 100644
--- a/_maps/map_files/NorthStar/north_star.dmm
+++ b/_maps/map_files/NorthStar/north_star.dmm
@@ -1437,9 +1437,6 @@
/area/station/hallway/secondary/exit)
"asu" = (
/obj/machinery/camera/autoname/directional/north,
-/obj/structure/sign/warning/vacuum{
- pixel_y = 32
- },
/turf/open/floor/iron/dark/side{
dir = 1
},
@@ -5334,6 +5331,13 @@
/obj/structure/flora/bush/sparsegrass/style_random,
/turf/open/floor/grass,
/area/station/service/library/garden)
+"bpo" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/chair{
+ dir = 8
+ },
+/turf/open/floor/catwalk_floor/iron,
+/area/station/cargo/miningdock)
"bpq" = (
/obj/machinery/vending/robotics,
/turf/open/floor/iron/dark,
@@ -6594,12 +6598,12 @@
/turf/open/floor/iron/dark/side,
/area/station/command/bridge)
"bEp" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/structure/railing/corner/end/flip{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/structure/table,
-/obj/item/storage/box/donkpockets,
-/obj/machinery/light/directional/east,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"bED" = (
@@ -6787,6 +6791,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/pod/light,
/area/station/maintenance/solars/port/aft)
+"bIq" = (
+/obj/structure/cable,
+/obj/machinery/conveyor/inverted{
+ dir = 10
+ },
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"bIx" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -11254,16 +11265,11 @@
/turf/open/floor/iron/dark,
/area/station/command/bridge)
"cRk" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
-/obj/structure/chair{
- dir = 8
- },
-/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
- dir = 1
- },
/obj/structure/cable,
+/obj/machinery/conveyor{
+ dir = 5;
+ id = "mining"
+ },
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"cRs" = (
@@ -13182,19 +13188,17 @@
/turf/open/floor/iron/dark/telecomms,
/area/station/tcommsat/server)
"dsJ" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 8
+/obj/effect/turf_decal/stripes/line,
+/obj/machinery/camera/autoname/directional/south,
+/obj/item/ammo_casing/spent,
+/obj/structure/railing/corner{
+ dir = 1
},
-/obj/structure/chair/plastic{
- dir = 8
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
},
-/obj/item/toy/plush/lizard_plushie/space/green{
- name = "Warns-The-Fool";
- pixel_x = -3;
- pixel_y = 2
- },
-/turf/open/floor/iron/dark/airless,
-/area/station/hallway/floor1/aft)
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"dtb" = (
/obj/machinery/door/airlock/science/glass{
name = "Break Room"
@@ -17223,6 +17227,12 @@
/obj/structure/window/reinforced/tinted/spawner/directional/north,
/turf/open/floor/iron/dark,
/area/station/hallway/floor2/fore)
+"ewg" = (
+/obj/structure/sign/warning/chem_diamond/directional/north,
+/turf/open/floor/iron/dark/side{
+ dir = 1
+ },
+/area/station/hallway/floor1/aft)
"ewm" = (
/obj/effect/turf_decal/siding/wood/end{
dir = 8
@@ -18699,6 +18709,12 @@
/obj/structure/closet/emcloset,
/turf/open/floor/iron/smooth_large,
/area/station/hallway/secondary/entry)
+"eSm" = (
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"eSn" = (
/obj/structure/disposalpipe/segment{
dir = 9
@@ -19798,6 +19814,12 @@
/obj/machinery/light_switch/directional/north,
/turf/open/floor/iron/dark/side,
/area/station/command/teleporter)
+"fjL" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/item/storage/box/donkpockets,
+/obj/structure/table,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"fjN" = (
/obj/effect/turf_decal/delivery,
/obj/structure/sign/departments/cargo/directional/north,
@@ -20648,12 +20670,13 @@
/turf/open/floor/iron/dark/smooth_large,
/area/station/hallway/floor1/aft)
"fvS" = (
-/obj/effect/turf_decal/stripes/line{
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/cable,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating/airless,
-/area/station/hallway/floor1/aft)
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"fvV" = (
/obj/effect/turf_decal/tile/red/half/contrasted{
dir = 1
@@ -23324,9 +23347,13 @@
/turf/open/floor/pod/light,
/area/station/maintenance/floor1/port/aft)
"gha" = (
-/obj/effect/spawner/structure/window/reinforced,
/obj/structure/cable,
-/turf/open/floor/plating,
+/obj/machinery/bouldertech/brm,
+/obj/machinery/conveyor{
+ dir = 4;
+ id = "mining"
+ },
+/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"ghg" = (
/obj/effect/turf_decal/trimline/yellow/warning{
@@ -24260,6 +24287,7 @@
"gun" = (
/obj/effect/turf_decal/bot,
/obj/effect/decal/cleanable/dirt,
+/obj/effect/spawner/random/structure/crate,
/turf/open/floor/iron/textured_large,
/area/station/cargo/storage)
"gup" = (
@@ -24488,11 +24516,16 @@
/turf/open/floor/iron/dark/side,
/area/station/hallway/floor2/fore)
"gxB" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/structure/cable,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
+ dir = 1
+ },
+/obj/structure/railing/corner/end/flip{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/structure/cable,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"gxH" = (
@@ -25216,11 +25249,12 @@
/turf/open/floor/wood/tile,
/area/station/command/heads_quarters/captain)
"gGP" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
/obj/machinery/computer/security/telescreen/entertainment/directional/north,
/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"gHi" = (
@@ -29045,11 +29079,11 @@
/turf/open/floor/iron/dark,
/area/station/maintenance/floor2/starboard/aft)
"hGT" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/item/radio/intercom/directional/west,
+/obj/structure/railing/corner,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/structure/chair,
-/obj/item/radio/intercom/directional/west,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"hGW" = (
@@ -30332,10 +30366,12 @@
/turf/open/floor/carpet/green,
/area/station/service/abandoned_gambling_den)
"hXO" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/structure/railing/corner/end{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/structure/table,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"hXQ" = (
@@ -31147,6 +31183,14 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/textured_large,
/area/station/cargo/storage)
+"ijO" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/extinguisher_cabinet/directional/south,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"ijQ" = (
/obj/machinery/computer/station_alert,
/turf/open/floor/iron/dark,
@@ -32254,14 +32298,13 @@
/turf/open/floor/iron/textured_large,
/area/station/cargo/storage)
"iyY" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/machinery/airalarm/directional/east,
+/obj/structure/railing/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/structure/table,
-/obj/machinery/microwave{
- pixel_y = 6
- },
-/obj/machinery/airalarm/directional/east,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"iyZ" = (
@@ -39578,13 +39621,11 @@
/turf/open/floor/iron/white,
/area/station/medical/medbay/aft)
"ksD" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
-/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
- dir = 1
- },
/obj/structure/cable,
+/obj/machinery/bouldertech/refinery/smelter,
+/obj/machinery/conveyor/inverted{
+ dir = 10
+ },
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"ksH" = (
@@ -40047,6 +40088,18 @@
/obj/machinery/duct,
/turf/open/floor/iron/dark,
/area/station/security/office)
+"kzk" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/chair/plastic{
+ dir = 8
+ },
+/obj/item/toy/plush/lizard_plushie/space/green{
+ name = "Warns-The-Fool";
+ pixel_x = -3;
+ pixel_y = 2
+ },
+/turf/open/floor/catwalk_floor/iron,
+/area/station/cargo/miningdock)
"kzn" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron/dark,
@@ -43959,6 +44012,17 @@
/obj/effect/spawner/random/structure/closet_maintenance,
/turf/open/floor/pod/light,
/area/station/maintenance/floor3/starboard)
+"lxS" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/cable,
+/obj/structure/railing/corner/end/flip{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"lxU" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -44096,10 +44160,16 @@
/turf/open/floor/iron/dark/side,
/area/station/security/office)
"lAq" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
+ dir = 1
+ },
+/obj/structure/cable,
+/obj/structure/railing/corner/end{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"lAD" = (
@@ -47412,11 +47482,10 @@
/turf/open/floor/engine/hull,
/area/space/nearstation)
"mqn" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
/obj/structure/cable,
-/obj/item/ammo_casing/spent,
+/obj/machinery/conveyor/inverted{
+ dir = 6
+ },
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"mqt" = (
@@ -50469,11 +50538,6 @@
/obj/effect/mapping_helpers/broken_floor,
/turf/open/floor/iron,
/area/station/cargo/storage)
-"ney" = (
-/obj/effect/turf_decal/delivery,
-/obj/effect/spawner/random/structure/crate,
-/turf/open/floor/iron/textured_large,
-/area/station/cargo/storage)
"neB" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/button/door/directional/south{
@@ -51622,13 +51686,6 @@
/obj/machinery/door/firedoor,
/turf/open/floor/iron,
/area/station/cargo/lobby)
-"nsr" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
-/obj/structure/cable,
-/turf/open/floor/iron/checker,
-/area/station/cargo/miningdock)
"nss" = (
/obj/structure/chair/comfy/shuttle,
/obj/effect/turf_decal/trimline/red/filled/line{
@@ -54042,6 +54099,9 @@
/turf/open/floor/pod/light,
/area/station/maintenance/floor4/port/fore)
"nYw" = (
+/obj/machinery/conveyor_switch/oneway{
+ id = "mining"
+ },
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"nYE" = (
@@ -57212,12 +57272,6 @@
},
/turf/open/floor/engine/vacuum,
/area/station/science/ordnance/freezerchamber)
-"oRi" = (
-/obj/effect/turf_decal/bot,
-/obj/effect/spawner/random/structure/crate,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/turf/open/floor/iron/textured_large,
-/area/station/cargo/storage)
"oRq" = (
/obj/machinery/door/window/left/directional/north{
name = "Pen 3";
@@ -58211,12 +58265,10 @@
/turf/open/floor/pod/light,
/area/station/maintenance/floor1/port)
"pfO" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/machinery/newscaster/directional/west,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/machinery/newscaster/directional/west,
-/obj/structure/table,
-/obj/machinery/firealarm/directional/south,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"pfX" = (
@@ -63277,11 +63329,12 @@
/turf/open/floor/iron/white,
/area/station/medical/medbay/aft)
"qyG" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
/obj/effect/decal/cleanable/dirt,
-/obj/structure/extinguisher_cabinet/directional/south,
+/obj/machinery/bouldertech/refinery,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"qyH" = (
@@ -68319,6 +68372,13 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden,
/turf/open/floor/catwalk_floor,
/area/station/maintenance/floor4/starboard/fore)
+"rQC" = (
+/obj/structure/railing/corner/end,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"rQG" = (
/obj/machinery/chem_master{
name = "CytoMaster 3000"
@@ -73867,6 +73927,13 @@
/obj/effect/turf_decal/tile/blue/fourcorners,
/turf/open/floor/iron/white/textured,
/area/station/medical/storage)
+"tpl" = (
+/obj/machinery/conveyor{
+ dir = 4;
+ id = "mining"
+ },
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"tpy" = (
/obj/machinery/holopad,
/obj/effect/turf_decal/tile/red{
@@ -73959,6 +74026,7 @@
/area/station/maintenance/floor1/port)
"tqo" = (
/obj/effect/spawner/structure/window/reinforced,
+/obj/structure/cable,
/turf/open/floor/plating,
/area/station/hallway/floor1/aft)
"tqr" = (
@@ -77135,6 +77203,13 @@
/obj/machinery/portable_atmospherics/canister/nitrogen,
/turf/open/floor/iron/telecomms,
/area/station/tcommsat/server)
+"uiU" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/chair{
+ dir = 8
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"uiY" = (
/obj/structure/window/reinforced/spawner/directional/north,
/obj/effect/turf_decal/trimline/white/filled/line{
@@ -81179,12 +81254,10 @@
/turf/closed/wall,
/area/station/engineering/atmos/hfr_room)
"vmu" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
- dir = 1
- },
/obj/structure/cable,
-/obj/structure/chair{
- dir = 8
+/obj/machinery/conveyor{
+ dir = 9;
+ id = "mining"
},
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
@@ -82904,6 +82977,10 @@
"vIe" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/sign/poster/contraband/random/directional/east,
+/obj/machinery/microwave{
+ pixel_y = 6
+ },
+/obj/structure/table,
/turf/open/floor/catwalk_floor/iron,
/area/station/cargo/miningdock)
"vIh" = (
@@ -85521,6 +85598,12 @@
/obj/effect/spawner/random/maintenance,
/turf/open/floor/catwalk_floor,
/area/station/maintenance/floor2/port/fore)
+"wqa" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/reagentgrinder,
+/obj/structure/table,
+/turf/open/floor/catwalk_floor/iron,
+/area/station/cargo/miningdock)
"wqg" = (
/obj/effect/turf_decal/trimline/yellow/line{
dir = 9
@@ -89235,13 +89318,11 @@
/turf/open/floor/carpet/red,
/area/station/service/theater)
"xkE" = (
-/obj/effect/turf_decal/tile/bar/opposingcorners{
+/obj/structure/sign/poster/random/directional/east,
+/obj/machinery/light/directional/east,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
dir = 1
},
-/obj/machinery/camera/autoname/directional/south,
-/obj/machinery/reagentgrinder,
-/obj/structure/table,
-/obj/structure/sign/poster/random/directional/east,
/turf/open/floor/iron/checker,
/area/station/cargo/miningdock)
"xkN" = (
@@ -93017,11 +93098,13 @@
/turf/open/floor/iron/white,
/area/station/medical/storage)
"ylD" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 4
+/obj/machinery/firealarm/directional/south,
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
},
-/turf/open/floor/iron/dark/airless,
-/area/station/hallway/floor1/aft)
+/turf/open/floor/iron/checker,
+/area/station/cargo/miningdock)
"ylE" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -119907,7 +119990,7 @@ gun
tHL
nAm
hLP
-rbT
+nAm
tHL
tHL
cUL
@@ -120164,7 +120247,7 @@ hBw
bcZ
hBw
hLP
-ney
+hBw
tHL
kOS
hDf
@@ -120417,7 +120500,7 @@ dOs
dOs
oCK
bZr
-rbT
+nAm
nTZ
iyU
aat
@@ -120931,7 +121014,7 @@ dOs
dOs
oCK
mjQ
-nAm
+rbT
ijL
rbT
hLP
@@ -121447,7 +121530,7 @@ gcE
fXm
mqt
uKO
-oRi
+mqt
aat
ydt
oYn
@@ -125056,7 +125139,7 @@ yiw
hGT
hXO
pfO
-dpH
+eSm
ylD
rjD
cax
@@ -125568,10 +125651,10 @@ quB
nYw
ehG
gGP
-nsr
+tpl
qyG
-dpH
-fvS
+tpl
+ijO
rjD
asu
cKC
@@ -125827,8 +125910,8 @@ dAc
lAq
ksD
mqn
-gha
-fvS
+bIq
+lxS
tqo
cax
cKC
@@ -126084,10 +126167,10 @@ yiw
iyY
bEp
xkE
-dpH
+rQC
dsJ
rjD
-cax
+ewg
cqY
kSN
xgH
@@ -126321,13 +126404,13 @@ dpH
ehG
tFc
yim
-yim
-mRt
-yim
+wqa
+uiU
+bpo
vIe
vyN
-mRt
-yim
+fjL
+kzk
qcW
tIn
bMD
diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm
index 0638947a9ac..c8a2d32ce84 100644
--- a/_maps/map_files/debug/runtimestation.dmm
+++ b/_maps/map_files/debug/runtimestation.dmm
@@ -1946,6 +1946,7 @@
"sH" = (
/obj/structure/table,
/obj/item/storage/box/shipping,
+/obj/item/boulder_beacon,
/turf/open/floor/iron,
/area/station/commons/storage/primary)
"tE" = (
diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm
index 5a2a8f3cdbb..224542d0ced 100644
--- a/_maps/map_files/tramstation/tramstation.dmm
+++ b/_maps/map_files/tramstation/tramstation.dmm
@@ -1608,16 +1608,18 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"afj" = (
-/obj/effect/turf_decal/trimline/brown/filled/corner{
- dir = 4
- },
/obj/effect/turf_decal/trimline/brown/filled/corner,
/obj/structure/disposalpipe/segment{
dir = 10
},
+/obj/effect/turf_decal/trimline/brown/filled/corner{
+ dir = 4
+ },
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"afl" = (
@@ -7502,6 +7504,8 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 8
},
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"bAK" = (
@@ -7585,6 +7589,13 @@
},
/turf/open/floor/iron/dark,
/area/station/command/heads_quarters/ce)
+"bDn" = (
+/obj/structure/closet/secure_closet/miner,
+/obj/effect/turf_decal/trimline/brown/filled/line{
+ dir = 5
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"bDq" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/public/glass{
@@ -8220,6 +8231,7 @@
/obj/effect/turf_decal/trimline/brown/filled/corner{
dir = 1
},
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"bMZ" = (
@@ -10320,6 +10332,11 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/iron/white,
/area/station/science/lobby)
+"cyG" = (
+/obj/effect/decal/cleanable/rubble,
+/obj/structure/closet/crate,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"cyH" = (
/obj/structure/closet/secure_closet/engineering_welding,
/obj/effect/turf_decal/bot{
@@ -12234,6 +12251,10 @@
},
/turf/open/floor/plating/elevatorshaft,
/area/station/science/xenobiology)
+"dfo" = (
+/obj/effect/turf_decal/tile/brown/fourcorners,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"dfw" = (
/obj/machinery/door/firedoor,
/obj/effect/turf_decal/trimline/neutral/filled/line,
@@ -15718,6 +15739,11 @@
},
/turf/open/floor/wood,
/area/station/service/library)
+"ewU" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/railing,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"exl" = (
/obj/machinery/computer/atmos_control/nitrogen_tank{
dir = 1
@@ -16380,6 +16406,13 @@
/obj/effect/spawner/random/armory/riot_shield,
/turf/open/floor/iron/dark,
/area/station/ai_monitored/security/armory)
+"eJN" = (
+/obj/structure/closet/secure_closet/miner,
+/obj/effect/turf_decal/trimline/brown/filled/line{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"eJQ" = (
/turf/open/floor/glass/reinforced,
/area/station/science/xenobiology)
@@ -17836,6 +17869,15 @@
/obj/effect/turf_decal/tile/bar/opposingcorners,
/turf/open/floor/iron,
/area/station/cargo/miningdock/cafeteria)
+"fmm" = (
+/obj/effect/turf_decal/trimline/brown/filled/line{
+ dir = 1
+ },
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"fmt" = (
/obj/machinery/door/airlock/mining{
name = "Mining Office"
@@ -17887,6 +17929,14 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/hallway/secondary/command)
+"fmK" = (
+/obj/structure/sign/poster/official/jim_nortons/directional/north,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"fnb" = (
/obj/effect/spawner/structure/window,
/turf/open/floor/plating,
@@ -19479,6 +19529,13 @@
/obj/machinery/computer/tram_controls/split/directional/south,
/turf/open/openspace,
/area/station/hallway/primary/tram/center)
+"fSd" = (
+/obj/structure/cable,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"fSf" = (
/obj/structure/railing,
/obj/effect/turf_decal/trimline/tram/filled/line{
@@ -21115,6 +21172,7 @@
dir = 1
},
/obj/machinery/airalarm/directional/north,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"gxO" = (
@@ -21766,6 +21824,8 @@
dir = 4
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"gJs" = (
@@ -23461,6 +23521,9 @@
/obj/effect/mapping_helpers/broken_floor,
/turf/open/floor/wood,
/area/station/commons/vacant_room/office)
+"hqk" = (
+/turf/closed/wall,
+/area/station/cargo/miningfoundry)
"hqp" = (
/obj/structure/table,
/obj/item/razor{
@@ -23658,6 +23721,12 @@
},
/turf/open/floor/iron,
/area/station/security/courtroom)
+"huN" = (
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"huO" = (
/obj/structure/transport/linear/tram,
/obj/structure/tram/split,
@@ -28371,6 +28440,14 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
+"jhU" = (
+/obj/machinery/bouldertech/brm,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"jhV" = (
/obj/effect/spawner/random/vending/snackvend,
/obj/effect/turf_decal/trimline/yellow/filled/line{
@@ -28749,6 +28826,17 @@
},
/turf/open/floor/iron,
/area/station/hallway/secondary/command)
+"jow" = (
+/obj/effect/turf_decal/tile/brown/fourcorners,
+/obj/machinery/conveyor_switch/oneway{
+ id = "mining";
+ dir = 1
+ },
+/obj/structure/railing{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"joB" = (
/obj/effect/turf_decal/trimline/neutral/filled/line{
dir = 8
@@ -29930,6 +30018,15 @@
/obj/effect/turf_decal/trimline/white/filled/line,
/turf/open/floor/iron/dark,
/area/station/engineering/storage/tech)
+"jIz" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"jIA" = (
/obj/structure/chair/pew/right,
/turf/open/floor/iron/chapel{
@@ -33070,6 +33167,13 @@
},
/turf/open/floor/plating,
/area/station/maintenance/tram/mid)
+"kLq" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/turf_decal/tile/brown/opposingcorners,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"kLz" = (
/turf/closed/wall/r_wall,
/area/station/security/prison/work)
@@ -34174,6 +34278,10 @@
},
/turf/open/floor/iron,
/area/station/hallway/primary/tram/center)
+"les" = (
+/obj/effect/turf_decal/tile/brown/opposingcorners,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"lew" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -34343,6 +34451,13 @@
},
/turf/open/floor/iron/dark,
/area/station/ai_monitored/turret_protected/aisat/hallway)
+"liE" = (
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"liN" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2,
/turf/open/floor/iron,
@@ -34420,6 +34535,8 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"ljZ" = (
@@ -34522,6 +34639,14 @@
},
/turf/open/floor/iron,
/area/station/commons/fitness/recreation)
+"lln" = (
+/obj/machinery/bouldertech/refinery,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"llo" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
/obj/effect/turf_decal/trimline/brown/filled/line{
@@ -37825,6 +37950,18 @@
"mpd" = (
/turf/open/floor/engine/o2,
/area/station/science/ordnance/storage)
+"mpe" = (
+/obj/machinery/door/airlock/mining,
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/turf_decal/tile/brown/half/contrasted{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/access/all/supply/mining,
+/obj/machinery/door/firedoor,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"mpw" = (
/obj/machinery/hydroponics/soil,
/turf/open/floor/grass,
@@ -38389,6 +38526,17 @@
"mBq" = (
/turf/closed/wall/r_wall,
/area/station/maintenance/department/crew_quarters/dorms)
+"mBy" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/effect/turf_decal/tile/brown/opposingcorners,
+/obj/structure/railing/corner/end{
+ dir = 8
+ },
+/obj/machinery/light/small/directional/east,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"mBT" = (
/obj/machinery/power/apc/auto_name/directional/east,
/obj/structure/cable,
@@ -38630,6 +38778,15 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron/white,
/area/station/medical/medbay/central)
+"mGk" = (
+/obj/machinery/airalarm/directional/east,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/railing/corner/end/flip{
+ dir = 8
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"mGl" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/circuit,
@@ -39890,6 +40047,12 @@
},
/turf/open/floor/iron,
/area/station/maintenance/tram/right)
+"nge" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"ngg" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden,
/obj/effect/spawner/structure/window/reinforced,
@@ -40057,6 +40220,22 @@
/obj/item/pen,
/turf/open/floor/iron,
/area/station/security/checkpoint/engineering)
+"niM" = (
+/obj/structure/closet,
+/obj/item/clothing/ears/earmuffs{
+ pixel_x = -3;
+ pixel_y = -2
+ },
+/obj/item/clothing/ears/earmuffs{
+ pixel_y = 7
+ },
+/obj/item/clothing/ears/earmuffs{
+ pixel_x = 6;
+ pixel_y = 3
+ },
+/obj/effect/turf_decal/tile/brown/fourcorners,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"niN" = (
/obj/machinery/power/apc/auto_name/directional/north,
/obj/structure/cable,
@@ -41542,6 +41721,12 @@
/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/secondary/exit/departure_lounge)
+"nJD" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/railing,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"nJF" = (
/obj/structure/bookcase/random/adult,
/turf/open/floor/wood/parquet,
@@ -45267,6 +45452,12 @@
"phl" = (
/turf/open/floor/carpet,
/area/station/command/heads_quarters/captain)
+"phs" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/railing,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"phB" = (
/obj/effect/turf_decal/siding/thinplating{
dir = 8
@@ -49103,6 +49294,13 @@
/obj/structure/extinguisher_cabinet/directional/south,
/turf/open/floor/wood,
/area/station/service/bar/backroom)
+"qwI" = (
+/obj/machinery/light/small/directional/west,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"qwU" = (
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 6
@@ -51727,6 +51925,12 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/hallway/secondary/service)
+"rqB" = (
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"rqD" = (
/obj/effect/turf_decal/trimline/brown/filled/corner,
/obj/effect/turf_decal/trimline/brown/filled/corner{
@@ -51816,6 +52020,13 @@
},
/turf/open/floor/iron/dark,
/area/station/ai_monitored/command/nuke_storage)
+"rsL" = (
+/obj/effect/turf_decal/tile/brown/fourcorners,
+/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"rsZ" = (
/obj/machinery/holopad/secure,
/turf/open/floor/iron/dark,
@@ -53636,6 +53847,7 @@
/obj/effect/landmark/start/shaft_miner,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"scn" = (
@@ -54399,6 +54611,13 @@
"spF" = (
/turf/open/floor/engine/vacuum,
/area/station/engineering/atmos)
+"spW" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/railing/corner/end{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"sqc" = (
/obj/structure/table,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -54925,6 +55144,14 @@
},
/turf/open/floor/plating/elevatorshaft,
/area/station/maintenance/tram/mid)
+"swU" = (
+/obj/effect/turf_decal/tile/brown/opposingcorners{
+ dir = 1
+ },
+/obj/machinery/firealarm/directional/west,
+/obj/item/kirbyplants/random,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"swX" = (
/obj/structure/window/reinforced/spawner/directional/north,
/turf/open/floor/iron/dark/smooth_edge{
@@ -57027,6 +57254,7 @@
/obj/structure/disposalpipe/junction/flip,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/cargo/miningdock)
"tkH" = (
@@ -59497,6 +59725,14 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron,
/area/station/security/execution/transfer)
+"ucK" = (
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/obj/machinery/digital_clock/directional/north,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"udk" = (
/obj/effect/turf_decal/siding/wood{
dir = 8
@@ -62235,6 +62471,13 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/hallway/primary/tram/left)
+"uUj" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"uUs" = (
/obj/machinery/vending/wardrobe/sec_wardrobe,
/obj/effect/turf_decal/trimline/red/filled/line{
@@ -62327,6 +62570,10 @@
/obj/structure/cable,
/turf/open/floor/iron,
/area/station/cargo/office)
+"uWj" = (
+/obj/item/radio/intercom/directional/west,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"uWn" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/door/poddoor/shutters/preopen{
@@ -62902,6 +63149,13 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/security/brig)
+"vgo" = (
+/obj/effect/turf_decal/trimline/brown/filled/line{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/turf/open/floor/iron,
+/area/station/cargo/miningdock)
"vgD" = (
/obj/effect/turf_decal/stripes/corner{
dir = 8
@@ -63372,6 +63626,14 @@
/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/engineering/engine_smes)
+"vnE" = (
+/obj/machinery/light/warm/directional/north,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"vnI" = (
/obj/machinery/vending/boozeomat,
/obj/effect/landmark/navigate_destination/bar,
@@ -64391,6 +64653,14 @@
/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/commons/fitness/recreation/entertainment)
+"vFm" = (
+/obj/machinery/bouldertech/refinery/smelter,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"vFp" = (
/obj/effect/turf_decal/trimline/neutral/filled/line{
dir = 5
@@ -64683,6 +64953,13 @@
/obj/machinery/light/cold/directional/east,
/turf/open/floor/iron/white,
/area/station/medical/medbay/central)
+"vLv" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"vLB" = (
/obj/structure/reagent_dispensers/cooking_oil,
/obj/effect/turf_decal/weather/snow,
@@ -65685,6 +65962,12 @@
},
/turf/open/floor/iron/checker,
/area/station/commons/lounge)
+"wew" = (
+/obj/machinery/power/apc/auto_name/directional/south,
+/obj/structure/cable,
+/obj/effect/turf_decal/tile/brown/opposingcorners,
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"wex" = (
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -67394,6 +67677,12 @@
},
/turf/open/floor/iron,
/area/station/maintenance/tram/left)
+"wMd" = (
+/obj/structure/railing/corner{
+ dir = 4
+ },
+/turf/closed/wall,
+/area/station/cargo/miningdock/cafeteria)
"wMt" = (
/obj/effect/turf_decal/trimline/neutral/filled/corner{
dir = 1
@@ -68157,6 +68446,17 @@
},
/turf/open/floor/engine,
/area/station/science/ordnance/burnchamber)
+"xep" = (
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/brown/opposingcorners,
+/obj/machinery/light_switch/directional/south{
+ pixel_x = 8;
+ pixel_y = -23
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"xet" = (
/obj/machinery/hydroponics/constructable,
/turf/open/floor/grass,
@@ -69073,6 +69373,12 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/security/office)
+"xwC" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"xxe" = (
/obj/machinery/duct,
/obj/effect/turf_decal/trimline/neutral/filled/corner{
@@ -69452,6 +69758,15 @@
"xDQ" = (
/turf/closed/wall,
/area/station/security/processing)
+"xDW" = (
+/obj/effect/mapping_helpers/burnt_floor,
+/obj/structure/sign/poster/official/midtown_slice/directional/north,
+/obj/machinery/conveyor{
+ dir = 8;
+ id = "mining"
+ },
+/turf/open/floor/iron,
+/area/station/cargo/miningfoundry)
"xEo" = (
/turf/closed/wall/r_wall,
/area/station/command/heads_quarters/captain)
@@ -116546,11 +116861,11 @@ aac
aac
aaa
aaa
-aaa
-aaa
-aaa
-aaa
-aaa
+hqk
+hqk
+hqk
+hqk
+hqk
unl
hKV
rMq
@@ -116803,11 +117118,11 @@ aac
aac
aaa
aaa
-aaa
-aaa
-aaa
-aaa
-aaa
+hqk
+cyG
+qwI
+uWj
+swU
unl
ikc
bvk
@@ -117059,12 +117374,12 @@ aac
aac
aac
aac
-aac
-aaa
-aaa
-aaa
-aaa
aaa
+hqk
+vFm
+uUj
+spW
+xep
unl
oNp
rMq
@@ -117072,7 +117387,7 @@ qBT
oCe
lDw
lJt
-oTd
+nge
cJX
uGW
fvM
@@ -117315,13 +117630,13 @@ aac
aac
aac
aac
-aac
-aac
-aaa
-aaa
-aaa
aaa
aaa
+hqk
+xDW
+xwC
+nJD
+huN
unl
rbM
gJs
@@ -117329,7 +117644,7 @@ uRR
rMq
unl
npb
-oTd
+nge
cJX
uGW
uGW
@@ -117573,13 +117888,13 @@ aac
aac
aac
aac
-aac
aaa
-aaa
-aaa
-aaa
-aaa
-unl
+hqk
+vnE
+xwC
+ewU
+les
+njK
xiZ
nTG
nTG
@@ -117829,14 +118144,14 @@ aac
aac
aac
aac
-aac
-aac
aaa
aaa
-aaa
-aaa
-aaa
-unl
+hqk
+lln
+xwC
+ewU
+liE
+njK
flZ
ktb
mNp
@@ -118086,20 +118401,20 @@ aac
aac
aac
aac
-aac
-aac
-aaa
-aaa
-aaa
aaa
aaa
+hqk
+ucK
+uUj
+ewU
+wew
+wMd
unl
unl
unl
unl
unl
-unl
-eyR
+vgo
bAa
cJX
uGW
@@ -118344,18 +118659,18 @@ aac
aac
aac
aac
-aac
aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-uGW
-bwM
+hqk
+fmK
+vLv
+phs
+fSd
+jow
+niM
+hqk
+dfo
pni
+kaF
bMX
ljU
lGz
@@ -118602,18 +118917,18 @@ aac
aac
aaa
aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-uGW
-bwM
-eyR
-kDi
+hqk
+jhU
+xwC
+mGk
+kLq
+mBy
+jIz
+mpe
+rsL
+fmm
+rqB
+rqB
afi
kDi
cJX
@@ -118859,17 +119174,17 @@ aac
aac
aac
aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
-aaa
+hqk
+hqk
+hqk
+hqk
+hqk
+hqk
+hqk
uGW
bwM
-dwA
+bDn
+eJN
dAl
afj
cZY
@@ -119123,7 +119438,7 @@ aaa
aaa
aaa
aaa
-aaa
+uGW
uGW
uGW
uGW
diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm
index aff00260705..d4f9af401cf 100644
--- a/code/__DEFINES/ai/monsters.dm
+++ b/code/__DEFINES/ai/monsters.dm
@@ -116,6 +116,10 @@
#define BB_ORE_TARGET "BB_ore_target"
/// which ore types we will not eat
#define BB_ORE_IGNORE_TYPES "BB_ore_ignore_types"
+/// key that holds the boulder we will break
+#define BB_BOULDER_TARGET "BB_boulder_target"
+/// key that holds the ore_vent we will harvest boulders from
+#define BB_VENT_TARGET "BB_vent_target"
// minebot keys
/// key that stores our toggle light ability
diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm
index 294fe6364cd..24ab2eb3303 100644
--- a/code/__DEFINES/construction/material.dm
+++ b/code/__DEFINES/construction/material.dm
@@ -75,3 +75,15 @@
#define MATERIAL_QUANTITY_RARE 2500
/// How much quantity of a material stock exists for exotic materials like diamond & bluespace crystals.
#define MATERIAL_QUANTITY_EXOTIC 500
+
+// The number of ore vents that will spawn boulders with this material.
+/// Is this material going to spawn often in ore vents? (80% of vents on lavaland)
+#define MATERIAL_RARITY_COMMON 12
+/// Is this material going to spawn often in ore vents? (53% of vents on lavaland)
+#define MATERIAL_RARITY_SEMIPRECIOUS 8
+/// Is this material going to spawn uncommonly in ore vents? (33% of vents on lavaland)
+#define MATERIAL_RARITY_PRECIOUS 5
+/// Is this material going to spawn rarely in ore vents? (20% of vents on lavaland)
+#define MATERIAL_RARITY_RARE 3
+/// Is this material only going to spawn once in ore vents? (6% of vents on lavaland)
+#define MATERIAL_RARITY_UNDISCOVERED 1
diff --git a/code/__DEFINES/dcs/signals/signals_mining.dm b/code/__DEFINES/dcs/signals/signals_mining.dm
index 8dc3fe283f6..3ef84b1f7b6 100644
--- a/code/__DEFINES/dcs/signals/signals_mining.dm
+++ b/code/__DEFINES/dcs/signals/signals_mining.dm
@@ -1,3 +1,6 @@
+/// Sent from /obj/structure/ore_vent, lets the spawner component know to qdel.
+#define COMSIG_VENT_WAVE_CONCLUDED "mining_waves_stop"
+
/// Fired by a mob which has been grabbed by a goliath
#define COMSIG_GOLIATH_TENTACLED_GRABBED "comsig_goliath_tentacle_grabbed"
/// Fired by a goliath tentacle which is returning to the earth
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index f164c78d422..efcc3a4fbd8 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -7,7 +7,7 @@
#define WEIGHT_CLASS_SMALL 2
/// Standard backpacks can carry tiny, small & normal items, (e.g. fire extinguisher, stun baton, gas mask, metal sheets)
#define WEIGHT_CLASS_NORMAL 3
-/// Items that can be weilded or equipped but not stored in an inventory, (e.g. defibrillator, backpack, space suits)
+/// Items that can be wielded or equipped but not stored in an inventory, (e.g. defibrillator, backpack, space suits)
#define WEIGHT_CLASS_BULKY 4
/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons)
#define WEIGHT_CLASS_HUGE 5
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 1ba6879005b..0a9ea44aaa8 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -197,7 +197,7 @@
#define MOB_SHIELD_LAYER 4.01
#define MOB_ABOVE_PIGGYBACK_LAYER 4.06
#define MOB_UPPER_LAYER 4.07
-#define HITSCAN_PROJECTILE_LAYER 4.09 //above all mob but still hidden by FoV
+#define HITSCAN_PROJECTILE_LAYER 4.09
#define ABOVE_MOB_LAYER 4.1
#define WALL_OBJ_LAYER 4.25
#define TRAM_SIGNAL_LAYER 4.26
diff --git a/code/__DEFINES/mecha.dm b/code/__DEFINES/mecha.dm
index 0f900f72ee4..8fd3ff4888c 100644
--- a/code/__DEFINES/mecha.dm
+++ b/code/__DEFINES/mecha.dm
@@ -46,6 +46,7 @@
#define MECHA_SNOWFLAKE_ID_AIR_TANK "air_tank_snowflake"
#define MECHA_SNOWFLAKE_ID_WEAPON_BALLISTIC "ballistic_weapon_snowflake"
#define MECHA_SNOWFLAKE_ID_GENERATOR "generator_snowflake"
+#define MECHA_SNOWFLAKE_ID_ORE_SCANNER "orescanner_snowflake"
#define MECHA_SNOWFLAKE_ID_CLAW "lawclaw_snowflake"
#define MECHA_AMMO_INCENDIARY "Incendiary bullet"
diff --git a/code/__DEFINES/mining.dm b/code/__DEFINES/mining.dm
new file mode 100644
index 00000000000..2f4b5446476
--- /dev/null
+++ b/code/__DEFINES/mining.dm
@@ -0,0 +1,47 @@
+// Defines related to the mining rework circa June 2023
+/// Durability of a large size boulder from a large size vent.
+#define BOULDER_SIZE_LARGE 15
+/// Durability of a medium size boulder from a medium size vent.
+#define BOULDER_SIZE_MEDIUM 10
+/// Durability of a small size boulder from a small size vent.
+#define BOULDER_SIZE_SMALL 5
+/// How many boulders can a single ore vent have on it's tile before it stops producing more?
+#define MAX_BOULDERS_PER_VENT 10
+/// Time multiplier
+#define INATE_BOULDER_SPEED_MULTIPLIER 3
+// Vent type
+/// Large vents, giving large boulders.
+#define LARGE_VENT_TYPE "large"
+/// Medium vents, giving medium boulders.
+#define MEDIUM_VENT_TYPE "medium"
+/// Small vents, giving small boulders.
+#define SMALL_VENT_TYPE "small"
+
+/// Proximity to a vent that a wall ore needs to be for 5 ore to be mined.
+#define VENT_PROX_VERY_HIGH 3
+/// Proximity to a vent that a wall ore needs to be for 4 ore to be mined.
+#define VENT_PROX_HIGH 6
+/// Proximity to a vent that a wall ore needs to be for 3 ore to be mined.
+#define VENT_PROX_MEDIUM 15
+/// Proximity to a vent that a wall ore needs to be for 2 ore to be mined.
+#define VENT_PROX_LOW 32
+/// Proximity to a vent that a wall ore needs to be for 1 ore to be mined.
+#define VENT_PROX_FAR 64
+
+/// The chance of ore spawning in a wall that is VENT_PROX_VERY_HIGH tiles to a vent.
+#define VENT_CHANCE_VERY_HIGH 75
+/// The chance of ore spawning in a wall that is VENT_PROX_HIGH tiles to a vent.
+#define VENT_CHANCE_HIGH 18
+/// The chance of ore spawning in a wall that is VENT_PROX_MEDIUM tiles to a vent.
+#define VENT_CHANCE_MEDIUM 9
+/// The chance of ore spawning in a wall that is VENT_PROX_LOW tiles to a vent.
+#define VENT_CHANCE_LOW 5
+/// The chance of ore spawning in a wall that is VENT_PROX_FAR tiles to a vent.
+#define VENT_CHANCE_FAR 1
+
+/// The number of points a miner gets for discovering a vent, multiplied by BOULDER_SIZE when completing a wave defense minus the discovery bonus.
+#define MINER_POINT_MULTIPLIER 100
+/// The multiplier that gets applied for automatically generated mining points.
+#define MINING_POINT_MACHINE_MULTIPLIER 0.8
+
+
diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm
index e870e9de7a6..f6ecde7c2e1 100644
--- a/code/__DEFINES/skills.dm
+++ b/code/__DEFINES/skills.dm
@@ -43,3 +43,6 @@
#define FISHING_SKILL_DIFFIULTY_EXP_MULT 0.015
///How much exp one would gain per spent playing the fishing minigame at minimum difficulty. the time is multiplied by 0.1 because deciseconds...
#define FISHING_SKILL_EXP_PER_SECOND (SKILL_EXP_LEGENDARY / (15 MINUTES * 0.1))
+
+///The base modifier a boulder's size grants to the mining skill.
+#define MINING_SKILL_BOULDER_SIZE_XP 10
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 8f8ce8dadbb..0d01e3b920d 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -1058,4 +1058,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait which means whatever has this is dancing by a dance machine
#define TRAIT_DISCO_DANCER "disco_dancer"
+/// That which allows mobs to instantly break down boulders.
+#define TRAIT_INSTANTLY_PROCESSES_BOULDERS "instantly_processes_boulders"
+
+/// Trait applied to objects and mobs that can attack a boulder and break it down. (See /obj/item/boulder/manual_process())
+#define TRAIT_BOULDER_BREAKER "boulder_breaker"
+
// END TRAIT DEFINES
diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm
index 5a0d5c3f002..98e11b483ba 100644
--- a/code/__HELPERS/spatial_info.dm
+++ b/code/__HELPERS/spatial_info.dm
@@ -442,3 +442,31 @@
if(our_area == get_area(carbon))
return FALSE
return TRUE
+
+/**
+ * Behaves like the orange() proc, but only looks in the outer range of the function (The "peel" of the orange).
+ * This is useful for things like checking if a mob is in a certain range, but not within a smaller range.
+ *
+ * @params outer_range - The outer range of the cicle to pull from.
+ * @params inner_range - The inner range of the circle to NOT pull from.
+ * @params center - The center of the circle to pull from, can be an atom (we'll apply get_turf() to it within circle_x_turfs procs.)
+ * @params view_based - If TRUE, we'll use circle_view_turfs instead of circle_range_turfs procs.
+ */
+/proc/turf_peel(outer_range, inner_range, center, view_based = FALSE)
+ if(inner_range > outer_range) // If the inner range is larger than the outer range, you're using this wrong.
+ CRASH("Turf peel inner range is larger than outer range!")
+ var/list/peel = list()
+ var/list/outer
+ var/list/inner
+ if(view_based)
+ outer = circle_view_turfs(center, outer_range)
+ inner = circle_view_turfs(center, inner_range)
+ else
+ outer = circle_range_turfs(center, outer_range)
+ inner = circle_range_turfs(center, inner_range)
+ for(var/turf/possible_spawn as anything in outer)
+ if(possible_spawn in inner)
+ continue
+ peel += possible_spawn
+ return peel
+
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index d567f152c06..82878b2dff1 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -32,6 +32,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_AREA_SENSITIVE" = TRAIT_AREA_SENSITIVE,
"TRAIT_ASHSTORM_IMMUNE" = TRAIT_ASHSTORM_IMMUNE,
"TRAIT_BLOCKING_EXPLOSIVES" = TRAIT_BLOCKING_EXPLOSIVES,
+ "TRAIT_BOULDER_BREAKER" = TRAIT_BOULDER_BREAKER,
"TRAIT_CASTABLE_LOC" = TRAIT_CASTABLE_LOC,
"TRAIT_DEL_ON_SPACE_DUMP" = TRAIT_DEL_ON_SPACE_DUMP,
"TRAIT_FISH_CASE_COMPATIBILE" = TRAIT_FISH_CASE_COMPATIBILE,
@@ -500,6 +501,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE,
"TRAIT_WIELDED" = TRAIT_WIELDED,
"TRAIT_BAKEABLE" = TRAIT_BAKEABLE,
+ "TRAIT_INSTANTLY_PROCESSES_BOULDERS" = TRAIT_INSTANTLY_PROCESSES_BOULDERS,
),
/obj/item/ammo_casing = list(
"TRAIT_DART_HAS_INSERT" = TRAIT_DART_HAS_INSERT,
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 9241c3dc6b9..cda203b0302 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -252,18 +252,18 @@ SUBSYSTEM_DEF(mapping)
var/list/ice_ruins = levels_by_trait(ZTRAIT_ICE_RUINS)
if (ice_ruins.len)
// needs to be whitelisted for underground too so place_below ruins work
- seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), themed_ruins[ZTRAIT_ICE_RUINS], clear_below = TRUE)
+ seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), themed_ruins[ZTRAIT_ICE_RUINS], clear_below = TRUE, mineral_budget = 4)
var/list/ice_ruins_underground = levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND)
if (ice_ruins_underground.len)
- seedRuins(ice_ruins_underground, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/underground/unexplored), themed_ruins[ZTRAIT_ICE_RUINS_UNDERGROUND], clear_below = TRUE)
+ seedRuins(ice_ruins_underground, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/underground/unexplored), themed_ruins[ZTRAIT_ICE_RUINS_UNDERGROUND], clear_below = TRUE, mineral_budget = 21)
// Generate deep space ruins
var/list/space_ruins = levels_by_trait(ZTRAIT_SPACE_RUINS)
if (space_ruins.len)
// Create a proportional budget by multiplying the amount of space ruin levels in the current map over the default amount
var/proportional_budget = round(CONFIG_GET(number/space_budget) * (space_ruins.len / DEFAULT_SPACE_RUIN_LEVELS))
- seedRuins(space_ruins, proportional_budget, list(/area/space), themed_ruins[ZTRAIT_SPACE_RUINS])
+ seedRuins(space_ruins, proportional_budget, list(/area/space), themed_ruins[ZTRAIT_SPACE_RUINS], mineral_budget = 0)
/// Sets up rivers, and things that behave like rivers. So lava/plasma rivers, and chasms
/// It is important that this happens AFTER generating mineral walls and such, since we rely on them for river logic
diff --git a/code/controllers/subsystem/ore_generation.dm b/code/controllers/subsystem/ore_generation.dm
new file mode 100644
index 00000000000..e659b10d873
--- /dev/null
+++ b/code/controllers/subsystem/ore_generation.dm
@@ -0,0 +1,80 @@
+
+SUBSYSTEM_DEF(ore_generation)
+ name = "Ore Generation"
+ wait = 60 SECONDS
+ init_order = INIT_ORDER_DEFAULT
+ runlevels = RUNLEVEL_GAME
+
+ /// All ore vents that are currently producing boulders.
+ var/list/processed_vents = list()
+ /// All the boulders that have been produced by ore vents to be pulled by BRM machines.
+ var/list/available_boulders = list()
+ /// All the ore vents that are currently in the game, not just the ones that are producing boulders.
+ var/list/possible_vents = list()
+ /// A list of all the minerals that are being mined by ore vents. We reset this list every time cave generation is done.
+ var/list/ore_vent_minerals = list()
+ /**
+ * Associated list of minerals to be associated with our ore vents.
+ * Generally Should be empty by the time initialize ends on lavaland.
+ * Each key value is the number of vents that will have this ore as a unique possible choice.
+ */
+ var/static/list/ore_vent_minerals_default = list(
+ /datum/material/iron = 13,
+ /datum/material/glass = 12,
+ /datum/material/plasma = 9,
+ /datum/material/titanium = 6,
+ /datum/material/silver = 5,
+ /datum/material/gold = 5,
+ /datum/material/diamond = 3,
+ /datum/material/uranium = 3,
+ /datum/material/bluespace = 3,
+ /datum/material/plastic = 1,
+ )
+ var/list/ore_vent_sizes = list(
+ LARGE_VENT_TYPE = 3,
+ MEDIUM_VENT_TYPE = 5,
+ SMALL_VENT_TYPE = 7,
+ )
+ /// Ores spawned by proximity to an ore vent. Useful for logging purposes.
+ var/list/post_ore_random = list(
+ "1" = 0,
+ "2" = 0,
+ "3" = 0,
+ "4" = 0,
+ "5" = 0,
+ )
+ /// Ores spawned randomly on the map without proximity to an ore vent. Useful for logging purposes.
+ var/list/post_ore_manual = list(
+ "1" = 0,
+ "2" = 0,
+ "3" = 0,
+ "4" = 0,
+ "5" = 0,
+ )
+
+/datum/controller/subsystem/ore_generation/Initialize()
+ //Basically, we're going to round robin through the list of ore vents and assign a mineral to them until complete.
+ while(ore_vent_minerals.len > 0)
+ for(var/obj/structure/ore_vent/vent as anything in possible_vents)
+ if(vent.unique_vent)
+ continue //Ya'll already got your minerals.
+ if(ore_vent_minerals.len <= 0)
+ break
+ vent.generate_mineral_breakdown(max_minerals = 1, map_loading = TRUE)
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/ore_generation/fire(resumed)
+ available_boulders = list() // reset upon new fire.
+ for(var/obj/structure/ore_vent/current_vent as anything in processed_vents)
+
+ var/local_vent_count = 0
+ for(var/obj/item/boulder/old_rock in current_vent.loc)
+ available_boulders += old_rock
+ local_vent_count++
+
+ if(local_vent_count >= MAX_BOULDERS_PER_VENT)
+ continue //We don't want to be accountable for literally hundreds of unprocessed boulders for no reason.
+
+ var/obj/item/boulder/new_rock = current_vent.produce_boulder()
+ available_boulders += new_rock
+
diff --git a/code/datums/ai/hunting_behavior/hunting_behaviors.dm b/code/datums/ai/hunting_behavior/hunting_behaviors.dm
index 3e747640be3..1615a28d53b 100644
--- a/code/datums/ai/hunting_behavior/hunting_behaviors.dm
+++ b/code/datums/ai/hunting_behavior/hunting_behaviors.dm
@@ -160,3 +160,19 @@
var/datum/action/cooldown/ability = hunter.ai_controller.blackboard[ability_key]
ability.InterceptClickOn(hunter, null, hunted)
+
+/datum/ai_behavior/hunt_target/latch_onto
+
+/datum/ai_behavior/hunt_target/latch_onto/setup(datum/ai_controller/controller, hunting_target_key, hunting_cooldown_key)
+ . = ..()
+ var/mob/living/living_pawn = controller.pawn
+ if(living_pawn.buckled)
+ return FALSE
+
+/datum/ai_behavior/hunt_target/latch_onto/target_caught(mob/living/hunter, obj/hunted)
+ if(hunter.buckled)
+ return FALSE
+ if(!hunted.buckle_mob(hunter, force = TRUE))
+ return FALSE
+ hunted.visible_message(span_notice("[hunted] has been latched onto by [hunter]!"))
+ return TRUE
diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm
index 76538bcb315..9829dfc3f52 100644
--- a/code/datums/components/chasm.dm
+++ b/code/datums/components/chasm.dm
@@ -32,6 +32,7 @@
/obj/singularity,
/obj/structure/lattice,
/obj/structure/stone_tile,
+ /obj/structure/ore_vent,
))
/datum/component/chasm/Initialize(turf/target, mapload)
diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm
index 3f660d5fcbd..a9bb9b4432b 100644
--- a/code/datums/components/spawner.dm
+++ b/code/datums/components/spawner.dm
@@ -11,10 +11,15 @@
var/list/faction
/// List of weak references to things we have already created
var/list/spawned_things = list()
- /// Time until we next spawn
+ /// How many mobs can we spawn maximum each time we try to spawn? (1 - max)
+ var/max_spawn_per_attempt
+ /// Distance from the spawner to spawn mobs
+ var/spawn_distance
+ /// Distance from the spawner to exclude mobs from spawning
+ var/spawn_distance_exclude
COOLDOWN_DECLARE(spawn_delay)
-/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, faction = list(FACTION_MINING), spawn_text = null)
+/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 2 , faction = list(FACTION_MINING), spawn_text = null, spawn_distance = 1, spawn_distance_exclude = 0)
if (!islist(spawn_types))
CRASH("invalid spawn_types to spawn specified for spawner component!")
src.spawn_time = spawn_time
@@ -22,8 +27,12 @@
src.faction = faction
src.spawn_text = spawn_text
src.max_spawned = max_spawned
+ src.max_spawn_per_attempt = max_spawn_per_attempt
+ src.spawn_distance = spawn_distance
+ src.spawn_distance_exclude = spawn_distance_exclude
RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(stop_spawning))
+ RegisterSignal(parent, COMSIG_VENT_WAVE_CONCLUDED, PROC_REF(stop_spawning))
START_PROCESSING((spawn_time < 2 SECONDS ? SSfastprocess : SSprocessing), src)
/datum/component/spawner/process()
@@ -47,22 +56,41 @@
return
var/atom/spawner = parent
COOLDOWN_START(src, spawn_delay, spawn_time)
-
var/chosen_mob_type = pick(spawn_types)
- var/atom/created = new chosen_mob_type(spawner.loc)
- created.flags_1 |= (spawner.flags_1 & ADMIN_SPAWNED_1)
- spawned_things += WEAKREF(created)
- if (isliving(created))
- var/mob/living/created_mob = created
- created_mob.faction = src.faction
- RegisterSignal(created, COMSIG_MOB_STATCHANGE, PROC_REF(mob_stat_changed))
+ var/adjusted_spawn_count = 1
+ if (max_spawn_per_attempt > 1)
+ adjusted_spawn_count = rand(1, max_spawn_per_attempt)
+ for(var/i in 1 to adjusted_spawn_count)
+ var/atom/created
+ var/turf/picked_spot
+
+ if(spawn_distance == 1)
+ created = new chosen_mob_type(spawner.loc)
+ else if(spawn_distance >= 1 && spawn_distance_exclude >= 1)
+ picked_spot = pick(turf_peel(spawn_distance, spawn_distance_exclude, spawner.loc, view_based = TRUE))
+ if(!picked_spot)
+ picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance))
+ created = new chosen_mob_type(picked_spot)
+ else if (spawn_distance >= 1)
+ picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance))
+ created = new chosen_mob_type(picked_spot)
+
+ created.flags_1 |= (spawner.flags_1 & ADMIN_SPAWNED_1)
+ spawned_things += WEAKREF(created)
+
+ if (isliving(created))
+ var/mob/living/created_mob = created
+ created_mob.faction = src.faction
+ RegisterSignal(created, COMSIG_MOB_STATCHANGE, PROC_REF(mob_stat_changed))
+
+ SEND_SIGNAL(src, COMSIG_SPAWNER_SPAWNED, created)
+ RegisterSignal(created, COMSIG_QDELETING, PROC_REF(on_deleted))
if (spawn_text)
- spawner.visible_message(span_danger("[created] [spawn_text] [spawner]."))
+ spawner.visible_message(span_danger("A creature [spawn_text] [spawner]."))
+
- SEND_SIGNAL(src, COMSIG_SPAWNER_SPAWNED, created)
- RegisterSignal(created, COMSIG_QDELETING, PROC_REF(on_deleted))
/// Remove weakrefs to atoms which have been killed or deleted without us picking it up somehow
/datum/component/spawner/proc/validate_references()
diff --git a/code/datums/mapgen/CaveGenerator.dm b/code/datums/mapgen/CaveGenerator.dm
index 754b8755545..5211c413531 100644
--- a/code/datums/mapgen/CaveGenerator.dm
+++ b/code/datums/mapgen/CaveGenerator.dm
@@ -35,7 +35,7 @@
///Base chance of spawning flora
var/flora_spawn_chance = 2
///Base chance of spawning features
- var/feature_spawn_chance = 0.15
+ var/feature_spawn_chance = 0.25
///Unique ID for this spawner
var/string_gen
@@ -73,7 +73,10 @@
)
flora_spawn_list = expand_weights(weighted_flora_spawn_list)
if(!weighted_feature_spawn_list)
- weighted_feature_spawn_list = list(/obj/structure/geyser/random = 1)
+ weighted_feature_spawn_list = list(
+ /obj/structure/geyser/random = 1,
+ /obj/structure/ore_vent/random = 1,
+ )
feature_spawn_list = expand_weights(weighted_feature_spawn_list)
open_turf_types = expand_weights(weighted_open_turf_types)
closed_turf_types = expand_weights(weighted_closed_turf_types)
@@ -115,6 +118,7 @@
var/megas_allowed = (generate_in.area_flags & MEGAFAUNA_SPAWN_ALLOWED) && length(megafauna_spawn_list)
var/start_time = REALTIMEOFDAY
+ SSore_generation.ore_vent_minerals = (SSore_generation.ore_vent_minerals_default).Copy() //reset the ore vent minerals to the default
for(var/turf/target_turf as anything in turfs)
if(!(target_turf.type in open_turf_types)) //only put stuff on open turfs we generated, so closed walls and rivers and stuff are skipped
diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm
index 96d30fbd359..168b62a25e4 100644
--- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm
+++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm
@@ -1,6 +1,9 @@
/datum/map_generator/cave_generator/icemoon
weighted_open_turf_types = list(/turf/open/misc/asteroid/snow/icemoon = 19, /turf/open/misc/ice/icemoon = 1)
- weighted_closed_turf_types = list(/turf/closed/mineral/random/snow = 1)
+ weighted_closed_turf_types = list(
+ /turf/closed/mineral/snowmountain/icemoon = 100,
+ /turf/closed/mineral/gibtonite/ice = 4,
+ )
weighted_mob_spawn_list = list(
@@ -26,6 +29,7 @@
/obj/structure/geyser/protozine = 10,
/obj/structure/geyser/random = 2,
/obj/structure/geyser/wittel = 10,
+ /obj/structure/ore_vent/boss/icebox = 1,
)
/datum/map_generator/cave_generator/icemoon/surface
@@ -59,7 +63,7 @@
/datum/map_generator/cave_generator/icemoon/surface/noruins //use this for when you don't want ruins to spawn in a certain area
/datum/map_generator/cave_generator/icemoon/deep
- weighted_closed_turf_types = list(/turf/closed/mineral/random/snow/underground = 1)
+ weighted_closed_turf_types = list(/turf/closed/mineral/snowmountain/icemoon = 1)
weighted_mob_spawn_list = list(
SPAWN_MEGAFAUNA = 1,
/mob/living/basic/mining/ice_demon = 100,
diff --git a/code/datums/mapgen/Cavegens/LavalandGenerator.dm b/code/datums/mapgen/Cavegens/LavalandGenerator.dm
index 6f8aa7ed1bb..846e23181e0 100644
--- a/code/datums/mapgen/Cavegens/LavalandGenerator.dm
+++ b/code/datums/mapgen/Cavegens/LavalandGenerator.dm
@@ -33,6 +33,7 @@
/obj/structure/geyser/protozine = 10,
/obj/structure/geyser/random = 2,
/obj/structure/geyser/wittel = 10,
+ /obj/structure/ore_vent/boss = 1,
)
initial_closed_chance = 45
@@ -42,4 +43,4 @@
/datum/map_generator/cave_generator/lavaland/ruin_version
weighted_open_turf_types = list(/turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins = 1)
- weighted_closed_turf_types = list(/turf/closed/mineral/random/volcanic/do_not_chasm = 1)
+ weighted_closed_turf_types = list(/turf/closed/mineral/volcanic/lava_land_surface/do_not_chasm = 1)
diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index 396b902b73f..da5a15b8d31 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -29,6 +29,8 @@ Simple datum which is instanced once per type and is used for every object of sa
var/list/categories = list()
///The type of sheet this material creates. This should be replaced as soon as possible by greyscale sheets
var/sheet_type
+ /// What type of ore is this material associated with? Used for mining, and not every material has one.
+ var/obj/item/ore_type
///This is a modifier for force, and resembles the strength of the material
var/strength_modifier = 1
///This is a modifier for integrity, and resembles the strength of the material
@@ -59,6 +61,10 @@ Simple datum which is instanced once per type and is used for every object of sa
var/obj/item/shard_type
///What type of debris the tile will leave behind when shattered.
var/obj/effect/decal/debris_type
+ /// How likely this mineral is to be found in a boulder during mining.
+ var/mineral_rarity = MATERIAL_RARITY_COMMON
+ /// How many points per units of ore does this grant?
+ var/points_per_unit = 1
/** Handles initializing the material.
*
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index f79b9f7e422..3c5f6ab62d0 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -6,7 +6,10 @@
greyscale_colors = "#878687"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/iron
+ ore_type = /obj/item/stack/ore/iron
value_per_unit = 5 / SHEET_MATERIAL_AMOUNT
+ mineral_rarity = MATERIAL_RARITY_COMMON
+ points_per_unit = 1 / SHEET_MATERIAL_AMOUNT
minimum_value_override = 0
tradable = TRUE
tradable_base_quantity = MATERIAL_QUANTITY_COMMON
@@ -25,6 +28,7 @@
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
integrity_modifier = 0.1
sheet_type = /obj/item/stack/sheet/glass
+ ore_type = /obj/item/stack/ore/glass
shard_type = /obj/item/shard
debris_type = /obj/effect/decal/cleanable/glass
value_per_unit = 5 / SHEET_MATERIAL_AMOUNT
@@ -33,6 +37,8 @@
tradable_base_quantity = MATERIAL_QUANTITY_COMMON
beauty_modifier = 0.05
armor_modifiers = list(MELEE = 0.2, BULLET = 0.2, ENERGY = 1, BIO = 0.2, FIRE = 1, ACID = 0.2)
+ mineral_rarity = MATERIAL_RARITY_COMMON
+ points_per_unit = 1 / SHEET_MATERIAL_AMOUNT
/datum/material/glass/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5, sharpness = TRUE) //cronch
@@ -61,10 +67,13 @@ Unless you know what you're doing, only use the first three numbers. They're in
greyscale_colors = "#e3f1f8"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/silver
+ ore_type = /obj/item/stack/ore/silver
value_per_unit = 50 / SHEET_MATERIAL_AMOUNT
tradable = TRUE
tradable_base_quantity = MATERIAL_QUANTITY_UNCOMMON
beauty_modifier = 0.075
+ mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS
+ points_per_unit = 16 / SHEET_MATERIAL_AMOUNT
/datum/material/silver/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5)
@@ -79,11 +88,14 @@ Unless you know what you're doing, only use the first three numbers. They're in
strength_modifier = 1.2
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/gold
+ ore_type = /obj/item/stack/ore/gold
value_per_unit = 125 / SHEET_MATERIAL_AMOUNT
tradable = TRUE
tradable_base_quantity = MATERIAL_QUANTITY_RARE
beauty_modifier = 0.15
armor_modifiers = list(MELEE = 1.1, BULLET = 1.1, LASER = 1.15, ENERGY = 1.15, BOMB = 1, BIO = 1, FIRE = 0.7, ACID = 1.1)
+ mineral_rarity = MATERIAL_RARITY_PRECIOUS
+ points_per_unit = 18 / SHEET_MATERIAL_AMOUNT
/datum/material/gold/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(10, BRUTE, BODY_ZONE_HEAD, wound_bonus = 5)
@@ -97,6 +109,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
greyscale_colors = "#71c8f784"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
+ ore_type = /obj/item/stack/ore/diamond
alpha = 132
starlight_color = COLOR_BLUE_LIGHT
value_per_unit = 500 / SHEET_MATERIAL_AMOUNT
@@ -104,6 +117,8 @@ Unless you know what you're doing, only use the first three numbers. They're in
tradable_base_quantity = MATERIAL_QUANTITY_EXOTIC
beauty_modifier = 0.3
armor_modifiers = list(MELEE = 1.3, BULLET = 1.3, LASER = 0.6, ENERGY = 1, BOMB = 1.2, BIO = 1, FIRE = 1, ACID = 1)
+ mineral_rarity = MATERIAL_RARITY_RARE
+ points_per_unit = 50 / SHEET_MATERIAL_AMOUNT
/datum/material/diamond/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7)
@@ -117,11 +132,14 @@ Unless you know what you're doing, only use the first three numbers. They're in
greyscale_colors = rgb(48, 237, 26)
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/uranium
+ ore_type = /obj/item/stack/ore/uranium
value_per_unit = 100 / SHEET_MATERIAL_AMOUNT
tradable = TRUE
tradable_base_quantity = MATERIAL_QUANTITY_RARE
beauty_modifier = 0.3 //It shines so beautiful
armor_modifiers = list(MELEE = 1.5, BULLET = 1.4, LASER = 0.5, ENERGY = 0.5, FIRE = 1, ACID = 1)
+ mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS
+ points_per_unit = 30 / SHEET_MATERIAL_AMOUNT
/datum/material/uranium/on_applied(atom/source, amount, material_flags)
. = ..()
@@ -154,9 +172,12 @@ Unless you know what you're doing, only use the first three numbers. They're in
greyscale_colors = "#c162ec"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/plasma
+ ore_type = /obj/item/stack/ore/plasma
value_per_unit = 200 / SHEET_MATERIAL_AMOUNT
beauty_modifier = 0.15
armor_modifiers = list(MELEE = 1.4, BULLET = 0.7, ENERGY = 1.2, BIO = 1.2, ACID = 0.5)
+ mineral_rarity = MATERIAL_RARITY_PRECIOUS
+ points_per_unit = 15 / SHEET_MATERIAL_AMOUNT
/datum/material/plasma/on_applied(atom/source, amount, material_flags)
. = ..()
@@ -186,7 +207,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE)
beauty_modifier = 0.5
sheet_type = /obj/item/stack/sheet/bluespace_crystal
+ ore_type = /obj/item/stack/ore/bluespace_crystal
value_per_unit = 300 / SHEET_MATERIAL_AMOUNT
+ mineral_rarity = MATERIAL_RARITY_RARE
+ points_per_unit = 50 / SHEET_MATERIAL_AMOUNT
tradable = TRUE
tradable_base_quantity = MATERIAL_QUANTITY_EXOTIC
@@ -203,9 +227,12 @@ Unless you know what you're doing, only use the first three numbers. They're in
greyscale_colors = "#ffff00"
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/bananium
+ ore_type = /obj/item/stack/ore/bananium
value_per_unit = 1000 / SHEET_MATERIAL_AMOUNT
beauty_modifier = 0.5
armor_modifiers = list(BOMB = 100, FIRE = 10) //Clowns cant be blown away.
+ mineral_rarity = MATERIAL_RARITY_UNDISCOVERED
+ points_per_unit = 60 / SHEET_MATERIAL_AMOUNT
/datum/material/bananium/on_applied(atom/source, amount, material_flags)
. = ..()
@@ -231,11 +258,13 @@ Unless you know what you're doing, only use the first three numbers. They're in
strength_modifier = 1.3
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/titanium
+ ore_type = /obj/item/stack/ore/titanium
value_per_unit = 125 / SHEET_MATERIAL_AMOUNT
tradable = TRUE
tradable_base_quantity = MATERIAL_QUANTITY_UNCOMMON
beauty_modifier = 0.05
armor_modifiers = list(MELEE = 1.35, BULLET = 1.3, LASER = 1.3, ENERGY = 1.25, BOMB = 1.25, BIO = 1, FIRE = 0.7, ACID = 1)
+ mineral_rarity = MATERIAL_RARITY_SEMIPRECIOUS
/datum/material/titanium/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(15, BRUTE, BODY_ZONE_HEAD, wound_bonus = 7)
@@ -252,6 +281,8 @@ Unless you know what you're doing, only use the first three numbers. They're in
value_per_unit = 600 / SHEET_MATERIAL_AMOUNT
beauty_modifier = 0.5
armor_modifiers = list(MELEE = 1.35, BULLET = 2, LASER = 0.5, ENERGY = 1.25, BOMB = 1.25, BIO = 1, FIRE = 1.4, ACID = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle.
+ mineral_rarity = MATERIAL_RARITY_UNDISCOVERED
+ points_per_unit = 100 / SHEET_MATERIAL_AMOUNT
/datum/material/runite/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10)
@@ -265,10 +296,13 @@ Unless you know what you're doing, only use the first three numbers. They're in
greyscale_colors = "#caccd9"
strength_modifier = 0.85
sheet_type = /obj/item/stack/sheet/plastic
+ ore_type = /obj/item/stack/ore/slag //No plastic or coal ore, so we use slag.
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
value_per_unit = 25 / SHEET_MATERIAL_AMOUNT
beauty_modifier = -0.01
armor_modifiers = list(MELEE = 1.5, BULLET = 1.1, LASER = 0.3, ENERGY = 0.5, BOMB = 1, BIO = 1, FIRE = 1.1, ACID = 1)
+ mineral_rarity = MATERIAL_RARITY_UNDISCOVERED //Nobody's found oil on lavaland yet.
+ points_per_unit = 4 / SHEET_MATERIAL_AMOUNT
/datum/material/plastic/on_accidental_mat_consumption(mob/living/carbon/eater, obj/item/food)
eater.reagents.add_reagent(/datum/reagent/plastic_polymers, rand(6, 8))
@@ -328,6 +362,8 @@ Unless you know what you're doing, only use the first three numbers. They're in
value_per_unit = 500 / SHEET_MATERIAL_AMOUNT
beauty_modifier = 0.4
armor_modifiers = list(MELEE = 1.5, BULLET = 1.5, LASER = 1.3, ENERGY = 1.3, BOMB = 1, BIO = 1, FIRE = 2.5, ACID = 1)
+ mineral_rarity = MATERIAL_RARITY_UNDISCOVERED //Doesn't naturally spawn on lavaland.
+ points_per_unit = 100 / SHEET_MATERIAL_AMOUNT
/datum/material/adamantine/on_accidental_mat_consumption(mob/living/carbon/victim, obj/item/source_item)
victim.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = 10)
@@ -345,6 +381,8 @@ Unless you know what you're doing, only use the first three numbers. They're in
strength_modifier = 1.2
armor_modifiers = list(MELEE = 1.5, BULLET = 1.5, LASER = 1.5, ENERGY = 1.5, BOMB = 1.5, BIO = 1.5, FIRE = 1.5, ACID = 1.5)
beauty_modifier = 0.5
+ mineral_rarity = MATERIAL_RARITY_UNDISCOVERED //Doesn't naturally spawn on lavaland.
+ points_per_unit = 100 / SHEET_MATERIAL_AMOUNT
/datum/material/mythril/on_applied_obj(atom/source, amount, material_flags)
. = ..()
diff --git a/code/datums/ruins.dm b/code/datums/ruins.dm
index 2a7b73d1f7e..703991f596e 100644
--- a/code/datums/ruins.dm
+++ b/code/datums/ruins.dm
@@ -6,17 +6,27 @@
How is there a wooden container filled with 18th century coinage in the middle of a lavawracked hellscape? \
It is clearly a mystery."
- var/unpickable = FALSE //If TRUE these won't be placed automatically (can still be forced or loaded with another ruin)
- var/always_place = FALSE //Will skip the whole weighting process and just plop this down, ideally you want the ruins of this kind to have no cost.
- var/placement_weight = 1 //How often should this ruin appear
- var/cost = 0 //Cost in ruin budget placement system
+ ///If TRUE these won't be placed automatically (can still be forced or loaded with another ruin)
+ var/unpickable = FALSE
+ ///Will skip the whole weighting process and just plop this down, ideally you want the ruins of this kind to have no cost.
+ var/always_place = FALSE
+ ///How often should this ruin appear
+ var/placement_weight = 1
+ ///Cost in ruin budget placement system
+ var/cost = 0
+ /// Cost in the ruin budget placement system associated with mineral spawning. We use a different budget for mineral sources like ore vents. For practical use see seedRuins
+ var/mineral_cost = 0
+ /// If TRUE, this ruin can be placed multiple times in the same map
var/allow_duplicates = TRUE
- var/list/always_spawn_with = null //These ruin types will be spawned along with it (where dependent on the flag) eg list(/datum/map_template/ruin/space/teleporter_space = SPACERUIN_Z)
- var/list/never_spawn_with = null //If this ruin is spawned these will not eg list(/datum/map_template/ruin/base_alternate)
-
+ ///These ruin types will be spawned along with it (where dependent on the flag) eg list(/datum/map_template/ruin/space/teleporter_space = SPACERUIN_Z)
+ var/list/always_spawn_with = null
+ ///If this ruin is spawned these will not eg list(/datum/map_template/ruin/base_alternate)
+ var/list/never_spawn_with = null
+ ///Static part of the ruin path eg "_maps\RandomRuins\LavaRuins\"
var/prefix = null
+ ///The dynamic part of the ruin path eg "lavaland_surface_ruinfile.dmm"
var/suffix = null
-
+ ///What flavor or ruin is this? eg ZTRAIT_SPACE_RUINS
var/ruin_type = null
/datum/map_template/ruin/New()
diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm
index a903d9444f4..452d8bf3578 100644
--- a/code/datums/ruins/icemoon.dm
+++ b/code/datums/ruins/icemoon.dm
@@ -7,7 +7,7 @@
ruin_type = ZTRAIT_ICE_RUINS
default_area = /area/icemoon/surface/outdoors/unexplored
has_ceiling = TRUE
- ceiling_turf = /turf/closed/mineral/random/snow/do_not_chasm
+ ceiling_turf = /turf/closed/mineral/snowmountain/do_not_chasm
ceiling_baseturfs = list(/turf/open/misc/asteroid/snow/icemoon/do_not_chasm)
// above ground only
@@ -179,3 +179,23 @@
id = "hotsprings"
description = "Just relax and take a dip, nothing will go wrong, I swear!"
suffix = "icemoon_underground_hotsprings.dmm"
+
+/datum/map_template/ruin/icemoon/underground/vent
+ name = "Icemoon Ore Vent"
+ id = "ore_vent_i"
+ description = "A vent that spews out ore. Seems to be a natural phenomenon." //Make this a subtype that only spawns medium and large vents. Some smalls will go to the top level.
+ suffix = "icemoon_underground_ore_vent.dmm"
+ allow_duplicates = TRUE
+ cost = 0
+ mineral_cost = 1
+ always_place = TRUE
+
+/datum/map_template/ruin/icemoon/ruin/vent
+ name = "Surface Icemoon Ore Vent"
+ id = "ore_vent_i"
+ description = "A vent that spews out ore. Seems to be a natural phenomenon. Smaller than the underground ones."
+ suffix = "icemoon_surface_ore_vent.dmm"
+ allow_duplicates = TRUE
+ cost = 0
+ mineral_cost = 1
+ always_place = TRUE
diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm
index b3bc5a4dc18..f66d06a4bba 100644
--- a/code/datums/ruins/lavaland.dm
+++ b/code/datums/ruins/lavaland.dm
@@ -287,6 +287,16 @@
allow_duplicates = TRUE
cost = 3
+/datum/map_template/ruin/lavaland/vent
+ name = "Ore Vent"
+ id = "ore_vent"
+ description = "A vent that spews out ore. Seems to be a natural phenomenon."
+ suffix = "lavaland_surface_ore_vent.dmm"
+ allow_duplicates = TRUE
+ cost = 0
+ mineral_cost = 1
+ always_place = TRUE
+
/datum/map_template/ruin/lavaland/watcher_grave
name = "Watchers' Grave"
id = "watcher-grave"
diff --git a/code/datums/wires/brm.dm b/code/datums/wires/brm.dm
new file mode 100644
index 00000000000..c00d7875035
--- /dev/null
+++ b/code/datums/wires/brm.dm
@@ -0,0 +1,14 @@
+/datum/wires/brm
+ holder_type = /obj/machinery/bouldertech/brm
+ proper_name = "Boulder Retrieval Matrix"
+
+/datum/wires/brm/New(atom/holder)
+ add_duds(1)
+ return ..()
+
+/datum/wires/brm/on_pulse(wire)
+ var/obj/machinery/bouldertech/brm/brm_holder = holder
+ if(brm_holder.panel_open)
+ return
+ brm_holder.toggle_auto_on()
+
diff --git a/code/game/area/areas/station/cargo.dm b/code/game/area/areas/station/cargo.dm
index faa9f2f6299..323a564c495 100644
--- a/code/game/area/areas/station/cargo.dm
+++ b/code/game/area/areas/station/cargo.dm
@@ -53,3 +53,7 @@
/area/station/cargo/miningoffice
name = "\improper Mining Office"
icon_state = "mining"
+
+/area/station/cargo/miningfoundry
+ name = "\improper Mining Foundry"
+ icon_state = "mining_foundry"
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm b/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
index b219062932a..de2f3d82275 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
@@ -3,20 +3,20 @@
/datum/orderable_item/consumables/survival_pen
item_path = /obj/item/reagent_containers/hypospray/medipen/survival
- cost_per_order = 500
+ cost_per_order = 250
/datum/orderable_item/consumables/luxury_pen
item_path = /obj/item/reagent_containers/hypospray/medipen/survival/luxury
- cost_per_order = 1000
+ cost_per_order = 750
/datum/orderable_item/consumables/medkit
item_path = /obj/item/storage/medkit/brute
- cost_per_order = 600
+ cost_per_order = 400
/datum/orderable_item/consumables/medkit_fire
item_path = /obj/item/storage/medkit/fire
desc = "For emergency magmatic burn relief."
- cost_per_order = 700
+ cost_per_order = 500
/datum/orderable_item/consumables/whiskey
item_path = /obj/item/reagent_containers/cup/glass/bottle/whiskey
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_golem.dm b/code/game/machinery/computer/orders/order_items/mining/order_golem.dm
index 891c6b9f358..cbd037230f2 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_golem.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_golem.dm
@@ -3,33 +3,33 @@
/datum/orderable_item/golem/mining_id
item_path = /obj/item/card/id/advanced/mining
- cost_per_order = 250
+ cost_per_order = 200
/datum/orderable_item/golem/science_goggles
item_path = /obj/item/clothing/glasses/science
- cost_per_order = 250
+ cost_per_order = 200
/datum/orderable_item/golem/monkeycubes
item_path = /obj/item/food/monkeycube
- cost_per_order = 300
+ cost_per_order = 250
/datum/orderable_item/golem/belt
item_path = /obj/item/storage/belt/utility
- cost_per_order = 350
+ cost_per_order = 300
/datum/orderable_item/golem/royal_cape
item_path = /obj/item/bedsheet/rd/royal_cape
- cost_per_order = 500
+ cost_per_order = 400
/datum/orderable_item/golem/grey_extract
item_path = /obj/item/slime_extract/grey
- cost_per_order = 1000
+ cost_per_order = 800
/datum/orderable_item/golem/trigger_guard
item_path = /obj/item/borg/upgrade/modkit/trigger_guard
- cost_per_order = 1700
+ cost_per_order = 750
/datum/orderable_item/golem/rnd_boards
item_path = /obj/item/storage/box/rndboards
- cost_per_order = 2000
+ cost_per_order = 1000
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_mining.dm b/code/game/machinery/computer/orders/order_items/mining/order_mining.dm
index 09bbeed2bed..686f8312671 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_mining.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_mining.dm
@@ -3,52 +3,52 @@
/datum/orderable_item/mining/marker_beacon
item_path = /obj/item/stack/marker_beacon/ten
- cost_per_order = 100
+ cost_per_order = 80
/datum/orderable_item/mining/skeleton_key
item_path = /obj/item/skeleton_key
- cost_per_order = 777
+ cost_per_order = 675
/datum/orderable_item/mining/mining_stabilizer
item_path = /obj/item/mining_stabilizer
- cost_per_order = 400
+ cost_per_order = 320
/datum/orderable_item/mining/fulton_core
item_path = /obj/item/fulton_core
- cost_per_order = 400
+ cost_per_order = 320
/datum/orderable_item/mining/mining_modsuit
item_path = /obj/item/mod/control/pre_equipped/mining
desc = "A mining-themed MODsuit that works best when in a mining environment."
- cost_per_order = 3000
+ cost_per_order = 2500
/datum/orderable_item/mining/mining_belt
item_path = /obj/item/storage/belt/mining
- cost_per_order = 500
+ cost_per_order = 450
/datum/orderable_item/mining/jaunter
item_path = /obj/item/wormhole_jaunter
- cost_per_order = 750
+ cost_per_order = 650
/datum/orderable_item/mining/crusher
item_path = /obj/item/kinetic_crusher
- cost_per_order = 750
+ cost_per_order = 650
/datum/orderable_item/mining/resonator
item_path = /obj/item/resonator
- cost_per_order = 800
+ cost_per_order = 710
/datum/orderable_item/mining/resonator_advanced
item_path = /obj/item/resonator/upgraded
- cost_per_order = 2500
+ cost_per_order = 2000
/datum/orderable_item/mining/mining_scanner
item_path = /obj/item/t_scanner/adv_mining_scanner
- cost_per_order = 800
+ cost_per_order = 675
/datum/orderable_item/mining/fulton
item_path = /obj/item/extraction_pack
- cost_per_order = 1000
+ cost_per_order = 800
/datum/orderable_item/mining/lazarus
item_path = /obj/item/lazarus_injector
@@ -69,40 +69,45 @@
/datum/orderable_item/mining/conscription_kit
item_path = /obj/item/storage/backpack/duffelbag/mining_conscript
desc = "A kit containing everything a crewmember needs to support a shaft miner in the field."
- cost_per_order = 1500
+ cost_per_order = 1200
/datum/orderable_item/mining/capsule
item_path = /obj/item/survivalcapsule
- cost_per_order = 400
+ cost_per_order = 350
/datum/orderable_item/mining/capsule/bathroom
item_path = /obj/item/survivalcapsule/bathroom
- cost_per_order = 375
+ cost_per_order = 300
/datum/orderable_item/mining/capsule_luxury
item_path = /obj/item/survivalcapsule/luxury
- cost_per_order = 3000
+ cost_per_order = 2300
/datum/orderable_item/mining/capsule_luxuryelite
item_path = /obj/item/survivalcapsule/luxuryelite
- cost_per_order = 10000
+ cost_per_order = 7000
/datum/orderable_item/mining/kheiralcuffs
item_path = /obj/item/kheiral_cuffs
- cost_per_order = 750
+ cost_per_order = 675
/datum/orderable_item/mining/bhop
item_path = /obj/item/clothing/shoes/bhop
- cost_per_order = 2500
+ cost_per_order = 2000
/datum/orderable_item/mining/hiking_boots
item_path = /obj/item/clothing/shoes/winterboots/ice_boots
- cost_per_order = 2500
+ cost_per_order = 2000
/datum/orderable_item/mining/style_meter
item_path = /obj/item/style_meter
- cost_per_order = 1500
+ cost_per_order = 1200
/datum/orderable_item/mining/weather_radio
item_path = /obj/item/radio/weather_monitor
- cost_per_order = 400
+ cost_per_order = 320
+
+/datum/orderable_item/mining/boulder_processing
+ item_path = /obj/item/boulder_beacon
+ desc = "A Bouldertech brand all-in-one boulder processing beacon. Each use will teleport in a component of a full boulder processing assembly line. Good for when you need to process additional boulders."
+ cost_per_order = 875
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_pka.dm b/code/game/machinery/computer/orders/order_items/mining/order_pka.dm
index 7ba37721e36..251343e6f8e 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_pka.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_pka.dm
@@ -3,19 +3,19 @@
/datum/orderable_item/accelerator/gun
item_path = /obj/item/gun/energy/recharge/kinetic_accelerator
- cost_per_order = 750
+ cost_per_order = 600
/datum/orderable_item/accelerator/range
item_path = /obj/item/borg/upgrade/modkit/range
- cost_per_order = 1000
+ cost_per_order = 675
/datum/orderable_item/accelerator/damage
item_path = /obj/item/borg/upgrade/modkit/damage
- cost_per_order = 1000
+ cost_per_order = 675
/datum/orderable_item/accelerator/cooldown
item_path = /obj/item/borg/upgrade/modkit/cooldown
- cost_per_order = 1000
+ cost_per_order = 675
/datum/orderable_item/accelerator/chasis
item_path = /obj/item/borg/upgrade/modkit/chassis_mod
@@ -35,8 +35,8 @@
/datum/orderable_item/accelerator/aoe_mobs
item_path = /obj/item/borg/upgrade/modkit/aoe/mobs
- cost_per_order = 2000
+ cost_per_order = 1500
/datum/orderable_item/accelerator/minebot_passthrough
item_path = /obj/item/borg/upgrade/modkit/minebot_passthrough
- cost_per_order = 1000
+ cost_per_order = 800
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_toys.dm b/code/game/machinery/computer/orders/order_items/mining/order_toys.dm
index cd1dbf5c674..5ce92f7b84f 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_toys.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_toys.dm
@@ -3,29 +3,29 @@
/datum/orderable_item/toys_drones/soap
item_path = /obj/item/soap/nanotrasen
- cost_per_order = 200
+ cost_per_order = 180
/datum/orderable_item/toys_drones/laser_pointer
item_path = /obj/item/laser_pointer
- cost_per_order = 300
+ cost_per_order = 275
/datum/orderable_item/toys_drones/facehugger
item_path = /obj/item/clothing/mask/facehugger/toy
- cost_per_order = 300
+ cost_per_order = 275
/datum/orderable_item/toys_drones/mining_drone
item_path = /mob/living/basic/mining_drone
- cost_per_order = 800
+ cost_per_order = 675
/datum/orderable_item/toys_drones/drone_health
item_path = /obj/item/mine_bot_upgrade/health
- cost_per_order = 400
+ cost_per_order = 350
/datum/orderable_item/toys_drones/drone_pka
item_path = /obj/item/borg/upgrade/modkit/cooldown/minebot
- cost_per_order = 600
+ cost_per_order = 525
/datum/orderable_item/toys_drones/drone_sentience
item_path = /obj/item/slimepotion/slime/sentience/mining
- cost_per_order = 1000
+ cost_per_order = 850
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index 8a80692f1a9..c93b105767a 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -484,3 +484,17 @@
if(item.ignition_effect(src, user))
ignite()
return ..()
+
+/obj/effect/decal/cleanable/rubble
+ name = "rubble"
+ desc = "A pile of rubble."
+ icon = 'icons/obj/debris.dmi'
+ icon_state = "rubble"
+ mergeable_decal = FALSE
+ beauty = -10
+
+/obj/effect/decal/cleanable/rubble/Initialize(mapload)
+ . = ..()
+ flick("rubble_bounce", src)
+ icon_state = "rubble"
+ update_appearance(UPDATE_ICON_STATE)
diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
index fff8ba665f0..067478eb1c7 100644
--- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
@@ -1564,6 +1564,37 @@
/obj/item/stack/sheet/plasteel = 2,
)
+/obj/item/circuitboard/machine/brm
+ name = "Boulder Retrieval Matrix"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/bouldertech/brm
+ req_components = list(
+ /datum/stock_part/capacitor = 1,
+ /datum/stock_part/scanning_module = 1,
+ /datum/stock_part/micro_laser = 1,
+ )
+
+/obj/item/circuitboard/machine/refinery
+ name = "Boulder Refinery"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/bouldertech/refinery
+ req_components = list(
+ /obj/item/reagent_containers/cup/beaker = 1,
+ /obj/item/assembly/igniter/condenser = 1,
+ /datum/stock_part/servo = 2,
+ /datum/stock_part/matter_bin = 1,
+ )
+
+/obj/item/circuitboard/machine/smelter
+ name = "Boulder Smelter"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/bouldertech/refinery/smelter
+ req_components = list(
+ /obj/item/assembly/igniter = 1,
+ /datum/stock_part/servo = 2,
+ /datum/stock_part/matter_bin = 2,
+ )
+
/obj/item/circuitboard/machine/shieldwallgen
name = "Shield Wall Generator"
greyscale_colors = CIRCUIT_COLOR_SCIENCE
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index f949e175686..6c4c8a881e9 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -155,6 +155,12 @@
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
+/obj/item/storage/bag/ore/attackby(obj/item/attacking_item, mob/user, params)
+ if(istype(attacking_item, /obj/item/boulder))
+ to_chat(user, span_warning("You can't fit \the [attacking_item] into \the [src]. Perhaps you should break it down first, or find an ore box."))
+ return TRUE
+ return ..()
+
/obj/item/storage/bag/ore/proc/pickup_ores(mob/living/user)
SIGNAL_HANDLER
diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm
new file mode 100644
index 00000000000..28d019af581
--- /dev/null
+++ b/code/game/objects/structures/lavaland/ore_vent.dm
@@ -0,0 +1,525 @@
+#define MAX_ARTIFACT_ROLL_CHANCE 10
+#define MINERAL_TYPE_OPTIONS_RANDOM 4
+#define OVERLAY_OFFSET_START 0
+#define OVERLAY_OFFSET_EACH 5
+
+/obj/structure/ore_vent
+ name = "ore vent"
+ desc = "An ore vent, brimming with underground ore. Scan with an advanced mining scanner to start extracting ore from it."
+ icon = 'icons/obj/mining_zones/terrain.dmi'
+ icon_state = "ore_vent"
+ move_resist = MOVE_FORCE_EXTREMELY_STRONG
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF //This thing will take a beating.
+ anchored = TRUE
+ density = TRUE
+ can_buckle = TRUE
+
+ /// Has this vent been tapped to produce boulders? Cannot be untapped.
+ var/tapped = FALSE
+ /// Has this vent been scanned by a mining scanner? Cannot be scanned again. Adds ores to the vent's description.
+ var/discovered = FALSE
+ /// Is this type of vent exempt from the 15 vent limit? Think the free iron/glass vent or boss vents. This also causes it to not roll for random mineral breakdown.
+ var/unique_vent = FALSE
+ /// What icon_state do we use when the ore vent has been tapped?
+ var/icon_state_tapped = "ore_vent_active"
+
+ /// A weighted list of what minerals are contained in this vent, with weight determining how likely each mineral is to be picked in produced boulders.
+ var/list/mineral_breakdown = list()
+ /// How many rolls on the mineral_breakdown list are made per boulder produced? EG: 3 rolls means 3 minerals per boulder, with order determining percentage.
+ var/minerals_per_boulder = 3
+ /// How many minerals are picked to be in the ore vent? These are added to the mineral_breakdown list.
+ var/minerals_per_breakdown = MINERAL_TYPE_OPTIONS_RANDOM
+ /// What size boulders does this vent produce?
+ var/boulder_size = BOULDER_SIZE_SMALL
+ /// Reference to this ore vent's NODE drone, to track wave success.
+ var/mob/living/basic/node_drone/node = null //this path is a placeholder.
+ /// String containing the formatted list of ores that this vent can produce, and who first discovered this vent.
+ var/ore_string = ""
+ /// Associated list of vent size weights to pick from.
+ var/list/ore_vent_options = list(
+ LARGE_VENT_TYPE = 3,
+ MEDIUM_VENT_TYPE = 5,
+ SMALL_VENT_TYPE = 7,
+ )
+
+ /// What string do we use to warn the player about the excavation event?
+ var/excavation_warning = "Are you ready to excavate this ore vent?"
+ ///Are we currently spawning mobs?
+ var/spawning_mobs = FALSE
+ /// A list of mobs that can be spawned by this vent during a wave defense event.
+ var/list/defending_mobs = list(
+ /mob/living/basic/mining/goliath,
+ /mob/living/basic/mining/legion/spawner_made,
+ /mob/living/basic/mining/watcher,
+ /mob/living/basic/mining/lobstrosity/lava,
+ /mob/living/basic/mining/brimdemon,
+ /mob/living/basic/mining/bileworm,
+ )
+ ///What items can be used to scan a vent?
+ var/static/list/scanning_equipment = list(
+ /obj/item/t_scanner/adv_mining_scanner,
+ /obj/item/mining_scanner,
+ )
+
+ /// What base icon_state do we use for this vent's boulders?
+ var/boulder_icon_state = "boulder"
+ /// Percent chance that this vent will produce an artifact boulder.
+ var/artifact_chance = 0
+ /// We use a cooldown to prevent the wave defense from being started multiple times.
+ COOLDOWN_DECLARE(wave_cooldown)
+ COOLDOWN_DECLARE(manual_vent_cooldown)
+
+
+/obj/structure/ore_vent/Initialize(mapload)
+ if(mapload)
+ generate_description()
+ register_context()
+ SSore_generation.possible_vents += src
+ boulder_icon_state = pick(list(
+ "boulder",
+ "rock",
+ "stone",
+ ))
+ if(tapped)
+ SSore_generation.processed_vents += src
+ icon_state = icon_state_tapped
+ update_appearance(UPDATE_ICON_STATE)
+ add_overlay(mutable_appearance('icons/obj/mining_zones/terrain.dmi', "well", ABOVE_MOB_LAYER, src, ABOVE_MOB_LAYER))
+ return ..()
+
+/obj/structure/ore_vent/Destroy()
+ SSore_generation.possible_vents -= src
+ node = null
+ if(tapped)
+ SSore_generation.processed_vents -= src
+ return ..()
+
+/obj/structure/ore_vent/attackby(obj/item/attacking_item, mob/user, params)
+ . = ..()
+ if(.)
+ return TRUE
+ if(!is_type_in_list(attacking_item, scanning_equipment))
+ return TRUE
+ if(tapped)
+ balloon_alert_to_viewers("vent tapped!")
+ return TRUE
+ scan_and_confirm(user)
+ return TRUE
+
+/obj/structure/ore_vent/attack_hand(mob/living/user, list/modifiers)
+ . = ..()
+ if(.)
+ return
+ if(!HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ return
+ if(!discovered)
+ to_chat(user, span_notice("You can't quite find the weakpoint of [src]... Perhaps it needs to be scanned first?"))
+ return
+ to_chat(user, span_notice("You start striking [src] with your golem's fist, attempting to dredge up a boulder..."))
+ for(var/i in 1 to 3)
+ if(do_after(user, boulder_size * 1 SECONDS, src))
+ user.apply_damage(20, STAMINA)
+ playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE)
+ produce_boulder()
+ visible_message(span_notice("You've successfully produced a boulder! Boy are your arms tired."))
+
+/obj/structure/ore_vent/attack_basic_mob(mob/user, list/modifiers)
+ . = ..()
+ if(!HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ return
+ produce_boulder()
+
+/obj/structure/ore_vent/is_buckle_possible(mob/living/target, force, check_loc)
+ . = ..()
+ if(tapped)
+ return FALSE
+ if(istype(target, /mob/living/basic/node_drone))
+ return TRUE
+
+/obj/structure/ore_vent/examine(mob/user)
+ . = ..()
+ if(discovered)
+ switch(boulder_size)
+ if(BOULDER_SIZE_SMALL)
+ . += span_notice("This vent produces [span_bold("small")] boulders containing [ore_string]")
+ if(BOULDER_SIZE_MEDIUM)
+ . += span_notice("This vent produces [span_bold("medium")] boulders containing [ore_string]")
+ if(BOULDER_SIZE_LARGE)
+ . += span_notice("This vent produces [span_bold("large")] boulders containing [ore_string]")
+ else
+ . += span_notice("This vent can be scanned with a [span_bold("Mining Scanner")].")
+
+/obj/structure/ore_vent/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
+ if(is_type_in_list(held_item, scanning_equipment))
+ context[SCREENTIP_CONTEXT_LMB] = "Scan vent"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/**
+ * Picks n types of materials to pack into a boulder created by this ore vent, where n is this vent's minerals_per_boulder.
+ * Then assigns custom_materials based on boulder_size, assigned via the ore_quantity_function
+ */
+/obj/structure/ore_vent/proc/create_mineral_contents()
+ var/list/refined_list = list()
+ for(var/iteration in 1 to minerals_per_boulder)
+ var/datum/material/material = pick_weight(mineral_breakdown)
+ refined_list[material] += ore_quantity_function(iteration)
+ return refined_list
+
+/**
+ * This proc is called when the ore vent is initialized, in order to determine what minerals boulders it spawns can contain.
+ * The materials available are determined by SSore_generation.ore_vent_minerals, which is a list of all minerals that can be contained in ore vents for a given cave generation.
+ * As a result, minerals use a weighted list as seen by ore_vent_minerals_default, which is then copied to ore_vent_minerals.
+ * Once a material is picked from the weighted list, it's removed from ore_vent_minerals, so that it can't be picked again and provided it's own internal weight used when assigning minerals to boulders spawned by this vent.
+ * May also be called after the fact, as seen in SSore_generation's initialize, to add more minerals to an existing vent.
+ *
+ * The above applies only when spawning in at mapload, otherwise we pick randomly from ore_vent_minerals_default.
+ *
+ * @params max_minerals How many minerals should be added to this vent? Defaults to MINERAL_TYPE_OPTIONS_RANDOM, which is 4.
+ * @params map_loading Is this vent being spawned in at mapload? If so, we use the ore_generation subsystem's ore_vent_minerals list to pick minerals. Otherwise, we pick randomly from ore_vent_minerals_default.
+ */
+/obj/structure/ore_vent/proc/generate_mineral_breakdown(max_minerals = MINERAL_TYPE_OPTIONS_RANDOM, map_loading = FALSE)
+ if(max_minerals < 1)
+ CRASH("generate_mineral_breakdown called with max_minerals < 1.")
+ for(var/iterator in 1 to max_minerals)
+ if(!SSore_generation.ore_vent_minerals.len && map_loading)
+ CRASH("No minerals left to pick from! We may have spawned too many ore vents in init, or added too many ores to the existing vents.")
+ var/datum/material/material
+ if(map_loading)
+ material = pick_weight(SSore_generation.ore_vent_minerals)
+ if(is_type_in_list(mineral_breakdown, material))
+ continue
+ if(map_loading)
+ SSore_generation.ore_vent_minerals[material] -= 1 //We remove 1 from the ore vent's mineral breakdown weight, so that it can't be picked again.
+ if(SSore_generation.ore_vent_minerals[material] <= 0)
+ SSore_generation.ore_vent_minerals -= material
+ else
+ material = pick_weight(SSore_generation.ore_vent_minerals_default)
+ mineral_breakdown[material] = rand(1, 4)
+
+
+/**
+ * Returns the quantity of mineral sheets in each ore vent's boulder contents roll.
+ * First roll can produce the most ore, with subsequent rolls scaling lower logarithmically.
+ * Inversely scales with ore_floor, so that the first roll is the largest, and subsequent rolls are smaller.
+ * (1 -> from 16 to 7 sheets of materials, and 3 -> from 8 to 6 sheets of materials on a small vent)
+ * This also means a large boulder can highroll a boulder with a full stack of 50 sheets of material.
+ * @params ore_floor The number of minerals already rolled. Used to scale the logarithmic function.
+ */
+/obj/structure/ore_vent/proc/ore_quantity_function(ore_floor)
+ return SHEET_MATERIAL_AMOUNT * round(boulder_size * (log(rand(1 + ore_floor, 4 + ore_floor)) ** -1))
+
+/**
+ * Starts the wave defense event, which will spawn a number of lavaland mobs based on the size of the ore vent.
+ * Called after the vent has been tapped by a scanning device.
+ * Will summon a number of waves of mobs, ending in the vent being tapped after the final wave.
+ */
+/obj/structure/ore_vent/proc/start_wave_defense()
+ AddComponent(\
+ /datum/component/spawner, \
+ spawn_types = defending_mobs, \
+ spawn_time = (10 SECONDS + (5 SECONDS * (boulder_size/5))), \
+ max_spawned = 10, \
+ max_spawn_per_attempt = (1 + (boulder_size/5)), \
+ spawn_text = "emerges to assault", \
+ spawn_distance = 4, \
+ spawn_distance_exclude = 3, \
+ )
+ var/wave_timer = 60 SECONDS
+ if(boulder_size == BOULDER_SIZE_MEDIUM)
+ wave_timer = 90 SECONDS
+ else if(boulder_size == BOULDER_SIZE_LARGE)
+ wave_timer = 150 SECONDS
+ COOLDOWN_START(src, wave_cooldown, wave_timer)
+ addtimer(CALLBACK(src, PROC_REF(handle_wave_conclusion)), wave_timer)
+ spawning_mobs = TRUE
+ icon_state = icon_state_tapped
+ update_appearance(UPDATE_ICON_STATE)
+
+/**
+ * Called when the wave defense event ends, after a variable amount of time in start_wave_defense.
+ *
+ * If the node drone is still alive, the ore vent is tapped and the ore vent will begin generating boulders.
+ * If the node drone is dead, the ore vent is not tapped and the wave defense can be reattempted.
+ *
+ * Also gives xp and mining points to all nearby miners in equal measure.
+ */
+/obj/structure/ore_vent/proc/handle_wave_conclusion()
+ SEND_SIGNAL(src, COMSIG_VENT_WAVE_CONCLUDED)
+ COOLDOWN_RESET(src, wave_cooldown)
+ particles = null
+ if(!QDELETED(node)) ///The Node Drone has survived the wave defense, and the ore vent is tapped.
+ tapped = TRUE
+ SSore_generation.processed_vents += src
+ balloon_alert_to_viewers("vent tapped!")
+ icon_state = icon_state_tapped
+ update_appearance(UPDATE_ICON_STATE)
+ else
+ visible_message(span_danger("\the [src] creaks and groans as the mining attempt fails, and the vent closes back up."))
+ icon_state = initial(icon_state)
+ update_appearance(UPDATE_ICON_STATE)
+ return FALSE //Bad end, try again.
+
+ for(var/mob/living/miner in range(7, src)) //Give the miners who are near the vent points and xp.
+ var/obj/item/card/id/user_id_card = miner.get_idcard(TRUE)
+ if(miner.stat <= SOFT_CRIT)
+ miner.mind?.adjust_experience(/datum/skill/mining, MINING_SKILL_BOULDER_SIZE_XP * boulder_size)
+ if(!user_id_card)
+ continue
+ var/point_reward_val = (MINER_POINT_MULTIPLIER * boulder_size) - MINER_POINT_MULTIPLIER // We remove the base value of discovering the vent
+ user_id_card.registered_account.mining_points += point_reward_val
+ user_id_card.registered_account.bank_card_talk("You have been awarded [point_reward_val] mining points for your efforts.")
+ node.pre_escape() //Visually show the drone is done and flies away.
+ add_overlay(mutable_appearance('icons/obj/mining_zones/terrain.dmi', "well", ABOVE_MOB_LAYER, src, GAME_PLANE))
+
+/**
+ * Called when the ore vent is tapped by a scanning device.
+ * Gives a readout of the ores available in the vent that gets added to the description,
+ * then asks the user if they want to start wave defense if it's already been discovered.
+ * @params user The user who tapped the vent.
+ * @params scan_only If TRUE, the vent will only scan, and not prompt to start wave defense. Used by the mech mineral scanner.
+ */
+/obj/structure/ore_vent/proc/scan_and_confirm(mob/living/user, scan_only = FALSE)
+ if(tapped)
+ balloon_alert_to_viewers("vent tapped!")
+ return
+ if(!COOLDOWN_FINISHED(src, wave_cooldown))
+ balloon_alert_to_viewers("protect the node drone!")
+ return
+ if(scan_only)
+ discovered = TRUE
+ generate_description(user)
+ balloon_alert_to_viewers("vent scanned!")
+ return
+ if(!discovered)
+ balloon_alert(user, "scanning...")
+ playsound(src, 'sound/items/timer.ogg', 30, TRUE)
+ if(do_after(user, 4 SECONDS))
+ discovered = TRUE
+ balloon_alert(user, "vent scanned!")
+ generate_description(user)
+ var/obj/item/card/id/user_id_card = user.get_idcard(TRUE)
+ if(isnull(user_id_card))
+ return
+ user_id_card.registered_account.mining_points += (MINER_POINT_MULTIPLIER)
+ user_id_card.registered_account.bank_card_talk("You've been awarded [MINER_POINT_MULTIPLIER] mining points for discovery of an ore vent.")
+ return
+
+ if(tgui_alert(user, excavation_warning, "Begin defending ore vent?", list("Yes", "No")) != "Yes")
+ return
+ if(!COOLDOWN_FINISHED(src, wave_cooldown))
+ return
+ //This is where we start spitting out mobs.
+ Shake(duration = 3 SECONDS)
+ node = new /mob/living/basic/node_drone(loc)
+ node.arrive(src)
+ RegisterSignal(node, COMSIG_QDELETING, PROC_REF(handle_wave_conclusion))
+ particles = new /particles/smoke/ash()
+
+ for(var/i in 1 to 5) // Clears the surroundings of the ore vent before starting wave defense.
+ for(var/turf/closed/mineral/rock in oview(i))
+ if(istype(rock, /turf/open/misc/asteroid) && prob(35)) // so it's too common
+ new /obj/effect/decal/cleanable/rubble(rock)
+ if(prob(100 - (i * 15)))
+ rock.gets_drilled(user, FALSE)
+ if(prob(50))
+ new /obj/effect/decal/cleanable/rubble(rock)
+ sleep(0.6 SECONDS)
+
+ start_wave_defense()
+
+/**
+ * Generates a description of the ore vent to ore_string, based on the minerals contained within it.
+ * Ore_string is passed to examine().
+ */
+/obj/structure/ore_vent/proc/generate_description(mob/user)
+ for(var/mineral_count in 1 to length(mineral_breakdown))
+ var/datum/material/resource = mineral_breakdown[mineral_count]
+ if(mineral_count == length(mineral_breakdown))
+ ore_string += "and " + span_bold(initial(resource.name)) + "."
+ else
+ ore_string += span_bold(initial(resource.name)) + ", "
+ if(user)
+ ore_string += "\nThis vent was first discovered by [user]."
+/**
+ * Adds floating temp_visual overlays to the vent, showcasing what minerals are contained within it.
+ * If undiscovered, adds a single overlay with the icon_state "unknown".
+ */
+/obj/structure/ore_vent/proc/add_mineral_overlays()
+ if(mineral_breakdown.len && !discovered)
+ var/obj/effect/temp_visual/mining_overlay/vent/new_mat = new /obj/effect/temp_visual/mining_overlay/vent(drop_location())
+ new_mat.icon_state = "unknown"
+ return
+ for(var/datum/material/selected_mat as anything in mineral_breakdown)
+ var/obj/effect/temp_visual/mining_overlay/vent/new_mat = new /obj/effect/temp_visual/mining_overlay/vent(drop_location())
+ new_mat.icon_state = selected_mat.name
+
+/**
+ * Here is where we handle producing a new boulder, based on the qualities of this ore vent.
+ * Returns the boulder produced.
+ * @params apply_cooldown Should we apply a cooldown to producing boulders? Default's false, used by manual boulder production (goldgrubs, golems, etc).
+ */
+/obj/structure/ore_vent/proc/produce_boulder(apply_cooldown = FALSE)
+ if(!COOLDOWN_FINISHED(src, manual_vent_cooldown))
+ return
+ var/obj/item/boulder/new_rock
+ if(prob(artifact_chance))
+ new_rock = new /obj/item/boulder/artifact(loc)
+ else
+ new_rock = new /obj/item/boulder(loc)
+ var/list/mats_list = create_mineral_contents()
+ Shake(duration = 1.5 SECONDS)
+ new_rock.set_custom_materials(mats_list)
+ new_rock.flavor_boulder(src)
+ if(apply_cooldown)
+ COOLDOWN_START(src, manual_vent_cooldown, 10 SECONDS)
+ return new_rock
+
+
+//comes with the station, and is already tapped.
+/obj/structure/ore_vent/starter_resources
+ name = "active ore vent"
+ desc = "An ore vent, brimming with underground ore. It's already supplying the station with iron and glass."
+ tapped = TRUE
+ discovered = TRUE
+ unique_vent = TRUE
+ boulder_size = BOULDER_SIZE_SMALL
+ mineral_breakdown = list(
+ /datum/material/iron = 50,
+ /datum/material/glass = 50,
+ )
+
+/obj/structure/ore_vent/random
+ /// Static list of ore vent types, for random generation.
+ var/static/list/ore_vent_types = list(
+ BOULDER_SIZE_SMALL,
+ BOULDER_SIZE_MEDIUM,
+ BOULDER_SIZE_LARGE,
+ )
+
+/obj/structure/ore_vent/random/Initialize(mapload)
+ . = ..()
+ if(!unique_vent && !mapload)
+ generate_mineral_breakdown(map_loading = mapload) //Default to random mineral breakdowns, unless this is a unique vent or we're still setting up default vent distribution.
+ generate_description()
+ artifact_chance = rand(0, MAX_ARTIFACT_ROLL_CHANCE)
+ var/string_boulder_size = pick_weight(ore_vent_options)
+ name = "[string_boulder_size] ore vent"
+ switch(string_boulder_size)
+ if(LARGE_VENT_TYPE)
+ boulder_size = BOULDER_SIZE_LARGE
+ if(mapload)
+ SSore_generation.ore_vent_sizes["large"] -= 1
+ if(MEDIUM_VENT_TYPE)
+ boulder_size = BOULDER_SIZE_MEDIUM
+ if(mapload)
+ SSore_generation.ore_vent_sizes["medium"] -= 1
+ if(SMALL_VENT_TYPE)
+ boulder_size = BOULDER_SIZE_SMALL
+ if(mapload)
+ SSore_generation.ore_vent_sizes["small"] -= 1
+ else
+ boulder_size = BOULDER_SIZE_SMALL //Might as well set a default value
+ name = initial(name)
+
+
+
+/obj/structure/ore_vent/random/icebox //The one that shows up on the top level of icebox
+ icon_state = "ore_vent_ice"
+ icon_state_tapped = "ore_vent_ice_active"
+ defending_mobs = list(
+ /mob/living/basic/mining/lobstrosity,
+ /mob/living/basic/mining/legion/snow/spawner_made,
+ /mob/living/simple_animal/hostile/asteroid/polarbear,
+ /mob/living/simple_animal/hostile/asteroid/wolf,
+ )
+ ore_vent_options = list(
+ "small",
+ )
+
+/obj/structure/ore_vent/random/icebox/lower
+ defending_mobs = list(
+ /mob/living/basic/mining/ice_whelp,
+ /mob/living/basic/mining/lobstrosity,
+ /mob/living/basic/mining/legion/snow/spawner_made,
+ /mob/living/basic/mining/ice_demon,
+ /mob/living/simple_animal/hostile/asteroid/polarbear,
+ /mob/living/simple_animal/hostile/asteroid/wolf,
+ )
+ ore_vent_options = list(
+ "small",
+ "medium",
+ "large",
+ )
+
+
+/obj/structure/ore_vent/boss
+ name = "menacing ore vent"
+ desc = "An ore vent, brimming with underground ore. This one has an evil aura about it. Better be careful."
+ unique_vent = TRUE
+ boulder_size = BOULDER_SIZE_LARGE
+ mineral_breakdown = list( // All the riches of the world, eeny meeny boulder room.
+ /datum/material/iron = 1,
+ /datum/material/glass = 1,
+ /datum/material/plasma = 1,
+ /datum/material/titanium = 1,
+ /datum/material/silver = 1,
+ /datum/material/gold = 1,
+ /datum/material/diamond = 1,
+ /datum/material/uranium = 1,
+ /datum/material/bluespace = 1,
+ /datum/material/plastic = 1,
+ )
+ defending_mobs = list(
+ /mob/living/simple_animal/hostile/megafauna/bubblegum,
+ /mob/living/simple_animal/hostile/megafauna/dragon,
+ /mob/living/simple_animal/hostile/megafauna/colossus,
+ )
+ excavation_warning = "Something big is nearby. Are you ABSOLUTELY ready to excavate this ore vent?"
+ ///What boss do we want to spawn?
+ var/summoned_boss = null
+
+/obj/structure/ore_vent/boss/Initialize(mapload)
+ . = ..()
+ summoned_boss = pick(defending_mobs)
+
+/obj/structure/ore_vent/boss/examine(mob/user)
+ . = ..()
+ var/boss_string = ""
+ switch(summoned_boss)
+ if(/mob/living/simple_animal/hostile/megafauna/bubblegum)
+ boss_string = "A giant fleshbound beast"
+ if(/mob/living/simple_animal/hostile/megafauna/dragon)
+ boss_string = "Sharp teeth and scales"
+ if(/mob/living/simple_animal/hostile/megafauna/colossus)
+ boss_string = "A giant, armored behemoth"
+ if(/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner)
+ boss_string = "A bloody drillmark"
+ if(/mob/living/simple_animal/hostile/megafauna/wendigo)
+ boss_string = "A chilling skull"
+ . += span_notice("[boss_string] is etched onto the side of the vent.")
+
+/obj/structure/ore_vent/boss/start_wave_defense()
+ // Completely override the normal wave defense, and just spawn the boss.
+ var/mob/living/simple_animal/hostile/megafauna/boss = new summoned_boss(loc)
+ RegisterSignal(boss, COMSIG_LIVING_DEATH, PROC_REF(handle_wave_conclusion))
+ COOLDOWN_START(src, wave_cooldown, INFINITY) //Basically forever
+ boss.say(boss.summon_line) //Pull their specific summon line to say. Default is meme text so make sure that they have theirs set already.
+
+/obj/structure/ore_vent/boss/handle_wave_conclusion()
+ node = new /mob/living/basic/node_drone(loc) //We're spawning the vent after the boss dies, so the player can just focus on the boss.
+ COOLDOWN_RESET(src, wave_cooldown)
+ return ..()
+
+/obj/structure/ore_vent/boss/icebox
+ icon_state = "ore_vent_ice"
+ icon_state_tapped = "ore_vent_ice_active"
+ defending_mobs = list(
+ /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner,
+ /mob/living/simple_animal/hostile/megafauna/wendigo,
+ /mob/living/simple_animal/hostile/megafauna/colossus,
+ )
+
+#undef MAX_ARTIFACT_ROLL_CHANCE
+#undef MINERAL_TYPE_OPTIONS_RANDOM
+#undef OVERLAY_OFFSET_START
+#undef OVERLAY_OFFSET_EACH
diff --git a/code/game/objects/structures/spawner.dm b/code/game/objects/structures/spawner.dm
index a3af72878c3..0f1b1bb57b5 100644
--- a/code/game/objects/structures/spawner.dm
+++ b/code/game/objects/structures/spawner.dm
@@ -64,7 +64,14 @@
/obj/structure/spawner/Initialize(mapload)
. = ..()
- AddComponent(spawner_type, mob_types, spawn_time, max_mobs, faction, spawn_text)
+ AddComponent(\
+ spawner_type, \
+ spawn_types = mob_types, \
+ spawn_time = spawn_time, \
+ max_spawned = max_mobs, \
+ faction = faction, \
+ spawn_text = spawn_text, \
+ )
/obj/structure/spawner/attack_animal(mob/living/simple_animal/user, list/modifiers)
if(faction_check(faction, user.faction, FALSE) && !user.client)
diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm
index d43356d26aa..02d894bed85 100644
--- a/code/game/turfs/closed/minerals.dm
+++ b/code/game/turfs/closed/minerals.dm
@@ -28,15 +28,21 @@
color = "#677" //SKYRAT EDIT ADDITION
var/turf/open/floor/plating/turf_type = /turf/open/misc/asteroid/airless
+ /// The path of the ore stack we spawn when we're mined.
var/obj/item/stack/ore/mineralType = null
+ /// If we spawn a boulder like on the gulag, we use this in lou of mineralType
+ var/obj/item/boulder/spawned_boulder = null
+ /// How much ore we spawn when we're mining a mineralType.
var/mineralAmt = 3
- var/scan_state = "" //Holder for the image we display when we're pinged by a mining scanner
- var/defer_change = 0
- // If true you can mine the mineral turf without tools.
+ ///Holder for the image we display when we're pinged by a mining scanner
+ var/scan_state = ""
+ ///If true, this turf will not call AfterChange during change_turf calls.
+ var/defer_change = FALSE
+ /// If true you can mine the mineral turf without tools.
var/weak_turf = FALSE
- ///How long it takes to mine this turf with tools, before the tool's speed and the user's skill modifier are factored in.
+ /// How long it takes to mine this turf with tools, before the tool's speed and the user's skill modifier are factored in.
var/tool_mine_speed = 4 SECONDS
- ///How long it takes to mine this turf without tools, if it's weak.
+ /// How long it takes to mine this turf without tools, if it's weak.
var/hand_mine_speed = 15 SECONDS
@@ -85,6 +91,70 @@
var/obj/item/stack/ore/the_ore = ore_type
scan_state = initial(the_ore.scan_state) // I SAID. SWITCH. TO. IT.
mineralType = ore_type // Everything else assumes that this is typed correctly so don't set it to non-ores thanks.
+ if(ispath(ore_type, /obj/item/boulder))
+ scan_state = "rock_Boulder" //Yes even the lowly boulder has a scan state
+ spawned_boulder = /obj/item/boulder/gulag_expanded
+
+/**
+ * Returns the distance to the nearest ore vent, where ore vents are tracked in SSore_generation's possible vents list.
+ * Returns 0 if we're not on lavaland, and as we're using get_dist, our range is limited to 127 tiles.
+ */
+/turf/closed/mineral/proc/prox_to_vent()
+ if(!is_mining_level(z))
+ return 0
+
+ var/distance = 128 // Max distance for a get_dist is 127
+ for(var/obj/structure/ore_vent/vent as anything in SSore_generation.possible_vents)
+ if(vent.unique_vent)
+ continue
+ if(vent.z != src.z)
+ continue //Silly
+ var/temp_distance = get_dist(src, vent)
+ if(temp_distance < distance)
+ distance = temp_distance
+ return distance
+
+/**
+ * Returns the chance of ore spawning in this turf, based on proximity to a vent.
+ * See mining defines for the chances and distance defines.
+ */
+/turf/closed/mineral/proc/proximity_ore_chance()
+ var/distance = prox_to_vent()
+ if(distance == 0) //We asked for a random chance but we could not successfully find a vent, so 0.
+ return 0
+
+ if(distance < VENT_PROX_VERY_HIGH)
+ return VENT_CHANCE_VERY_HIGH
+ if(distance < VENT_PROX_HIGH)
+ return VENT_CHANCE_HIGH
+ if(distance < VENT_PROX_MEDIUM)
+ return VENT_CHANCE_MEDIUM
+ if(distance < VENT_PROX_LOW)
+ return VENT_CHANCE_LOW
+ if(distance < VENT_PROX_FAR)
+ return VENT_CHANCE_FAR
+ return 0
+
+/**
+ * Returns the amount of ore to spawn in this turf, based on proximity to a vent.
+ * If for some reason we have a distance of zero (like being off mining Z levels), we return a random amount between 1 and 5 instead.
+ */
+/turf/closed/mineral/proc/scale_ore_to_vent()
+ var/distance = prox_to_vent()
+ if(distance == 0) // We're not on lavaland or similar failure condition
+ return rand(1,5)
+
+ if(distance < VENT_PROX_VERY_HIGH)
+ return 5
+ if(distance < VENT_PROX_HIGH)
+ return 4
+ if(distance < VENT_PROX_MEDIUM)
+ return 3
+ if(distance < VENT_PROX_LOW)
+ return 2
+ if(distance < VENT_PROX_FAR)
+ return 1
+ return 0
/turf/closed/mineral/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
if(turf_type)
@@ -145,9 +215,11 @@
/turf/closed/mineral/proc/gets_drilled(mob/user, give_exp = FALSE)
if(istype(user))
SEND_SIGNAL(user, COMSIG_MOB_MINED, src, give_exp)
- if (mineralType && (mineralAmt > 0))
+ if(mineralType && (mineralAmt > 0))
new mineralType(src, mineralAmt)
SSblackbox.record_feedback("tally", "ore_mined", mineralAmt, mineralType)
+ if(spawned_boulder)
+ new spawned_boulder(src)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(give_exp)
@@ -206,7 +278,10 @@
gets_drilled(give_exp = FALSE)
/turf/closed/mineral/random
+ /// What are the base odds that this turf spawns a mineral in the wall on initialize?
var/mineralChance = 13
+ /// Does this mineral determine it's random chance and mineral contents based on proximity to a vent? Overrides mineralChance and mineralAmt.
+ var/proximity_based = FALSE
/// Returns a list of the chances for minerals to spawn.
/// Will only run once, and will then be cached.
@@ -228,7 +303,10 @@
var/static/list/mineral_chances_by_type = list()
. = ..()
- if (prob(mineralChance))
+ var/dynamic_prob = mineralChance
+ if(proximity_based)
+ dynamic_prob = proximity_ore_chance() // We assign the chance of ore spawning based on probability.
+ if (prob(dynamic_prob))
var/list/spawn_chance_list = mineral_chances_by_type[type]
if (isnull(spawn_chance_list))
mineral_chances_by_type[type] = expand_weights(mineral_chances())
@@ -246,7 +324,8 @@
if(ismineralturf(T))
var/turf/closed/mineral/M = T
M.turf_type = src.turf_type
- M.mineralAmt = rand(1, 5)
+ M.mineralAmt = scale_ore_to_vent()
+ SSore_generation.post_ore_random["[M.mineralAmt]"] += 1
src = M
M.levelupdate()
else
@@ -254,12 +333,15 @@
T.levelupdate()
else
- Change_Ore(path, 1)
+ Change_Ore(path, FALSE)
Spread_Vein(path)
+ mineralAmt = scale_ore_to_vent()
+ SSore_generation.post_ore_manual["[mineralAmt]"] += 1
/turf/closed/mineral/random/high_chance
icon_state = "rock_highchance"
mineralChance = 25
+ proximity_based = FALSE
/turf/closed/mineral/random/high_chance/mineral_chances()
return list(
@@ -277,6 +359,7 @@
baseturfs = /turf/open/misc/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = TRUE
+ proximity_based = FALSE
/turf/closed/mineral/random/high_chance/volcanic/mineral_chances()
return list(
@@ -327,8 +410,8 @@
baseturfs = /turf/open/misc/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = TRUE
-
- mineralChance = 10
+ proximity_based = TRUE
+ mineralChance = 5
/turf/closed/mineral/random/volcanic/mineral_chances()
return list(
@@ -343,12 +426,6 @@
/turf/closed/mineral/gibtonite/volcanic = 4,
)
-/// A turf that can't we can't build openspace chasms on or spawn ruins in.
-/turf/closed/mineral/random/volcanic/do_not_chasm
- turf_type = /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins
- baseturfs = /turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins
- turf_flags = NO_RUINS
-
/turf/closed/mineral/random/snow
name = "snowy mountainside"
icon = MAP_SWITCH('icons/turf/walls/mountain_wall.dmi', 'icons/turf/mining.dmi')
@@ -361,6 +438,7 @@
baseturfs = /turf/open/misc/asteroid/snow/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
weak_turf = TRUE
+ proximity_based = TRUE
/turf/closed/mineral/random/snow/Change_Ore(ore_type, random = 0)
. = ..()
@@ -384,7 +462,7 @@
)
/// Near exact same subtype as parent, just used in ruins to prevent other ruins/chasms from spawning on top of it.
-/turf/closed/mineral/random/snow/do_not_chasm
+/turf/closed/mineral/snowmountain/do_not_chasm
turf_type = /turf/open/misc/asteroid/snow/icemoon/do_not_chasm
baseturfs = /turf/open/misc/asteroid/snow/icemoon/do_not_chasm
turf_flags = NO_RUINS
@@ -409,6 +487,7 @@
)
/turf/closed/mineral/random/snow/high_chance
+ proximity_based = FALSE
/turf/closed/mineral/random/snow/high_chance/mineral_chances()
return list(
@@ -426,13 +505,7 @@
/turf/closed/mineral/random/labormineral/mineral_chances()
return list(
- /obj/item/stack/ore/diamond = 1,
- /obj/item/stack/ore/gold = 8,
- /obj/item/stack/ore/iron = 95,
- /obj/item/stack/ore/plasma = 30,
- /obj/item/stack/ore/silver = 20,
- /obj/item/stack/ore/titanium = 8,
- /obj/item/stack/ore/uranium = 3,
+ /obj/item/boulder/gulag = 165,
/turf/closed/mineral/gibtonite = 2,
)
@@ -444,14 +517,7 @@
/turf/closed/mineral/random/labormineral/volcanic/mineral_chances()
return list(
- /obj/item/stack/ore/bluespace_crystal = 1,
- /obj/item/stack/ore/diamond = 1,
- /obj/item/stack/ore/gold = 8,
- /obj/item/stack/ore/iron = 95,
- /obj/item/stack/ore/plasma = 30,
- /obj/item/stack/ore/silver = 20,
- /obj/item/stack/ore/titanium = 8,
- /obj/item/stack/ore/uranium = 3,
+ /obj/item/boulder/gulag_expanded = 166,
/turf/closed/mineral/gibtonite/volcanic = 2,
)
@@ -471,14 +537,7 @@
/turf/closed/mineral/random/labormineral/ice/mineral_chances()
return list(
- /obj/item/stack/ore/bluespace_crystal = 1,
- /obj/item/stack/ore/diamond = 1,
- /obj/item/stack/ore/gold = 8,
- /obj/item/stack/ore/iron = 95,
- /obj/item/stack/ore/plasma = 30,
- /obj/item/stack/ore/silver = 20,
- /obj/item/stack/ore/titanium = 8,
- /obj/item/stack/ore/uranium = 3,
+ /obj/item/boulder/gulag = 168,
/turf/closed/mineral/gibtonite/ice/icemoon = 2,
)
diff --git a/code/game/turfs/open/asteroid.dm b/code/game/turfs/open/asteroid.dm
index b453fb0c4be..3a3a837968a 100644
--- a/code/game/turfs/open/asteroid.dm
+++ b/code/game/turfs/open/asteroid.dm
@@ -185,6 +185,10 @@ GLOBAL_LIST_EMPTY(dug_up_basalt)
/turf/open/misc/asteroid/basalt/lava_land_surface/no_ruins
turf_flags = NO_RUINS
+/// A turf that can't we can't build openspace chasms on or spawn ruins in.
+/turf/closed/mineral/volcanic/lava_land_surface/do_not_chasm
+ turf_flags = NO_RUINS
+
/turf/open/misc/asteroid/lowpressure
initial_gas_mix = OPENTURF_LOW_PRESSURE
baseturfs = /turf/open/misc/asteroid/lowpressure
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index b3a31a132e8..ca4ed9c8580 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -39,9 +39,10 @@
/obj/item/flashlight/seclite = 1,
/obj/item/knife/combat/survival = 1,
/obj/item/mining_voucher = 1,
- /obj/item/suit_voucher = 1,
+ /obj/item/suit_voucher = 1, //SKYRAT EDIT: Suit_Voucher is an addition
/obj/item/stack/marker_beacon/ten = 1,
- ) //SKYRAT EDIT: Suit_Voucher is an addition, one line up
+ /obj/item/t_scanner/adv_mining_scanner/lesser = 1,
+ )
belt = /obj/item/modular_computer/pda/shaftminer
ears = /obj/item/radio/headset/headset_cargo/mining
gloves = /obj/item/clothing/gloves/color/black
@@ -90,6 +91,7 @@
/obj/item/gun/energy/recharge/kinetic_accelerator = 2,
/obj/item/kinetic_crusher/compact = 1,
/obj/item/resonator/upgraded = 1,
+ /obj/item/t_scanner/adv_mining_scanner/lesser = 1,
)
box = /obj/item/storage/box/survival/mining/bonus
l_pocket = /obj/item/modular_computer/pda/shaftminer
diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm
index a7b9480a34e..d5ffa9f968d 100644
--- a/code/modules/mapping/ruins.dm
+++ b/code/modules/mapping/ruins.dm
@@ -63,8 +63,16 @@
new /obj/effect/landmark/ruin(center, src)
return center
-
-/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = list(/area/space), list/potentialRuins, clear_below = FALSE)
+/**
+ * Loads the ruins for a given z level.
+ * @param z_levels The z levels to load ruins on.
+ * @param budget The budget to spend on ruins. Compare against the cost of the ruins in /datum/map_template/ruin.
+ * @param whitelist A list of areas to allow ruins to be placed in.
+ * @param potentialRuins A list of ruins to choose from.
+ * @param clear_below Whether to clear the area below the ruin. Used for multiz ruins.
+ * @param mineral_budget The budget to spend on ruins that spawn ore vents. Map templates with vents have that defined by mineral_cost.
+ */
+/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = list(/area/space), list/potentialRuins, clear_below = FALSE, mineral_budget = 15)
if(!z_levels || !z_levels.len)
WARNING("No Z levels provided - Not generating ruins")
return
@@ -93,14 +101,14 @@
R.allow_duplicates = FALSE // no multiples for testing
R.always_place = !R.unpickable // unpickable ruin means it spawns as a set with another ruin
- if(R.cost > budget) //Why would you do that
+ if(R.cost > budget || R.mineral_cost > mineral_budget) //Why would you do that
continue
if(R.always_place)
forced_ruins[R] = -1
if(R.unpickable)
continue
ruins_available[R] = R.placement_weight
- while(budget > 0 && (ruins_available.len || forced_ruins.len))
+ while((budget > 0 || mineral_budget > 0) && (ruins_available.len || forced_ruins.len))
var/datum/map_template/ruin/current_pick
var/forced = FALSE
var/forced_z //If set we won't pick z level and use this one instead.
@@ -159,6 +167,7 @@
log_world("Failed to place [current_pick.name] ruin.")
else
budget -= current_pick.cost
+ mineral_budget -= current_pick.mineral_cost
if(!current_pick.allow_duplicates)
for(var/datum/map_template/ruin/R in ruins_available)
if(R.id == current_pick.id)
@@ -189,7 +198,7 @@
//Update the available list
for(var/datum/map_template/ruin/R in ruins_available)
- if(R.cost > budget)
+ if(R.cost > budget || R.mineral_cost > mineral_budget)
ruins_available -= R
log_world("Ruin loader finished with [budget] left to spend.")
diff --git a/code/modules/mining/boulder_processing/_boulder_processing.dm b/code/modules/mining/boulder_processing/_boulder_processing.dm
new file mode 100644
index 00000000000..5cf9544141a
--- /dev/null
+++ b/code/modules/mining/boulder_processing/_boulder_processing.dm
@@ -0,0 +1,349 @@
+/obj/machinery/bouldertech
+ name = "bouldertech brand refining machine"
+ desc = "You shouldn't be seeing this! And bouldertech isn't even a real company!"
+ icon = 'icons/obj/machines/mining_machines.dmi'
+ icon_state = "ore_redemption"
+ anchored = TRUE
+ density = TRUE
+
+ /// What is the efficiency of minerals produced by the machine?
+ var/refining_efficiency = 1
+ /// How many boulders can we process maximum per loop?
+ var/boulders_processing_max = 1
+ /// What boulder(s) are we holding?
+ var/list/boulders_contained = list()
+ /// How many boulders can we hold maximum?
+ var/boulders_held_max = 1
+ /// Does this machine have a mineral storage link to the silo?
+ var/holds_minerals = FALSE
+ /// What materials do we accept and process out of boulders? Removing iron from an iron/glass boulder would leave a boulder with glass.
+ var/list/processable_materials = list()
+ /// If we get a boulder with one of these inside, we'll drop it back out.
+ var/static/list/drop_if_contained = list(
+ /obj/item/relic,
+ )
+
+ /// What sound plays when a thing operates?
+ var/usage_sound = 'sound/machines/mining/wooping_teleport.ogg'
+ /// Cooldown associated with the usage_sound played.
+ COOLDOWN_DECLARE(sound_cooldown)
+
+ /// Silo link to it's materials list.
+ var/datum/component/remote_materials/silo_materials
+ ///Does this machine hold mining points?
+ var/holds_mining_points = FALSE
+ /// Mining points held by the machine for miners.
+ var/points_held = 0
+
+/obj/machinery/bouldertech/Initialize(mapload)
+ . = ..()
+ register_context()
+ if(holds_minerals)
+ silo_materials = AddComponent(/datum/component/remote_materials, mapload)
+
+/obj/machinery/bouldertech/LateInitialize()
+ . = ..()
+ if(!holds_minerals)
+ return
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
+
+/obj/machinery/bouldertech/Destroy()
+ boulders_contained = null
+ silo_materials = null
+ return ..()
+
+/obj/machinery/bouldertech/update_icon_state()
+ . = ..()
+ if(anchored)
+ icon_state ="[initial(icon_state)]"
+ else
+ icon_state ="[initial(icon_state)]-off"
+
+/obj/machinery/bouldertech/wrench_act(mob/living/user, obj/item/tool)
+ . = ITEM_INTERACT_BLOCKING
+ if(default_unfasten_wrench(user, tool, time = 1.5 SECONDS) == SUCCESSFUL_UNFASTEN)
+ update_appearance(UPDATE_ICON_STATE)
+ START_PROCESSING(SSmachines, src)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/bouldertech/screwdriver_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-off", initial(icon_state), tool))
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/bouldertech/crowbar_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(default_pry_open(tool, close_after_pry = TRUE, closed_density = FALSE))
+ return ITEM_INTERACT_SUCCESS
+ if(default_deconstruction_crowbar(tool))
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/bouldertech/attackby(obj/item/attacking_item, mob/user, params)
+ if(holds_minerals && istype(attacking_item, /obj/item/boulder))
+ var/obj/item/boulder/my_boulder = attacking_item
+ update_boulder_count()
+ if(!accept_boulder(my_boulder))
+ balloon_alert_to_viewers("full!")
+ return
+ balloon_alert_to_viewers("accepted")
+ START_PROCESSING(SSmachines, src)
+ return TRUE
+ if(istype(attacking_item, /obj/item/card/id) && holds_mining_points)
+ if(points_held <= 0)
+ balloon_alert_to_viewers("no points to claim!")
+ if(!COOLDOWN_FINISHED(src, sound_cooldown))
+ return TRUE
+ COOLDOWN_START(src, sound_cooldown, 1.5 SECONDS)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 30, FALSE)
+ return FALSE
+ var/obj/item/card/id/id_card = attacking_item
+ var/amount = tgui_input_number(user, "How many mining points do you wish to claim? ID Balance: [id_card.registered_account.mining_points], stored mining points: [points_held]", "Transfer Points", max_value = points_held, min_value = 0, round_value = 1)
+ if(!amount)
+ return TRUE
+ if(amount > points_held)
+ amount = points_held
+ id_card.registered_account.mining_points += amount
+ points_held = round(points_held - amount)
+ to_chat(user, span_notice("You claim [amount] mining points from \the [src] to [id_card]."))
+ return TRUE
+ return ..()
+
+/obj/machinery/bouldertech/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ if(!anchored)
+ balloon_alert(user, "anchor first!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ if(!holds_minerals)
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+ if(!length(boulders_contained))
+ balloon_alert_to_viewers("No boulders to remove!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ remove_boulder(pick(boulders_contained))
+ return SECONDARY_ATTACK_CONTINUE_CHAIN
+
+/obj/machinery/bouldertech/deconstruct(disassembled)
+ . = ..()
+ if(length(contents))
+ for(var/obj/item/boulder/boulder in contents)
+ remove_boulder(boulder)
+
+/obj/machinery/bouldertech/process()
+ if(!anchored)
+ return PROCESS_KILL
+ var/stop_processing_check = FALSE
+ var/boulders_concurrent = boulders_processing_max ///How many boulders can we touch this process() call
+ for(var/obj/item/potential_boulder as anything in boulders_contained)
+ if(QDELETED(potential_boulder))
+ boulders_contained -= potential_boulder
+ break
+ if(boulders_concurrent <= 0)
+ break //Try again next time
+
+ if(!istype(potential_boulder, /obj/item/boulder))
+ potential_boulder.forceMove(drop_location())
+ CRASH("\The [src] had a non-boulder in it's boulders contained!")
+
+ var/obj/item/boulder/boulder = potential_boulder
+ if(boulder.durability < 0)
+ CRASH("\The [src] had a boulder with negative durability!")
+ if(!check_for_processable_materials(boulder.custom_materials)) //Checks for any new materials we can process.
+ boulders_concurrent-- //We count skipped boulders
+ remove_boulder(boulder)
+ continue
+ boulders_concurrent--
+ boulder.durability-- //One less durability to the processed boulder.
+ if(COOLDOWN_FINISHED(src, sound_cooldown))
+ COOLDOWN_START(src, sound_cooldown, 1.5 SECONDS)
+ playsound(loc, usage_sound, 29, FALSE, SHORT_RANGE_SOUND_EXTRARANGE) //This can get annoying. One play per process() call.
+ stop_processing_check = TRUE
+ if(boulder.durability <= 0)
+ breakdown_boulder(boulder) //Crack that bouwlder open!
+ continue
+ if(!stop_processing_check)
+ playsound(src.loc, 'sound/machines/ping.ogg', 50, FALSE)
+ return PROCESS_KILL
+
+
+/obj/machinery/bouldertech/CanAllowThrough(atom/movable/mover, border_dir)
+ if(!anchored)
+ return FALSE
+ if(boulders_contained.len >= boulders_held_max)
+ return FALSE
+ if(istype(mover, /obj/item/boulder))
+ var/obj/item/boulder/boulder = mover
+ return boulder.can_get_processed()
+ return ..()
+
+/obj/machinery/bouldertech/examine(mob/user)
+ . = ..()
+ if(holds_mining_points)
+ . += span_notice("The machine reads that it has [span_bold("[points_held] mining points")] stored. Swipe an ID to claim them.")
+
+/**
+ * Accepts a boulder into the machinery, then converts it into minerals.
+ * If the boulder can be fully processed by this machine, we take the materials, insert it into the silo, and destroy the boulder.
+ * If the boulder has materials left, we make a copy of the boulder to hold the processable materials, take the processable parts, and eject the original boulder.
+ * @param chosen_boulder The boulder to being breaking down into minerals.
+ */
+/obj/machinery/bouldertech/proc/breakdown_boulder(obj/item/boulder/chosen_boulder)
+ if(QDELETED(chosen_boulder))
+ return FALSE
+ if(chosen_boulder.loc != src)
+ return FALSE
+ if(!length(chosen_boulder.custom_materials))
+ qdel(chosen_boulder)
+ playsound(loc, 'sound/weapons/drill.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ update_boulder_count()
+ return FALSE
+ if(isnull(silo_materials))
+ return FALSE
+
+ //here we loop through the boulder's ores
+ var/list/processable_ores = list()
+ var/tripped = FALSE
+ //If a material is in the boulder's custom_materials, but not in the processable_materials list, we add it to the processable_ores list to add back to a leftover boulder.
+ for(var/datum/material/possible_mat as anything in chosen_boulder.custom_materials)
+ if(!is_type_in_list(possible_mat, processable_materials))
+ continue
+ var/quantity = chosen_boulder.custom_materials[possible_mat]
+ points_held = round((points_held + (quantity * possible_mat.points_per_unit)) * MINING_POINT_MACHINE_MULTIPLIER) // put point total here into machine
+ processable_ores += possible_mat
+ processable_ores[possible_mat] = quantity
+ chosen_boulder.custom_materials -= possible_mat //Remove it from the boulder now that it's tracked
+ tripped = TRUE
+ if(!tripped)
+ remove_boulder(chosen_boulder)
+ say("Nothing to process!")
+ return FALSE //we shouldn't spend more time processing a boulder with contents we don't care about.
+ use_power(BASE_MACHINE_ACTIVE_CONSUMPTION)
+ check_for_boosts() //Calls the relevant behavior for boosting the machine's efficiency, if able.
+ var/is_artifact = (istype(chosen_boulder, /obj/item/boulder/artifact)) //We need to know if it's an artifact so we can carry it over to the new boulder.
+ var/obj/item/boulder/disposable_boulder = new (src)
+ disposable_boulder.custom_materials = processable_ores
+ silo_materials.insert_item(disposable_boulder, refining_efficiency)
+ qdel(disposable_boulder)
+
+ refining_efficiency = initial(refining_efficiency) //Reset refining efficiency to 100% now that we've processed any relevant ores.
+ if(!length(chosen_boulder.custom_materials))
+ playsound(loc, 'sound/weapons/drill.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ if(is_artifact)
+ points_held = round((points_held + MINER_POINT_MULTIPLIER) * MINING_POINT_MACHINE_MULTIPLIER) /// Artifacts give bonus points!
+ chosen_boulder.break_apart()
+ update_boulder_count()
+ return TRUE //We've processed all the materials in the boulder, so we can just destroy it in break_apart.
+
+ chosen_boulder.restart_processing_cooldown() //So that we don't pick it back up!
+ chosen_boulder.durability = rand(chosen_boulder.boulder_size, chosen_boulder.boulder_size + BOULDER_SIZE_SMALL) //Reset durability to a random value between the boulder's size and a little more.
+ remove_boulder(chosen_boulder)
+ return TRUE
+
+/**
+ * Accepts a boulder into the machine. Used when a boulder is first placed into the machine.
+ * @param new_boulder The boulder to be accepted.
+ */
+/obj/machinery/bouldertech/proc/accept_boulder(obj/item/boulder/new_boulder)
+ if(isnull(new_boulder))
+ return FALSE
+ if(boulders_contained.len >= boulders_held_max) //Full already
+ return FALSE
+ if(!istype(new_boulder)) //Can't be processed
+ return FALSE
+ if(!new_boulder.custom_materials) //Shouldn't happen, but just in case.
+ qdel(new_boulder)
+ playsound(loc, 'sound/weapons/drill.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ return FALSE
+ new_boulder.forceMove(src)
+ boulders_contained += new_boulder
+ SSore_generation.available_boulders -= new_boulder
+ START_PROCESSING(SSmachines, src) //Starts processing if we aren't already.
+ return TRUE
+
+/**
+ * Ejects a boulder from the machine. Used when a boulder is finished processing, or when a boulder can't be processed.
+ * @param drop_turf The location to eject the boulder to. If null, it will eject to the machine's drop_location().
+ * @param specific_boulder The boulder to be ejected.
+ */
+/obj/machinery/bouldertech/proc/remove_boulder(obj/item/boulder/specific_boulder, turf/drop_turf = null)
+ if(isnull(specific_boulder))
+ CRASH("remove_boulder() called with no boulder!")
+ if(!length(specific_boulder.custom_materials))
+ qdel(specific_boulder)
+ update_boulder_count()
+ playsound(loc, 'sound/weapons/drill.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ return FALSE
+ specific_boulder.restart_processing_cooldown() //Reset the cooldown so we don't pick it back up by the same machine.
+ if(isturf(drop_turf))
+ specific_boulder.forceMove(drop_turf)
+ else
+ specific_boulder.forceMove(drop_location())
+ if(!update_boulder_count())
+ return TRUE
+ STOP_PROCESSING(SSmachines, src)
+ balloon_alert_to_viewers("clear!")
+ playsound(loc, 'sound/machines/ping.ogg', 50, FALSE)
+ return TRUE
+
+/**
+ * Getter proc to determine how many boulders are contained in the machine.
+ * Also adds their reference to the boulders_contained list.
+ */
+/obj/machinery/bouldertech/proc/update_boulder_count()
+ boulders_contained = list()
+ for(var/obj/item/boulder/boulder in contents)
+ boulders_contained += boulder
+ return boulders_contained.len
+
+/obj/machinery/bouldertech/proc/on_entered(datum/source, atom/movable/atom_movable)
+ SIGNAL_HANDLER
+ INVOKE_ASYNC(src, PROC_REF(accept_boulder), atom_movable)
+
+/**
+ * Looks for a boost to the machine's efficiency, and applies it if found.
+ * Applied more on the chemistry integration but can be used for other things if desired.
+ */
+/obj/machinery/bouldertech/proc/check_for_boosts()
+ refining_efficiency = initial(refining_efficiency) //Reset refining efficiency to 100%.
+
+/**
+ * Checks if a custom_material is in a list of processable materials in the machine.
+ * @param list/custom_material A list of materials, presumably taken from a boulder. If a material that this machine can process is in this list, it will return true, inclusively.
+ */
+/obj/machinery/bouldertech/proc/check_for_processable_materials(list/boulder_mats)
+ for(var/material as anything in boulder_mats)
+ if(is_type_in_list(material, processable_materials))
+ return TRUE
+ return FALSE
+
+///Beacon to launch a new mining setup when activated. For testing and speed!
+/obj/item/boulder_beacon
+ name = "boulder beacon"
+ desc = "N.T. approved boulder beacon, toss it down and you will have a full bouldertech mining station."
+ icon = 'icons/obj/machines/floor.dmi'
+ icon_state = "floor_beacon"
+ /// Number of activations left on this beacon. Uses will be removed as the beacon is used and each triggers a different machine to be spawned from it.
+ var/uses = 3
+
+/obj/item/boulder_beacon/attack_self()
+ loc.visible_message(span_warning("\The [src] begins to beep loudly!"))
+ addtimer(CALLBACK(src, PROC_REF(launch_payload)), 1 SECONDS)
+
+/**
+ * Spawns a new bouldertech machine from the beacon, then removes a use from the beacon.
+ * Use one spawns a BRM teleporter, then a refinery, and lastly a smelter.
+ */
+/obj/item/boulder_beacon/proc/launch_payload()
+ playsound(src, SFX_SPARKS, 80, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ switch(uses)
+ if(3)
+ new /obj/machinery/bouldertech/brm(drop_location())
+ if(2)
+ new /obj/machinery/bouldertech/refinery(drop_location())
+ if(1)
+ new /obj/machinery/bouldertech/refinery/smelter(drop_location())
+ qdel(src)
+ uses--
diff --git a/code/modules/mining/boulder_processing/boulder.dm b/code/modules/mining/boulder_processing/boulder.dm
new file mode 100644
index 00000000000..77260eef088
--- /dev/null
+++ b/code/modules/mining/boulder_processing/boulder.dm
@@ -0,0 +1,288 @@
+
+
+/**
+ * The objects that ore vents produce, which is refined into minerals.
+ */
+/obj/item/boulder
+ name = "boulder"
+ desc = "This rocks."
+ icon_state = "ore"
+ icon = 'icons/obj/ore.dmi'
+ item_flags = NO_MAT_REDEMPTION
+ throw_range = 2
+ throw_speed = 0.5
+ drag_slowdown = 1.5 // It's still a big rock.
+ ///When a refinery machine is working on this boulder, we'll set this. Re reset when the process is finished, but the boulder may still be refined/operated on further.
+ var/obj/machinery/bouldertech/processed_by = null
+ /// How many steps of refinement this boulder has gone through. Starts at 5-8, goes down one each machine process.
+ var/durability = 5
+ /// What was the size of the boulder when it was spawned? This is used for inheiriting the icon_state.
+ var/boulder_size = BOULDER_SIZE_SMALL
+ /// Used in inheriting the icon_state from our parent vent in update_icon.
+ var/boulder_string = "boulder"
+ /// Cooldown used to prevents boulders from getting processed back into a machine immediately after being processed.
+ COOLDOWN_DECLARE(processing_cooldown)
+
+ /// Static list of all minerals to populate gulag boulders with.
+ var/list/static/gulag_minerals = list(
+ /datum/material/diamond = 1,
+ /datum/material/gold = 8,
+ /datum/material/iron = 95,
+ /datum/material/plasma = 30,
+ /datum/material/silver = 20,
+ /datum/material/titanium = 8,
+ /datum/material/uranium = 3,
+ )
+ /// Static list of all minerals to populate gulag boulders with, but with bluespace added where safe.
+ var/list/static/expanded_gulag_minerals = list(
+ /datum/material/bluespace = 1,
+ /datum/material/diamond = 1,
+ /datum/material/gold = 8,
+ /datum/material/iron = 94,
+ /datum/material/plasma = 30,
+ /datum/material/silver = 20,
+ /datum/material/titanium = 8,
+ /datum/material/uranium = 3,
+ )
+
+/obj/item/boulder/Initialize(mapload)
+ . = ..()
+ register_context()
+ AddComponent(/datum/component/two_handed, require_twohands = TRUE, force_unwielded = 0, force_wielded = 5) //Heavy as all hell, it's a boulder, dude.
+
+/obj/item/boulder/Destroy(force)
+ SSore_generation.available_boulders -= src
+ processed_by = null
+ return ..()
+
+/obj/item/boulder/examine(mob/user)
+ . = ..()
+ . += span_notice("This boulder would take [durability] more steps to refine or break.")
+
+/obj/item/boulder/examine_more(mob/user)
+ . = ..()
+ . += span_notice("[span_bold("Boulders")] can either be cracked open by [span_bold("mining tools")], or processed into sheets with [span_bold("refineries or smelters")]. Undisturbed boulders can be collected by the [span_bold("BRM")].")
+
+/obj/item/boulder/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
+ if(held_item?.tool_behaviour == TOOL_MINING || HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ context[SCREENTIP_CONTEXT_RMB] = "Crush boulder into ore"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/obj/item/boulder/attack_self(mob/user, list/modifiers)
+ . = ..()
+ if(.)
+ return
+ if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ manual_process(null, user, INATE_BOULDER_SPEED_MULTIPLIER)
+ return
+
+/obj/item/boulder/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ manual_process(null, user, INATE_BOULDER_SPEED_MULTIPLIER)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/item/boulder/CanAllowThrough(atom/movable/mover, border_dir)
+ . = ..()
+ if(istype(mover, /obj/item/boulder)) //This way, boulders can only go one at a time on conveyor belts, but everyone else can go through.
+ return FALSE
+
+/obj/item/boulder/attackby_secondary(obj/item/weapon, mob/user, params)
+ . = ..()
+ if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER) || HAS_TRAIT(weapon, TRAIT_BOULDER_BREAKER))
+ manual_process(weapon, user, INATE_BOULDER_SPEED_MULTIPLIER)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ if(weapon.tool_behaviour == TOOL_MINING)
+ manual_process(weapon, user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ return ..()
+
+/obj/item/boulder/attack_basic_mob(mob/user, list/modifiers)
+ . = ..()
+ if(.)
+ return
+ if(HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ manual_process(null, user, INATE_BOULDER_SPEED_MULTIPLIER) //A little hacky but it works around the speed of the blackboard task selection process for now.
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/item/boulder/update_icon_state()
+ . = ..()
+ switch(boulder_size)
+ if(BOULDER_SIZE_SMALL)
+ icon_state = "[boulder_string]_small"
+ if(BOULDER_SIZE_MEDIUM)
+ icon_state = "[boulder_string]_medium"
+ if(BOULDER_SIZE_LARGE)
+ icon_state = "[boulder_string]_large"
+ else
+ icon_state = "[boulder_string]_small"
+
+/**
+ * This is called when a boulder is processed by a mob or tool, and reduces the durability of the boulder.
+ * @param obj/item/weapon The weapon that is being used to process the boulder, that we pull toolspeed from. If null, we use the override_speed_multiplier instead.
+ * @param mob/living/user The mob that is processing the boulder.
+ * @param override_speed_multiplier The speed multiplier to use if weapon is null. The do_after will take 2 * this value seconds to complete.
+ * @param continued Whether or not this is a continued process, or the first one. If true, we don't play the "You swing at the boulder" message.
+ */
+/obj/item/boulder/proc/manual_process(obj/item/weapon, mob/living/user, override_speed_multiplier, continued = FALSE)
+ var/process_speed = 0
+ //Handle weapon conditions.
+ if(weapon)
+ if(HAS_TRAIT(weapon, TRAIT_INSTANTLY_PROCESSES_BOULDERS))
+ durability = 0
+ process_speed = weapon.toolspeed
+ weapon.play_tool_sound(src, 50)
+ if(!continued)
+ to_chat(user, span_notice("You swing at \the [src]..."))
+
+ // Handle user conditions/override conditions.
+ else if (override_speed_multiplier || HAS_TRAIT(user, TRAIT_BOULDER_BREAKER))
+ if(user)
+ if(HAS_TRAIT(user, TRAIT_INSTANTLY_PROCESSES_BOULDERS))
+ durability = 0
+ else if(override_speed_multiplier)
+ process_speed = override_speed_multiplier
+ else
+ process_speed = INATE_BOULDER_SPEED_MULTIPLIER
+ playsound(src, 'sound/effects/rocktap1.ogg', 50)
+ if(!continued)
+ to_chat(user, span_notice("You scrape away at \the [src]... speed is [process_speed]."))
+ else
+ CRASH("No weapon, acceptable user, or override speed multiplier passed to manual_process()")
+ if(durability > 0)
+ if(!do_after(user, (2 * process_speed SECONDS), target = src))
+ return
+ if(!user.Adjacent(src))
+ return
+ durability--
+ user.apply_damage(4, STAMINA)
+ if(durability <= 0)
+ convert_to_ore()
+ to_chat(user, span_notice("You finish working on \the [src], and it crumbles into ore."))
+ playsound(src, 'sound/effects/rock_break.ogg', 50)
+ user.mind?.adjust_experience(/datum/skill/mining, MINING_SKILL_BOULDER_SIZE_XP * 0.2)
+ qdel(src)
+ return
+ var/msg = (durability == 1 ? "is crumbling!" : "looks weaker!")
+ to_chat(user, span_notice("\The [src] [msg]"))
+ manual_process(weapon, user, override_speed_multiplier, continued = TRUE)
+
+/**
+ * This function is called while breaking boulders manually, and drops ore based on the boulder's mineral content.
+ * Quantity of ore spawned here is 1 less than if the boulder was processed by a machine, but clamped at 10 maximum, 1 minimum.
+ */
+/obj/item/boulder/proc/convert_to_ore()
+ for(var/datum/material/picked in custom_materials)
+ var/obj/item/stack/ore/cracked_ore // Take the associated value and convert it into ore stacks...
+ var/quantity = clamp(round((custom_materials[picked] - SHEET_MATERIAL_AMOUNT)/SHEET_MATERIAL_AMOUNT), 1, 10) //but less resources than if they processed it by hand.
+
+ var/cracked_ore_type = picked.ore_type
+ if(isnull(cracked_ore_type))
+ stack_trace("boulder found containing material type [picked.type] with no set ore_type")
+ continue
+ cracked_ore = new cracked_ore_type (drop_location(), quantity)
+ SSblackbox.record_feedback("tally", "ore_mined", quantity, cracked_ore)
+
+/**
+ * Handles the boulder's processing cooldown to check if it's ready to be processed again.
+ */
+/obj/item/boulder/proc/can_get_processed()
+ return COOLDOWN_FINISHED(src, processing_cooldown)
+
+/**
+ * Starts the boulder's processing cooldown.
+ */
+/obj/item/boulder/proc/restart_processing_cooldown()
+ COOLDOWN_START(src, processing_cooldown, 2 SECONDS)
+
+/**
+ * Moves boulder contents to the drop location, and then deletes the boulder.
+ */
+/obj/item/boulder/proc/break_apart()
+ var/list/quips = list("Clang!", "Crack!", "Bang!", "Clunk!", "Clank!")
+ if(length(contents))
+ visible_message(span_notice("[pick(quips)] Something falls out of \the [src]!"))
+ playsound(loc, 'sound/effects/picaxe1.ogg', 60, FALSE)
+ for(var/obj/item/content as anything in contents)
+ content.forceMove(get_turf(src))
+ qdel(src)
+
+/**
+ * This is called when a boulder is spawned from a vent, and is used to set the boulder's icon as well as durability.
+ * We also set our boulder_size variable, which is used for inheiriting the icon_state later on if processed.
+ * @param obj/structure/ore_vent/parent_vent The vent that spawned this boulder to generate consistent boulder icons. If null, we use the default size.
+ * @param size The size of the boulder to spawn. If parent_vent is defined, this is ignored.
+ * @param is_artifact Whether or not this boulder is an artifact boulder. If true, we use the artifact boulder icon state regardless of size.
+ */
+/obj/item/boulder/proc/flavor_boulder(obj/structure/ore_vent/parent_vent, size = BOULDER_SIZE_SMALL, is_artifact = FALSE)
+ var/durability_min = size
+ var/durability_max = size + BOULDER_SIZE_SMALL
+ if(parent_vent)
+ durability_min = parent_vent.boulder_size
+ durability_max = parent_vent.boulder_size + BOULDER_SIZE_SMALL
+ durability = rand(durability_min, durability_max) //randomize durability a bit for some flavor.
+ boulder_size = size
+ if(parent_vent)
+ boulder_size = parent_vent.boulder_size
+ boulder_string = parent_vent.boulder_icon_state
+ update_appearance(UPDATE_ICON_STATE)
+
+/**
+ * Unique proc for gulag-style boulders, which adds a random amount of minerals to the boulder.
+ */
+/obj/item/boulder/proc/add_gulag_minerals()
+ var/datum/material/new_material = pick_weight(gulag_minerals)
+ var/list/new_mats = list()
+ new_mats[new_material] = SHEET_MATERIAL_AMOUNT * rand(1,3) //We only want a few sheets of material in the gulag boulders
+ set_custom_materials(new_mats)
+
+/obj/item/boulder/artifact
+ name = "artifact boulder"
+ desc = "This boulder is brimming with strange energy. Cracking it open could contain something unusual for science."
+ icon_state = "boulder_artifact"
+ /// This is the type of item that will be inside the boulder. Default is a strange object.
+ var/artifact_type = /obj/item/relic
+ /// References to the relic inside the boulder, if any.
+ var/obj/item/artifact_inside
+
+/obj/item/boulder/artifact/Initialize(mapload)
+ . = ..()
+ artifact_inside = new artifact_type(src) /// This could be poggers for archaeology in the future.
+
+/obj/item/boulder/artifact/Destroy(force)
+ QDEL_NULL(artifact_inside)
+ return ..()
+
+/obj/item/boulder/artifact/convert_to_ore()
+ . = ..()
+ artifact_inside.forceMove(drop_location())
+ artifact_inside = null
+
+/obj/item/boulder/artifact/break_apart()
+ artifact_inside = null
+ return ..()
+
+
+/obj/item/boulder/gulag
+ name = "low-quality boulder"
+ desc = "This rocks. It's a low quality boulder, so it's probably not worth as much."
+
+/obj/item/boulder/gulag/Initialize(mapload)
+ . = ..()
+ add_gulag_minerals(gulag_minerals)
+
+/obj/item/boulder/gulag_expanded
+ name = "low-density boulder"
+ desc = "This rocks. It's not very well packed, and can't contain as many minerals."
+
+/obj/item/boulder/gulag_expanded/Initialize(mapload)
+ . = ..()
+ add_gulag_minerals(expanded_gulag_minerals)
+
+/obj/item/boulder/shabby
+ name = "shabby boulder"
+ desc = "A bizzare, twisted boulder. Wait, wait no, it's just a rock."
+ custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.1, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.1)
+ durability = 1
diff --git a/code/modules/mining/boulder_processing/brm.dm b/code/modules/mining/boulder_processing/brm.dm
new file mode 100644
index 00000000000..c76ec9dabbd
--- /dev/null
+++ b/code/modules/mining/boulder_processing/brm.dm
@@ -0,0 +1,187 @@
+#define MANUAL_TELEPORT_SOUND 'sound/machines/mining/manual_teleport.ogg'
+#define AUTO_TELEPORT_SOUND 'sound/machines/mining/auto_teleport.ogg'
+
+/obj/machinery/bouldertech/brm
+ name = "boulder retrieval matrix"
+ desc = "A teleportation matrix used to retrieve boulders excavated by mining NODEs from ore vents."
+ icon_state = "brm"
+ circuit = /obj/item/circuitboard/machine/brm
+ usage_sound = MANUAL_TELEPORT_SOUND
+ processing_flags = START_PROCESSING_MANUALLY
+ boulders_held_max = 2
+ /// Are we trying to actively collect boulders automatically?
+ var/toggled_on = FALSE
+ /// How long does it take to collect a boulder?
+ var/teleportation_time = 1.5 SECONDS
+ /// Cooldown used for left click teleportation.
+ COOLDOWN_DECLARE(manual_teleport_cooldown)
+
+/obj/machinery/bouldertech/brm/Initialize(mapload)
+ . = ..()
+ set_wires(new /datum/wires/brm(src))
+
+/obj/machinery/bouldertech/brm/Destroy()
+ QDEL_NULL(wires)
+ return ..()
+
+/obj/machinery/bouldertech/brm/attack_hand(mob/living/user, list/modifiers)
+ . = ..()
+ if(!handle_teleport_conditions(user))
+ return
+ pre_collect_boulder()
+
+ COOLDOWN_START(src, manual_teleport_cooldown, teleportation_time)
+
+/obj/machinery/bouldertech/brm/attack_robot(mob/user)
+ if(!handle_teleport_conditions(user))
+ return
+ pre_collect_boulder()
+
+ COOLDOWN_START(src, manual_teleport_cooldown, teleportation_time)
+
+/obj/machinery/bouldertech/brm/attackby(obj/item/attacking_item, mob/user, params)
+ if(is_wire_tool(attacking_item) && panel_open)
+ wires.interact(user)
+ return TRUE
+ return ..()
+
+/obj/machinery/bouldertech/brm/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ if(!anchored)
+ balloon_alert(user, "anchor first!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ toggle_auto_on(user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/machinery/bouldertech/brm/attack_robot_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ if(!anchored)
+ balloon_alert(user, "anchor first!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ toggle_auto_on(user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/machinery/bouldertech/brm/process()
+ if(SSore_generation.available_boulders.len < 1)
+ say("No boulders to collect. Entering idle mode.")
+ toggled_on = FALSE
+ update_appearance(UPDATE_ICON_STATE)
+ return PROCESS_KILL
+ for(var/i in 1 to boulders_processing_max)
+ if(pre_collect_boulder())
+ continue
+ toggled_on = FALSE
+ update_appearance(UPDATE_ICON_STATE)
+ return PROCESS_KILL
+ for(var/obj/item/boulder/ground_rocks in loc.contents)
+ boulders_contained += ground_rocks
+ if(boulders_contained.len < boulders_held_max)
+ continue
+ toggled_on = FALSE
+ boulders_contained.Cut()
+ update_appearance(UPDATE_ICON_STATE)
+ return PROCESS_KILL
+
+/obj/machinery/bouldertech/brm/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ context[SCREENTIP_CONTEXT_LMB] = "Teleport single boulder"
+ context[SCREENTIP_CONTEXT_RMB] = "Toggle automatic boulder retrieval"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/obj/machinery/bouldertech/brm/examine(mob/user)
+ . = ..()
+ . += span_notice("The small screen reads there are [span_boldnotice("[SSore_generation.available_boulders.len] boulders")] available to teleport.")
+
+/obj/machinery/bouldertech/brm/RefreshParts()
+ . = ..()
+ var/scanner_stack = 0
+ var/laser_stack = 0
+ for(var/datum/stock_part/scanning_module/scanner in component_parts)
+ scanner_stack += scanner.tier
+ boulders_processing_max = scanner_stack
+ for(var/datum/stock_part/micro_laser/laser in component_parts)
+ laser_stack += laser.tier
+ boulders_held_max = laser_stack + 1
+
+/obj/machinery/bouldertech/brm/update_icon_state()
+ if(toggled_on && !panel_open)
+ icon_state = "[initial(icon_state)]-toggled"
+ return
+ return ..()
+
+/**
+ * Handles qualifiers for enabling teleportation of boulders.
+ * Returns TRUE if the teleportation can proceed, FALSE otherwise.
+ */
+/obj/machinery/bouldertech/brm/proc/handle_teleport_conditions(mob/user)
+ if(!COOLDOWN_FINISHED(src, manual_teleport_cooldown))
+ return FALSE
+ if(panel_open)
+ balloon_alert(user, "close panel first!")
+ return FALSE
+ playsound(src, MANUAL_TELEPORT_SOUND, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ return TRUE
+
+/**
+ * Begins to collect a boulder from the available boulders list in SSore_generation.
+ * Boulders must not be processed by another BRM or machine, and must be in the available boulders list.
+ * A selected boulder is picked randomly.
+ * The actual movement is then handled by collect_boulder() after a timed callback.
+ */
+/obj/machinery/bouldertech/brm/proc/pre_collect_boulder()
+ if(!SSore_generation.available_boulders.len)
+ playsound(loc, 'sound/machines/synth_no.ogg', 30 , TRUE)
+ balloon_alert_to_viewers("no boulders to collect!")
+ return FALSE //Nothing to collect
+ var/obj/item/boulder/random_boulder = pick(SSore_generation.available_boulders)
+ if(random_boulder.processed_by)
+ return FALSE
+
+ random_boulder.processed_by = src
+ random_boulder.Shake(duration = 1.5 SECONDS)
+ SSore_generation.available_boulders -= random_boulder
+ addtimer(CALLBACK(src, PROC_REF(collect_boulder), random_boulder), 1.5 SECONDS)
+ return TRUE
+
+/**
+ * Collects a boulder from the available boulders list in SSore_generation.
+ * Handles the movement of the boulder as well as visual effects on the BRM.
+ * @param obj/item/boulder/random_boulder The boulder to collect.
+ */
+/obj/machinery/bouldertech/brm/proc/collect_boulder(obj/item/boulder/random_boulder)
+ flick("brm-flash", src)
+ if(QDELETED(random_boulder))
+ playsound(loc, 'sound/machines/synth_no.ogg', 30 , TRUE)
+ balloon_alert_to_viewers("target lost!")
+ return FALSE
+ playsound(src, AUTO_TELEPORT_SOUND, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ random_boulder.forceMove(drop_location())
+ random_boulder.processed_by = null
+ random_boulder.pixel_x = rand(-2, 2)
+ random_boulder.pixel_y = rand(-2, 2)
+ balloon_alert_to_viewers("boulder appears!")
+ random_boulder.visible_message(span_warning("[random_boulder] suddenly appears!"))
+ use_power(BASE_MACHINE_ACTIVE_CONSUMPTION * 0.1)
+ return TRUE
+
+/**
+ * Toggles automatic boulder retrieval on.
+ * Adjusts the teleportation sound, icon state, and begins processing.
+ * @param mob/user The user who toggled the BRM.
+ */
+/obj/machinery/bouldertech/brm/proc/toggle_auto_on(mob/user)
+ if(panel_open)
+ if(user)
+ balloon_alert(user, "close panel first!")
+ return
+ toggled_on = TRUE
+ START_PROCESSING(SSmachines, src)
+ update_appearance(UPDATE_ICON_STATE)
+ usage_sound = AUTO_TELEPORT_SOUND
+
+#undef MANUAL_TELEPORT_SOUND
+#undef AUTO_TELEPORT_SOUND
diff --git a/code/modules/mining/boulder_processing/refinery.dm b/code/modules/mining/boulder_processing/refinery.dm
new file mode 100644
index 00000000000..828ace377e9
--- /dev/null
+++ b/code/modules/mining/boulder_processing/refinery.dm
@@ -0,0 +1,98 @@
+/**
+ * Your new favorite industrial waste magnet!
+ * Accepts boulders and produces sheets of non-metalic materials.
+ * Can be upgraded with stock parts or through chemical inputs.
+ * When upgraded, it can hold more boulders and process more at once.
+ *
+ * Chemical inputs can be used to boost the refinery's efficiency, but produces industrial waste, which eats through the station and is generally difficult to store.
+ */
+
+/obj/machinery/bouldertech/refinery
+ name = "boulder refinery"
+ desc = "BR for short. Accepts boulders and refines non-metallic ores into sheets using internal chemicals. Can be upgraded with stock parts or through chemical inputs."
+ icon_state = "stacker"
+ holds_minerals = TRUE
+ processable_materials = list(
+ /datum/material/glass,
+ /datum/material/plasma,
+ /datum/material/diamond,
+ /datum/material/bluespace,
+ /datum/material/bananium,
+ /datum/material/plastic,
+ )
+ circuit = /obj/item/circuitboard/machine/refinery
+ usage_sound = 'sound/machines/mining/refinery.ogg'
+ holds_mining_points = TRUE
+
+/// okay so var that holds mining points to claim
+/// add total of pts from minerals mined in parent proc
+/// then, little mini UI showing points to collect?
+
+/obj/machinery/bouldertech/refinery/RefreshParts()
+ . = ..()
+ var/manipulator_stack = 0
+ var/matter_bin_stack = 0
+ for(var/datum/stock_part/servo/servo in component_parts)
+ manipulator_stack += servo.tier - 1
+ boulders_processing_max = clamp(manipulator_stack, 1, 6)
+ for(var/datum/stock_part/matter_bin/bin in component_parts)
+ matter_bin_stack += bin.tier
+ boulders_held_max = matter_bin_stack
+
+
+/obj/machinery/bouldertech/refinery/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ if(istype(held_item, /obj/item/boulder))
+ context[SCREENTIP_CONTEXT_LMB] = "Insert boulder"
+ if(istype(held_item, /obj/item/card/id) && points_held > 0)
+ context[SCREENTIP_CONTEXT_LMB] = "Claim mining points"
+ context[SCREENTIP_CONTEXT_RMB] = "Remove boulder"
+ return CONTEXTUAL_SCREENTIP_SET
+
+
+/**
+ * Your other new favorite industrial waste magnet!
+ * Accepts boulders and produces sheets of metalic materials.
+ * Can be upgraded with stock parts or through chemical inputs.
+ * When upgraded, it can hold more boulders and process more at once.
+ *
+ * Chemical inputs can be used to boost the refinery's efficiency, but produces industrial waste, which eats through the station and is generally difficult to store.
+ */
+/obj/machinery/bouldertech/refinery/smelter
+ name = "boulder smelter"
+ desc = "BS for short. Accept boulders and refines metallic ores into sheets. Can be upgraded with stock parts or through gas inputs."
+ icon_state = "smelter"
+ processable_materials = list(
+ /datum/material/iron,
+ /datum/material/titanium,
+ /datum/material/silver,
+ /datum/material/gold,
+ /datum/material/uranium,
+ /datum/material/mythril,
+ /datum/material/adamantine,
+ /datum/material/runite,
+ )
+ light_system = MOVABLE_LIGHT
+ light_range = 1
+ light_power = 2
+ light_color = "#ffaf55"
+ light_on = FALSE
+ circuit = /obj/item/circuitboard/machine/smelter
+ usage_sound = 'sound/machines/mining/smelter.ogg'
+
+/obj/machinery/bouldertech/refinery/smelter/RefreshParts()
+ . = ..()
+ light_power = boulders_processing_max
+
+/obj/machinery/bouldertech/refinery/smelter/accept_boulder(obj/item/boulder/new_boulder)
+ . = ..()
+ if(.)
+ set_light_on(TRUE)
+ return TRUE
+
+
+/obj/machinery/bouldertech/refinery/smelter/process()
+ . = ..()
+ if(. == PROCESS_KILL)
+ set_light_on(FALSE)
+
diff --git a/code/modules/mining/equipment/mineral_scanner.dm b/code/modules/mining/equipment/mineral_scanner.dm
index 62b61b89ce9..0994e820144 100644
--- a/code/modules/mining/equipment/mineral_scanner.dm
+++ b/code/modules/mining/equipment/mineral_scanner.dm
@@ -11,7 +11,9 @@
w_class = WEIGHT_CLASS_SMALL
obj_flags = CONDUCTS_ELECTRICITY
slot_flags = ITEM_SLOT_BELT
+ /// The cooldown between scans.
var/cooldown = 35
+ /// Current time until the next scan can be performed.
var/current_cooldown = 0
/obj/item/mining_scanner/attack_self(mob/user)
@@ -19,7 +21,7 @@
return
if(current_cooldown <= world.time)
current_cooldown = world.time + cooldown
- mineral_scan_pulse(get_turf(user))
+ mineral_scan_pulse(get_turf(user), scanner = src)
//Debug item to identify all ore spread quickly
/obj/item/mining_scanner/admin
@@ -40,8 +42,11 @@
w_class = WEIGHT_CLASS_SMALL
obj_flags = CONDUCTS_ELECTRICITY
slot_flags = ITEM_SLOT_BELT
+ /// The cooldown between scans.
var/cooldown = 35
+ /// Current time until the next scan can be performed.
var/current_cooldown = 0
+ /// The range of the scanner in tiles.
var/range = 7
/obj/item/t_scanner/adv_mining_scanner/cyborg/Initialize(mapload)
@@ -59,13 +64,26 @@
if(current_cooldown <= world.time)
current_cooldown = world.time + cooldown
var/turf/t = get_turf(src)
- mineral_scan_pulse(t, range)
+ mineral_scan_pulse(t, range, src)
-/proc/mineral_scan_pulse(turf/T, range = world.view)
+/proc/mineral_scan_pulse(turf/T, range = world.view, obj/item/scanner)
var/list/minerals = list()
- for(var/turf/closed/mineral/M in range(range, T))
- if(M.scan_state)
- minerals += M
+ var/vents_nearby = FALSE
+ var/undiscovered = FALSE
+ var/radar_volume = 30
+ scanner.transform = matrix()
+ for(var/turf/closed/mineral/mineral in RANGE_TURFS(range, T))
+ if(mineral.scan_state)
+ minerals += mineral
+ for(var/obj/structure/ore_vent/vent in range(range, T))
+ if(!vents_nearby && (!vent.discovered || !vent.tapped))
+ vents_nearby = TRUE
+ if(vent.discovered)
+ undiscovered = TRUE
+ var/potential_volume = 80 - (get_dist(scanner, vent) * 10)
+ radar_volume = max(potential_volume, radar_volume)
+ vent.add_mineral_overlays()
+
if(LAZYLEN(minerals))
for(var/turf/closed/mineral/M in minerals)
var/obj/effect/temp_visual/mining_overlay/oldC = locate(/obj/effect/temp_visual/mining_overlay) in M
@@ -74,6 +92,14 @@
var/obj/effect/temp_visual/mining_overlay/C = new /obj/effect/temp_visual/mining_overlay(M)
C.icon_state = M.scan_state
+ if(vents_nearby && scanner)
+ if(undiscovered)
+ playsound(scanner, 'sound/machines/radar-ping.ogg', radar_volume, FALSE)
+ else
+ playsound(scanner, 'sound/machines/sonar-ping.ogg', radar_volume, FALSE)
+ scanner.balloon_alert_to_viewers("ore vent nearby")
+ scanner.spasm_animation(1.5 SECONDS)
+
/obj/effect/temp_visual/mining_overlay
plane = HIGH_GAME_PLANE
layer = FLASH_LAYER
@@ -82,7 +108,17 @@
duration = 35
pixel_x = -224
pixel_y = -224
+ /// What animation easing to use when we create the ore overlay on rock walls/ore vents.
+ var/easing_style = EASE_IN
/obj/effect/temp_visual/mining_overlay/Initialize(mapload)
. = ..()
- animate(src, alpha = 0, time = duration, easing = EASE_IN)
+ animate(src, alpha = 0, time = duration, easing = easing_style)
+
+/obj/effect/temp_visual/mining_overlay/vent
+ icon = 'icons/effects/vent_overlays.dmi'
+ icon_state = "unknown"
+ duration = 45
+ pixel_x = 0
+ pixel_y = 0
+ easing_style = CIRCULAR_EASING|EASE_IN
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index cfa8203615e..0b9b7895c6b 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -1,4 +1,4 @@
-/**********************Ore Redemption Unit**************************/
+/**********************Ore Redemption Unit (ORM)**************************/
//Turns all the various mining machines into a single unit to speed up mining and establish a point system
/obj/machinery/mineral/ore_redemption
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index f1a661e6a48..085fbca1945 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -69,7 +69,7 @@
new /obj/item/flashlight/seclite(src)
new /obj/item/storage/bag/plants(src)
new /obj/item/storage/bag/ore(src)
- new /obj/item/t_scanner/adv_mining_scanner/lesser(src)
+ new /obj/item/mining_scanner(src)
new /obj/item/clothing/glasses/meson(src)
if (HAS_TRAIT(SSstation, STATION_TRAIT_SMALLER_PODS))
new /obj/item/survivalcapsule/bathroom(src)
diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_box.dm
similarity index 76%
rename from code/modules/mining/satchel_ore_boxdm.dm
rename to code/modules/mining/satchel_ore_box.dm
index 607bbcd9f06..7a82b9483a0 100644
--- a/code/modules/mining/satchel_ore_boxdm.dm
+++ b/code/modules/mining/satchel_ore_box.dm
@@ -10,8 +10,9 @@
pressure_resistance = 5*ONE_ATMOSPHERE
/obj/structure/ore_box/attackby(obj/item/W, mob/user, params)
- if (istype(W, /obj/item/stack/ore))
- user.transferItemToLoc(W, src)
+ if (istype(W, /obj/item/stack/ore) || istype(W, /obj/item/boulder))
+ if(!user.transferItemToLoc(W, src))
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
else if(W.atom_storage)
W.atom_storage.remove_type(/obj/item/stack/ore, src, INFINITY, TRUE, FALSE, user, null)
to_chat(user, span_notice("You empty the ore in [W] into \the [src]."))
@@ -45,7 +46,7 @@
/obj/structure/ore_box/proc/dump_box_contents()
var/drop = drop_location()
var/turf/our_turf = get_turf(src)
- for(var/obj/item/stack/ore/O in src)
+ for(var/obj/item/O in src)
if(QDELETED(O))
continue
if(QDELETED(src))
@@ -64,17 +65,24 @@
ui.open()
/obj/structure/ore_box/ui_data()
- var/contents = list()
- for(var/obj/item/stack/ore/O in src)
- contents[O.type] += O.amount
+ var/item_contents = list()
+ var/boulder_count = 0
+ for(var/obj/item/stack/ore/potental_ore as anything in contents)
+ if(istype(potental_ore, /obj/item/stack/ore))
+ item_contents[potental_ore.type] += potental_ore.amount
+ else
+ boulder_count++
var/data = list()
- data["materials"] = list()
- for(var/type in contents)
- var/obj/item/stack/ore/O = type
- var/name = initial(O.name)
- data["materials"] += list(list("name" = name, "amount" = contents[type], "id" = type))
+ data["materials"] = list()
+
+ for(var/obj/item/stone as anything in item_contents)
+ if(ispath(stone, /obj/item/stack/ore))
+ var/obj/item/stack/ore/found_ore = stone
+ var/name = initial(found_ore.name)
+ data["materials"] += list(list("name" = name, "amount" = item_contents[stone], "id" = type))
+ data["boulders"] = boulder_count
return data
/obj/structure/ore_box/ui_act(action, params)
diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm
index 9a45ed99e1c..11fd7b6aa26 100644
--- a/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm
+++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimdemon_loot.dm
@@ -53,4 +53,4 @@
if(!COOLDOWN_FINISHED(src, ore_sensing_cooldown))
return
COOLDOWN_START(src, ore_sensing_cooldown, cooldown)
- mineral_scan_pulse(get_turf(src), range)
+ mineral_scan_pulse(get_turf(src), range, src)
diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm
index afc87fb7ce5..d0355e906a7 100644
--- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm
+++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm
@@ -65,7 +65,8 @@
make_tameable()
if(can_lay_eggs)
make_egg_layer()
-
+ ADD_TRAIT(src, TRAIT_BOULDER_BREAKER, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_INSTANTLY_PROCESSES_BOULDERS, INNATE_TRAIT)
RegisterSignal(src, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(block_bullets))
/mob/living/basic/mining/goldgrub/proc/block_bullets(datum/source, obj/projectile/hitting_projectile)
diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm
index 53054052e58..a31bf1f3e1d 100644
--- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm
+++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm
@@ -14,6 +14,8 @@
/datum/ai_planning_subtree/dig_away_from_danger,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/find_and_hunt_target/hunt_ores,
+ /datum/ai_planning_subtree/find_and_hunt_target/break_boulders,
+ /datum/ai_planning_subtree/find_and_hunt_target/harvest_vents,
/datum/ai_planning_subtree/find_and_hunt_target/baby_egg,
/datum/ai_planning_subtree/mine_walls,
)
@@ -43,7 +45,7 @@
hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target/hunt_ores
finding_behavior = /datum/ai_behavior/find_hunt_target/hunt_ores
hunt_targets = list(/obj/item/stack/ore)
- hunt_chance = 75
+ hunt_chance = 90
hunt_range = 9
/datum/ai_behavior/find_hunt_target/hunt_ores
@@ -66,6 +68,50 @@
/datum/ai_behavior/hunt_target/unarmed_attack_target/hunt_ores
always_reset_target = TRUE
+///break boulders so that we can find more food!
+/datum/ai_planning_subtree/find_and_hunt_target/harvest_vents
+ target_key = BB_VENT_TARGET
+ hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target //We call the ore vent's produce_boulder() proc here to produce a single boulder.
+ finding_behavior = /datum/ai_behavior/find_hunt_target/harvest_vents
+ hunt_targets = list(/obj/structure/ore_vent)
+ hunt_chance = 25
+ hunt_range = 15
+
+/datum/ai_behavior/find_hunt_target/harvest_vents
+
+/datum/ai_behavior/find_hunt_target/harvest_vents/valid_dinner(mob/living/basic/source, obj/structure/target, radius)
+ if(target in source)
+ return FALSE
+
+ var/turf/vent_turf = target.drop_location()
+ var/counter = 0
+ for(var/obj/item/boulder in vent_turf.contents)
+ counter++
+ if(counter > MAX_BOULDERS_PER_VENT) //Too many items currently on the vent
+ return FALSE
+
+ return can_see(source, target, radius)
+
+///break boulders so that we can find more food!
+/datum/ai_planning_subtree/find_and_hunt_target/break_boulders
+ target_key = BB_BOULDER_TARGET
+ hunting_behavior = /datum/ai_behavior/hunt_target/unarmed_attack_target //We process boulders once every tap, so we dont need to do anything special here
+ finding_behavior = /datum/ai_behavior/find_hunt_target/break_boulders
+ hunt_targets = list(/obj/item/boulder)
+ hunt_chance = 100 //If we can, we should always break boulders.
+ hunt_range = 9
+
+/datum/ai_behavior/find_hunt_target/break_boulders
+
+/datum/ai_behavior/find_hunt_target/break_boulders/valid_dinner(mob/living/basic/source, obj/item/boulder/target, radius)
+ if(target in source)
+ return FALSE
+
+ var/obj/item/pet_target = source.ai_controller.blackboard[BB_CURRENT_PET_TARGET]
+ if(target == pet_target) //we are currently fetching this ore for master, dont eat it!
+ return FALSE
+ return can_see(source, target, radius)
+
///find our child's egg and pull it!
/datum/ai_planning_subtree/find_and_hunt_target/baby_egg
target_key = BB_LOW_PRIORITY_HUNTING_TARGET
diff --git a/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm b/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm
new file mode 100644
index 00000000000..d85ad69682c
--- /dev/null
+++ b/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm
@@ -0,0 +1,154 @@
+#define FLY_IN_STATE 1
+#define FLY_OUT_STATE 2
+#define NEUTRAL_STATE 3
+
+/**
+ * Mining drones that are spawned when starting a ore vent's wave defense minigame.
+ * They will latch onto the vent to defend it from lavaland mobs, and will flee if attacked by lavaland mobs.
+ * If the drone survives, they will fly away to safety as the vent spawns ores.
+ * If the drone dies, the wave defense will fail.
+ */
+
+/mob/living/basic/node_drone
+ name = "NODE drone"
+ desc = "Standard in-atmosphere drone, used by Nanotrasen to operate and excavate valuable ore vents."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "mining_node_active"
+ icon_living = "mining_node_active"
+ icon_dead = "mining_node_active"
+
+ maxHealth = 500
+ health = 500
+ density = TRUE
+ pass_flags = PASSTABLE|PASSGRILLE|PASSMOB
+ mob_size = MOB_SIZE_LARGE
+ mob_biotypes = MOB_ROBOTIC
+ faction = list(FACTION_STATION, FACTION_NEUTRAL)
+ light_range = 4
+ basic_mob_flags = DEL_ON_DEATH
+
+ speak_emote = list("chirps")
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "gently pushes aside"
+ response_disarm_simple = "gently push aside"
+ response_harm_continuous = "clangs"
+ response_harm_simple = "clang against"
+
+ ai_controller = /datum/ai_controller/basic_controller/node_drone
+
+ /// Is the drone currently attached to a vent?
+ var/active_node = FALSE
+ /// What status do we currently track for icon purposes?
+ var/flying_state = NEUTRAL_STATE
+ /// Weakref to the vent the drone is currently attached to.
+ var/obj/structure/ore_vent/attached_vent = null
+ /// Set when the drone is begining to leave lavaland after the vent is secured.
+ var/escaping = FALSE
+
+/mob/living/basic/node_drone/death(gibbed)
+ . = ..()
+ explosion(origin = src, light_impact_range = 1, smoke = 1)
+
+/mob/living/basic/node_drone/Destroy()
+ attached_vent?.node = null //clean our reference to the vent both ways.
+ attached_vent = null
+ return ..()
+
+
+/mob/living/basic/node_drone/examine(mob/user)
+ . = ..()
+ var/sameside = user.faction_check_atom(src, exact_match = FALSE)
+ if(sameside)
+ . += span_notice("This drone is currently attached to a mineral vent. You should protect it from harm to secure the mineral vent.")
+ else
+ . += span_warning("This vile Nanotrasen trash is trying to destroy the environment. Attack it to free the mineral vent from its grasp.")
+
+/mob/living/basic/node_drone/update_icon_state()
+ . = ..()
+
+ icon_state = "mining_node_active"
+
+ if(flying_state == FLY_IN_STATE || flying_state == FLY_OUT_STATE)
+ icon_state = "mining_node_flying"
+
+/mob/living/basic/node_drone/proc/arrive(obj/structure/ore_vent/parent_vent)
+ attached_vent = parent_vent
+ flying_state = FLY_IN_STATE
+ update_appearance(UPDATE_ICON_STATE)
+ pixel_z = 400
+ animate(src, pixel_z = 0, time = 2 SECONDS, easing = QUAD_EASING|EASE_OUT, flags = ANIMATION_PARALLEL)
+
+
+/**
+ * Called when wave defense is completed. Visually flicks the escape sprite and then deletes the mob.
+ */
+/mob/living/basic/node_drone/proc/escape()
+ var/funny_ending = FALSE
+ flying_state = FLY_OUT_STATE
+ update_appearance(UPDATE_ICON_STATE)
+ if(prob(1))
+ say("I have to go now, my planet needs me.")
+ funny_ending = TRUE
+ visible_message(span_notice("The drone flies away to safety as the vent is secured."))
+ animate(src, pixel_z = 400, time = 2 SECONDS, easing = QUAD_EASING|EASE_IN, flags = ANIMATION_PARALLEL)
+ sleep(2 SECONDS)
+ if(funny_ending)
+ playsound(src, 'sound/effects/explosion3.ogg', 50, FALSE) //node drone died on the way back to his home planet.
+ visible_message(span_notice("...or maybe not."))
+ qdel(src)
+
+
+/mob/living/basic/node_drone/proc/pre_escape()
+ if(attached_vent)
+ attached_vent.unbuckle_mob(src)
+ attached_vent = null
+ if(!escaping)
+ escaping = TRUE
+ flick("mining_node_escape", src)
+ addtimer(CALLBACK(src, PROC_REF(escape)), 1.9 SECONDS)
+ return
+
+/// The node drone AI controller
+// Generally, this is a very simple AI that will try to find a vent and latch onto it, unless attacked by a lavaland mob, who it will try to flee from.
+/datum/ai_controller/basic_controller/node_drone
+ blackboard = list(
+ BB_BASIC_MOB_FLEEING = FALSE, // Will flee when the vent lies undefended.
+ BB_CURRENT_HUNTING_TARGET = null, // Hunts for vents.
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, // Use this to find vents to run away from
+ )
+
+ ai_traits = STOP_MOVING_WHEN_PULLED
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = null
+ planning_subtrees = list(
+ // Priority is see if lavaland mobs are attacking us to flee from them.
+ /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee,
+ // Fly you fool
+ /datum/ai_planning_subtree/flee_target/node_drone,
+ // Otherwise, look for and execute hunts for vents to latch onto.
+ /datum/ai_planning_subtree/find_and_hunt_target/look_for_vent,
+ )
+
+// Node subtree to hunt down ore vents.
+/datum/ai_planning_subtree/find_and_hunt_target/look_for_vent
+ hunting_behavior = /datum/ai_behavior/hunt_target/latch_onto/node_drone
+ hunt_targets = list(/obj/structure/ore_vent)
+ hunt_range = 7 // Hunt vents to the end of the earth.
+
+// node drone behavior for buckling down on a vent.
+/datum/ai_behavior/hunt_target/latch_onto/node_drone
+ hunt_cooldown = 5 SECONDS
+
+// Evasion behavior.
+/datum/ai_planning_subtree/flee_target/node_drone
+ flee_behaviour = /datum/ai_behavior/run_away_from_target/drone
+
+/datum/ai_behavior/run_away_from_target/drone
+ action_cooldown = 1 SECONDS
+ run_distance = 3
+
+
+#undef FLY_IN_STATE
+#undef FLY_OUT_STATE
+#undef NEUTRAL_STATE
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 01451a8db36..612328e749e 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -18,6 +18,7 @@
TRAIT_RADIMMUNE,
TRAIT_SNOWSTORM_IMMUNE, // Shared with plasma river... but I guess if you can survive a plasma river a blizzard isn't a big deal
TRAIT_UNHUSKABLE,
+ TRAIT_BOULDER_BREAKER,
)
mutantheart = null
mutantlungs = null
@@ -87,7 +88,7 @@
SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
SPECIES_PERK_ICON = "pickaxe",
SPECIES_PERK_NAME = "Natural Miners",
- SPECIES_PERK_DESC = "Golems can see dimly in the dark, sense minerals, and mine stone with their bare hands. \
+ SPECIES_PERK_DESC = "Golems can see dimly in the dark, sense minerals, break boulders, and mine stone with their bare hands. \
They can even smelt ores in an internal furnace, if their surrounding environment is hot enough.",
))
diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm
index 96de0436b3c..4140738bb09 100644
--- a/code/modules/mob/living/silicon/robot/robot_model.dm
+++ b/code/modules/mob/living/silicon/robot/robot_model.dm
@@ -723,6 +723,7 @@
/obj/item/gun/energy/recharge/kinetic_accelerator/cyborg,
/obj/item/gps/cyborg,
/obj/item/stack/marker_beacon,
+ /obj/item/t_scanner/adv_mining_scanner/cyborg,
)
radio_channels = list(RADIO_CHANNEL_SCIENCE, RADIO_CHANNEL_SUPPLY)
emag_modules = list(
@@ -736,16 +737,6 @@
"Spider Miner" = list(SKIN_ICON_STATE = "spidermin"),
"Lavaland Miner" = list(SKIN_ICON_STATE = "miner"),
)
- var/obj/item/t_scanner/adv_mining_scanner/cyborg/mining_scanner //built in memes. //fuck you
-
-/obj/item/robot_model/miner/rebuild_modules()
- . = ..()
- if(!mining_scanner)
- mining_scanner = new(src)
-
-/obj/item/robot_model/miner/Destroy()
- QDEL_NULL(mining_scanner)
- return ..()
/obj/item/robot_model/peacekeeper
name = "Peacekeeper"
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
index fd6a951dedd..bc8134aac15 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
@@ -49,6 +49,8 @@
var/chosen_attack = 1
/// Attack actions, sets chosen_attack to the number in the action
var/list/attack_action_types = list()
+ /// Summoning line, said when summoned via megafauna vents.
+ var/summon_line = "I'll kick your ass!"
/mob/living/simple_animal/hostile/megafauna/Initialize(mapload)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index eaeaddc3e03..91cf152acb0 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -68,6 +68,7 @@ Difficulty: Hard
death_message = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
death_sound = 'sound/magic/enter_blood.ogg'
faction = list(FACTION_MINING, FACTION_BOSS, FACTION_HELL)
+ summon_line = "GRAAAAAAAHHHHHHHHH!"
/// Check to see if we should spawn blood
var/spawn_blood = TRUE
/// Actual time where enrage ends
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index e394ea18db9..d794e493910 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -55,6 +55,7 @@
loot = list(/obj/structure/closet/crate/necropolis/colossus)
death_message = "disintegrates, leaving a glowing core in its wake."
death_sound = 'sound/magic/demon_dies.ogg'
+ summon_line = "Your trial begins now."
/// Spiral shots ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus/spiral_shots
/// Random shots ablity
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
index dc49d71f796..3415c45d12b 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
@@ -43,6 +43,7 @@ Difficulty: Extremely Hard
death_message = "falls to the ground, decaying into plasma particles."
death_sound = SFX_BODYFALL
footstep_type = FOOTSTEP_MOB_HEAVY
+ summon_line = "I'M WIDE AWAKE! AND YOU'RE WIIIIIIIDE OPEN!"
/// If the demonic frost miner is in its enraged state
var/enraged = FALSE
/// If the demonic frost miner is currently transforming to its enraged state
@@ -320,7 +321,7 @@ Difficulty: Extremely Hard
/obj/item/pickaxe/drill/jackhammer/demonic/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks)
var/turf/T = get_turf(target)
- mineral_scan_pulse(T, world.view + 1)
+ mineral_scan_pulse(T, world.view + 1, src)
. = ..()
/obj/item/crusher_trophy/ice_block_talisman
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 3cda123814c..cf573c3a574 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -69,6 +69,7 @@
death_message = "collapses into a pile of bones, its flesh sloughing away."
death_sound = 'sound/magic/demon_dies.ogg'
footstep_type = FOOTSTEP_MOB_HEAVY
+ summon_line = "ROOOOOOOOAAAAAAAAAAAR!"
/// Fire cone ability
var/datum/action/cooldown/mob_cooldown/fire_breath/cone/fire_cone
/// Meteors ability
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
index 50a6cee44ce..342713ee960 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
@@ -54,6 +54,7 @@ Difficulty: Hard
attack_action_types = list(/datum/action/innate/megafauna_attack/heavy_stomp,
/datum/action/innate/megafauna_attack/teleport,
/datum/action/innate/megafauna_attack/shockwave_scream)
+ summon_line = "GwaHOOOOOOOOOOOOOOOOOOOOO"
/// Saves the turf the megafauna was created at (spawns exit portal here)
var/turf/starting
/// Range for wendigo stomping when it moves
diff --git a/code/modules/paperwork/paper_premade.dm b/code/modules/paperwork/paper_premade.dm
index 47588a65706..b72ce806dd3 100644
--- a/code/modules/paperwork/paper_premade.dm
+++ b/code/modules/paperwork/paper_premade.dm
@@ -167,8 +167,8 @@
/////////// Lavaland
/obj/item/paper/fluff/stations/lavaland/orm_notice
- name = "URGENT!"
- default_raw_text = "A hastily written note has been scribbled here...
Please use the ore redemption machine in the cargo office for smelting. PLEASE!
--The Research Staff"
+ name = "URGENT! RENOVATIONS!"
+ default_raw_text = "A hastily written note has been scribbled here...
Please use the ore redemption machine smelter and refinery in the cargo office for smelting. PLEASE! Leave boulders alone for the BRM to pick up!
--The Research Staff"
/////////// Space Ruins
diff --git a/code/modules/procedural_mapping/mapGenerators/lavaland.dm b/code/modules/procedural_mapping/mapGenerators/lavaland.dm
index 2c8ae376a3c..5251f5e8435 100644
--- a/code/modules/procedural_mapping/mapGenerators/lavaland.dm
+++ b/code/modules/procedural_mapping/mapGenerators/lavaland.dm
@@ -3,10 +3,10 @@
spawnableTurfs = list(/turf/open/misc/asteroid/basalt/lava_land_surface = 100)
/datum/map_generator_module/bottom_layer/lavaland_mineral
- spawnableTurfs = list(/turf/closed/mineral/random/volcanic = 100)
+ spawnableTurfs = list(/turf/closed/mineral/volcanic = 100)
/datum/map_generator_module/bottom_layer/lavaland_mineral/dense
- spawnableTurfs = list(/turf/closed/mineral/random/high_chance/volcanic = 100)
+ spawnableTurfs = list(/turf/closed/mineral/volcanic = 100)
/datum/map_generator_module/splatter_layer/lavaland_monsters
spawnableTurfs = list()
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index aa943d12e77..e3ed515a708 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -153,7 +153,7 @@
icon_state = "kineticgun" // SKYRAT EDIT CHANGE
holds_charge = TRUE
unique_frequency = TRUE
- max_mod_capacity = 100 // SKYRAT EDIT CHANGE FROM 80 - Balance due to fauna changes and no level perks applying
+ max_mod_capacity = 100 // SKYRAT EDIT CHANGE FROM 90 - Balance due to fauna changes and no level perks applying
/obj/item/gun/energy/recharge/kinetic_accelerator/minebot
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
diff --git a/code/modules/research/designs/autolathe/mining.dm b/code/modules/research/designs/autolathe/mining.dm
new file mode 100644
index 00000000000..bc83d27123d
--- /dev/null
+++ b/code/modules/research/designs/autolathe/mining.dm
@@ -0,0 +1,32 @@
+// Autolathe-able circuitboards for starting with boulder processing machines.
+/datum/design/board/smelter
+ name = "Boulder Smelter"
+ desc = "A circuitboard for a boulder smelter. Lowtech enough to be printed from the lathe."
+ id = "b_smelter"
+ build_type = AUTOLATHE
+ materials = list(
+ /datum/material/glass = SHEET_MATERIAL_AMOUNT,
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT,
+ )
+ build_path = /obj/item/circuitboard/machine/smelter
+ category = list(
+ RND_CATEGORY_INITIAL,
+ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO,
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_CARGO
+
+/datum/design/board/refinery
+ name = "Boulder Refinery"
+ desc = "A circuitboard for a boulder refinery. Lowtech enough to be printed from the lathe."
+ id = "b_refinery"
+ build_type = AUTOLATHE
+ materials = list(
+ /datum/material/glass = SHEET_MATERIAL_AMOUNT,
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT,
+ )
+ build_path = /obj/item/circuitboard/machine/refinery
+ category = list(
+ RND_CATEGORY_INITIAL,
+ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO,
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_CARGO
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 11e6f026f68..a73b4459333 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -1135,3 +1135,16 @@
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE
)
departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE
+
+/datum/design/board/brm
+ name = "Boulder Retrieval Matrix"
+ id = "brm"
+ materials = list(
+ /datum/material/glass = SHEET_MATERIAL_AMOUNT,
+ )
+ build_path = /obj/item/circuitboard/machine/brm
+ category = list(
+ RND_CATEGORY_INITIAL,
+ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_TELEPORT,
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_CARGO
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index b12cca4b859..963e507c45b 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -1472,6 +1472,9 @@
"superresonator",
"triggermod",
"mining_scanner",
+ "brm",
+ "b_smelter",
+ "b_refinery",
)//e a r l y g a m e)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm
index f21e67552a3..ede42a1efda 100644
--- a/code/modules/surgery/organs/internal/eyes/_eyes.dm
+++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm
@@ -310,7 +310,7 @@
/datum/action/cooldown/golem_ore_sight/Activate(atom/target)
. = ..()
- mineral_scan_pulse(get_turf(target))
+ mineral_scan_pulse(get_turf(target), scanner = src)
///Robotic
diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm
index de96f3ad5f6..c7c082a20e8 100644
--- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm
@@ -29,6 +29,8 @@
butcher_sound = null, \
disabled = TRUE, \
)
+ ADD_TRAIT(src, TRAIT_INSTANTLY_PROCESSES_BOULDERS, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_BOULDER_BREAKER, INNATE_TRAIT)
/obj/item/mecha_parts/mecha_equipment/drill/action(mob/source, atom/target, list/modifiers)
// Check if we can even use the equipment to begin with.
@@ -66,8 +68,12 @@
playsound(src,'sound/weapons/drill.ogg',40,TRUE)
else if(isobj(target))
var/obj/O = target
- O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target))
- playsound(src,'sound/weapons/drill.ogg',40,TRUE)
+ if(istype(O, /obj/item/boulder))
+ var/obj/item/boulder/nu_boulder = O
+ nu_boulder.manual_process(src, source)
+ else
+ O.take_damage(15, BRUTE, 0, FALSE, get_dir(chassis, target))
+ playsound(src,'sound/weapons/drill.ogg', 40, TRUE)
// If we caused a qdel drilling the target, we can stop drilling them.
// Prevents starting a do_after on a qdeleted target.
@@ -154,10 +160,11 @@
name = "exosuit mining scanner"
desc = "Equipment for working exosuits. It will automatically check surrounding rock for useful minerals."
icon_state = "mecha_analyzer"
- equip_cooldown = 15
+ equip_cooldown = 1.5 SECONDS
equipment_slot = MECHA_UTILITY
mech_flags = EXOSUIT_MODULE_WORKING
var/scanning_time = 0
+ COOLDOWN_DECLARE(area_scan_cooldown)
/obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize(mapload)
. = ..()
@@ -174,7 +181,25 @@
if(!LAZYLEN(chassis.occupants))
return
scanning_time = world.time + equip_cooldown
- mineral_scan_pulse(get_turf(src))
+ mineral_scan_pulse(get_turf(src), scanner = src)
+
+/obj/item/mecha_parts/mecha_equipment/mining_scanner/get_snowflake_data()
+ return list(
+ "snowflake_id" = MECHA_SNOWFLAKE_ID_ORE_SCANNER,
+ "cooldown" = COOLDOWN_TIMELEFT(src, area_scan_cooldown),
+ )
+
+/obj/item/mecha_parts/mecha_equipment/mining_scanner/handle_ui_act(action, list/params)
+ switch(action)
+ if("area_scan")
+ if(!COOLDOWN_FINISHED(src, area_scan_cooldown))
+ return FALSE
+ COOLDOWN_START(src, area_scan_cooldown, 15 SECONDS)
+ for(var/mob/living/carbon/human/driver in chassis.return_drivers())
+ for(var/obj/structure/ore_vent/vent as anything in range(5, chassis))
+ if(istype(vent, /obj/structure/ore_vent))
+ vent.scan_and_confirm(driver, TRUE)
+ return TRUE
#undef DRILL_BASIC
#undef DRILL_HARDENED
diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm
index 766826e8f5a..a77381fe97a 100644
--- a/code/modules/vehicles/mecha/mecha_movement.dm
+++ b/code/modules/vehicles/mecha/mecha_movement.dm
@@ -19,6 +19,11 @@
//we can reach it and it's in front of us? grab it!
if(ore.Adjacent(src) && ((get_dir(src, ore) & dir) || ore.loc == loc))
ore.forceMove(ore_box)
+ for(var/obj/item/boulder/boulder in range(1, src))
+ //As above, but for boulders
+ if(boulder.Adjacent(src) && ((get_dir(src, boulder) & dir) || boulder.loc == loc))
+ boulder.forceMove(ore_box)
+
///Plays the mech step sound effect. Split from movement procs so that other mechs (HONK) can override this one specific part.
/obj/vehicle/sealed/mecha/proc/play_stepsound()
diff --git a/icons/area/areas_station.dmi b/icons/area/areas_station.dmi
index c63c333fa4c..66098018f75 100644
Binary files a/icons/area/areas_station.dmi and b/icons/area/areas_station.dmi differ
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 1be88105380..072fbe02558 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/effects/ore_visuals.dmi b/icons/effects/ore_visuals.dmi
index 5189711bc25..87c31c8c7df 100644
Binary files a/icons/effects/ore_visuals.dmi and b/icons/effects/ore_visuals.dmi differ
diff --git a/icons/effects/vent_overlays.dmi b/icons/effects/vent_overlays.dmi
new file mode 100644
index 00000000000..54ac3d7a819
Binary files /dev/null and b/icons/effects/vent_overlays.dmi differ
diff --git a/icons/obj/debris.dmi b/icons/obj/debris.dmi
index d256d1ddd6e..10b73560cbb 100644
Binary files a/icons/obj/debris.dmi and b/icons/obj/debris.dmi differ
diff --git a/icons/obj/machines/mining_machines.dmi b/icons/obj/machines/mining_machines.dmi
index d6fc1afd716..91f7f434ad3 100644
Binary files a/icons/obj/machines/mining_machines.dmi and b/icons/obj/machines/mining_machines.dmi differ
diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi
index 54b19553b84..cdc886d85ac 100644
Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ
diff --git a/icons/obj/mining_zones/terrain.dmi b/icons/obj/mining_zones/terrain.dmi
index 4db51145eee..fd930fe709d 100644
Binary files a/icons/obj/mining_zones/terrain.dmi and b/icons/obj/mining_zones/terrain.dmi differ
diff --git a/icons/obj/ore.dmi b/icons/obj/ore.dmi
index 23fcb8c89ea..7cc3b882057 100644
Binary files a/icons/obj/ore.dmi and b/icons/obj/ore.dmi differ
diff --git a/sound/attributions.txt b/sound/attributions.txt
index 9e573778be8..82486a5735d 100644
--- a/sound/attributions.txt
+++ b/sound/attributions.txt
@@ -121,3 +121,19 @@ throw.ogg, throwhard.ogg and throwsoft.ogg (Royalty-Free and Copyright-Free) are
https://uppbeat.io/sfx/whoosh-swift-cut/7727/23617
https://uppbeat.io/sfx/whoosh-air-punch/114/1168
https://uppbeat.io/sfx/throwing-item-swing/9430/25267
+
+rock_break.ogg is taken from Bertsz's Rock Destroy from Freesound.org, CC0:
+https://freesound.org/people/Bertsz/sounds/524312/
+
+sonar-ping.ogg and radar-ping is taken and modified from SamsterBirdies' Sonar Ping from Freesound.org, CC0:
+https://freesound.org/people/SamsterBirdies/sounds/539957/
+
+manual_teleport.ogg is taken from Quetzakol's teleport from Freesound.org, CC0:
+https://freesound.org/people/Quetzakol/sounds/520743/
+
+auto_teleport.ogg is taken from Steaq's A teleportation from Freesound.org, CC0:
+https://freesound.org/people/steaq/sounds/560124/
+
+refinery.ogg, smelter.ogg, and wooping_teleport.ogg are all original works by ArcaneMusic,
+with smelter.ogg using samples from rock_break alongside original sound effects from a warrior electric drill,
+where refinery and wooping_teleport are modifications of that same electric drill recording.
diff --git a/sound/effects/rock_break.ogg b/sound/effects/rock_break.ogg
new file mode 100644
index 00000000000..09f6b1d5d33
Binary files /dev/null and b/sound/effects/rock_break.ogg differ
diff --git a/sound/machines/mining/auto_teleport.ogg b/sound/machines/mining/auto_teleport.ogg
new file mode 100644
index 00000000000..a8fe669e865
Binary files /dev/null and b/sound/machines/mining/auto_teleport.ogg differ
diff --git a/sound/machines/mining/manual_teleport.ogg b/sound/machines/mining/manual_teleport.ogg
new file mode 100644
index 00000000000..b011ef91e65
Binary files /dev/null and b/sound/machines/mining/manual_teleport.ogg differ
diff --git a/sound/machines/mining/refinery.ogg b/sound/machines/mining/refinery.ogg
new file mode 100644
index 00000000000..fdae21f9a30
Binary files /dev/null and b/sound/machines/mining/refinery.ogg differ
diff --git a/sound/machines/mining/smelter.ogg b/sound/machines/mining/smelter.ogg
new file mode 100644
index 00000000000..b1d65f3bd20
Binary files /dev/null and b/sound/machines/mining/smelter.ogg differ
diff --git a/sound/machines/mining/wooping_teleport.ogg b/sound/machines/mining/wooping_teleport.ogg
new file mode 100644
index 00000000000..edf5eb57b43
Binary files /dev/null and b/sound/machines/mining/wooping_teleport.ogg differ
diff --git a/sound/machines/radar-ping.ogg b/sound/machines/radar-ping.ogg
new file mode 100644
index 00000000000..d6fd0000d1a
Binary files /dev/null and b/sound/machines/radar-ping.ogg differ
diff --git a/sound/machines/sonar-ping.ogg b/sound/machines/sonar-ping.ogg
new file mode 100644
index 00000000000..c69d4352095
Binary files /dev/null and b/sound/machines/sonar-ping.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 6197f82f996..1c3990aeb9d 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -143,6 +143,7 @@
#include "code\__DEFINES\melee.dm"
#include "code\__DEFINES\memory_defines.dm"
#include "code\__DEFINES\mergers.dm"
+#include "code\__DEFINES\mining.dm"
#include "code\__DEFINES\mob_spawn.dm"
#include "code\__DEFINES\mobfactions.dm"
#include "code\__DEFINES\mobs.dm"
@@ -742,6 +743,7 @@
#include "code\controllers\subsystem\mouse_entered.dm"
#include "code\controllers\subsystem\nightshift.dm"
#include "code\controllers\subsystem\npcpool.dm"
+#include "code\controllers\subsystem\ore_generation.dm"
#include "code\controllers\subsystem\overlays.dm"
#include "code\controllers\subsystem\pai.dm"
#include "code\controllers\subsystem\parallax.dm"
@@ -1911,6 +1913,7 @@
#include "code\datums\wires\airlock.dm"
#include "code\datums\wires\apc.dm"
#include "code\datums\wires\autolathe.dm"
+#include "code\datums\wires\brm.dm"
#include "code\datums\wires\conveyor.dm"
#include "code\datums\wires\ecto_sniffer.dm"
#include "code\datums\wires\emitter.dm"
@@ -2743,6 +2746,7 @@
#include "code\game\objects\structures\icemoon\cave_entrance.dm"
#include "code\game\objects\structures\lavaland\geyser.dm"
#include "code\game\objects\structures\lavaland\necropolis_tendril.dm"
+#include "code\game\objects\structures\lavaland\ore_vent.dm"
#include "code\game\objects\structures\plaques\_plaques.dm"
#include "code\game\objects\structures\plaques\static_plaques.dm"
#include "code\game\objects\structures\signs\_signs.dm"
@@ -4507,9 +4511,13 @@
#include "code\modules\mining\mine_items.dm"
#include "code\modules\mining\money_bag.dm"
#include "code\modules\mining\ores_coins.dm"
-#include "code\modules\mining\satchel_ore_boxdm.dm"
+#include "code\modules\mining\satchel_ore_box.dm"
#include "code\modules\mining\shelters.dm"
#include "code\modules\mining\voucher_sets.dm"
+#include "code\modules\mining\boulder_processing\_boulder_processing.dm"
+#include "code\modules\mining\boulder_processing\boulder.dm"
+#include "code\modules\mining\boulder_processing\brm.dm"
+#include "code\modules\mining\boulder_processing\refinery.dm"
#include "code\modules\mining\equipment\explorer_gear.dm"
#include "code\modules\mining\equipment\kheiral_cuffs.dm"
#include "code\modules\mining\equipment\kinetic_crusher.dm"
@@ -4725,6 +4733,7 @@
#include "code\modules\mob\living\basic\lavaland\mook\mook_abilities.dm"
#include "code\modules\mob\living\basic\lavaland\mook\mook_ai.dm"
#include "code\modules\mob\living\basic\lavaland\mook\mook_village.dm"
+#include "code\modules\mob\living\basic\lavaland\node_drone\node_drone.dm"
#include "code\modules\mob\living\basic\lavaland\watcher\watcher.dm"
#include "code\modules\mob\living\basic\lavaland\watcher\watcher_ai.dm"
#include "code\modules\mob\living\basic\lavaland\watcher\watcher_gaze.dm"
@@ -5571,6 +5580,7 @@
#include "code\modules\research\designs\autolathe\engineering_designs.dm"
#include "code\modules\research\designs\autolathe\materials.dm"
#include "code\modules\research\designs\autolathe\medsci_designs.dm"
+#include "code\modules\research\designs\autolathe\mining.dm"
#include "code\modules\research\designs\autolathe\multi-department_designs.dm"
#include "code\modules\research\designs\autolathe\security_designs.dm"
#include "code\modules\research\designs\autolathe\service_designs.dm"
diff --git a/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx b/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx
index ab8eb2e728f..5cd22f11d16 100644
--- a/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx
+++ b/tgui/packages/tgui/interfaces/Mecha/ModulesPane.tsx
@@ -308,6 +308,7 @@ const MECHA_SNOWFLAKE_ID_RADIO = 'radio_snowflake';
const MECHA_SNOWFLAKE_ID_AIR_TANK = 'air_tank_snowflake';
const MECHA_SNOWFLAKE_ID_WEAPON_BALLISTIC = 'ballistic_weapon_snowflake';
const MECHA_SNOWFLAKE_ID_GENERATOR = 'generator_snowflake';
+const MECHA_SNOWFLAKE_ID_ORE_SCANNER = 'orescanner_snowflake';
const MECHA_SNOWFLAKE_ID_CLAW = 'lawclaw_snowflake';
export const ModuleDetailsExtra = (props: { module: MechModule }) => {
@@ -327,6 +328,8 @@ export const ModuleDetailsExtra = (props: { module: MechModule }) => {
return ;
case MECHA_SNOWFLAKE_ID_GENERATOR:
return ;
+ case MECHA_SNOWFLAKE_ID_ORE_SCANNER:
+ return ;
case MECHA_SNOWFLAKE_ID_CLAW:
return ;
default:
@@ -924,6 +927,34 @@ const SnowflakeGeneraor = (props) => {
);
};
+const SnowflakeOreScanner = (props) => {
+ const { act, data } = useBackend();
+ const { ref } = props.module;
+ const { cooldown } = props.module.snowflake;
+ return (
+
+
+ {cooldown / 10 > 0 ? 'Recharging...' : 'Ready to scan vents'}
+
+
+
+ );
+};
+
const SnowflakeLawClaw = (props) => {
const { act, data } = useBackend();
const { ref } = props.module;
diff --git a/tgui/packages/tgui/interfaces/OreBox.tsx b/tgui/packages/tgui/interfaces/OreBox.tsx
index 24fb27bc327..bcafaa72454 100644
--- a/tgui/packages/tgui/interfaces/OreBox.tsx
+++ b/tgui/packages/tgui/interfaces/OreBox.tsx
@@ -6,6 +6,7 @@ import { Window } from '../layouts';
type Data = {
materials: Material[];
+ boulders: number;
};
type Material = {
@@ -19,7 +20,7 @@ mining stachel on your belt or in a pocket while dragging the ore box.`;
export const OreBox = (props) => {
const { act, data } = useBackend();
- const { materials } = data;
+ const { materials, boulders } = data;
return (
@@ -45,6 +46,16 @@ export const OreBox = (props) => {
))}
+ {boulders > 0 && (
+
+ Boulders
+
+
+ {boulders}
+
+
+
+ )}