diff --git a/code/game/objects/structures/ledges.dm b/code/game/objects/structures/ledges.dm
new file mode 100644
index 0000000000..1afa2efb01
--- /dev/null
+++ b/code/game/objects/structures/ledges.dm
@@ -0,0 +1,85 @@
+/obj/structure/ledge
+ name = "rock ledge"
+ desc = "An easily scaleable rocky ledge."
+ icon = 'icons/obj/ledges.dmi'
+ density = 1
+ throwpass = 1
+ climbable = 1
+ anchored = 1
+ var/solidledge = 1
+ flags = ON_BORDER
+ layer = STAIRS_LAYER
+ icon_state = "ledge"
+
+/obj/structure/ledge_corner
+ icon_state = "ledge-corner"
+ flags = 0
+ name = "rock ledge"
+ desc = "An easily scaleable rocky ledge."
+ icon = 'icons/obj/ledges.dmi'
+ density = 1
+ throwpass = 1
+ climbable = 1
+ anchored = 1
+ layer = STAIRS_LAYER
+
+/obj/structure/ledge/ledge_nub
+ desc = "Part of a rocky ledge."
+ icon_state = "ledge-nub"
+ density = 0
+ solidledge = 0
+
+/obj/structure/ledge/ledge_stairs
+ name = "rock stairs"
+ desc = "A colorful set of rocky stairs"
+ icon_state = "ledge-stairs"
+ density = 0
+ solidledge = 0
+
+/obj/structure/ledge/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover) && mover.checkpass(PASSTABLE))
+ return TRUE
+ if(solidledge && get_dir(mover, target) == turn(dir, 180))
+ return !density
+ return TRUE
+
+/obj/structure/ledge/CheckExit(atom/movable/O as mob|obj, target as turf)
+ if(istype(O) && O.checkpass(PASSTABLE))
+ return 1
+ if(solidledge && get_dir(O.loc, target) == dir)
+ return 0
+ return 1
+
+/obj/structure/ledge/do_climb(var/mob/living/user)
+ if(!can_climb(user))
+ return
+
+ usr.visible_message("[user] starts climbing onto \the [src]!")
+ climbers |= user
+
+ if(!do_after(user,(issmall(user) ? 20 : 34)))
+ climbers -= user
+ return
+
+ if(!can_climb(user, post_climb_check=1))
+ climbers -= user
+ return
+
+ if(get_turf(user) == get_turf(src))
+ usr.forceMove(get_step(src, src.dir))
+ else
+ usr.forceMove(get_turf(src))
+
+ usr.visible_message("[user] climbed over \the [src]!")
+ climbers -= user
+
+/obj/structure/ledge/can_climb(var/mob/living/user, post_climb_check=0)
+ if(!..())
+ return 0
+
+ if(get_turf(user) == get_turf(src))
+ var/obj/occupied = neighbor_turf_impassable()
+ if(occupied)
+ to_chat(user, "You can't climb there, there's \a [occupied] in the way.")
+ return 0
+ return 1
\ No newline at end of file
diff --git a/code/modules/mining/mine_outcrops.dm b/code/modules/mining/mine_outcrops.dm
new file mode 100644
index 0000000000..5ce5c5bc94
--- /dev/null
+++ b/code/modules/mining/mine_outcrops.dm
@@ -0,0 +1,117 @@
+/obj/structure/outcrop
+ name = "outcrop"
+ desc = "A boring rocky outcrop."
+ icon = 'icons/obj/outcrop.dmi'
+ density = 1
+ throwpass = 1
+ climbable = 1
+ anchored = 1
+ icon_state = "outcrop"
+ var/mindrop = 5
+ var/upperdrop = 10
+ var/outcropdrop = /obj/item/weapon/ore/glass
+
+/obj/structure/outcrop/Initialize()
+ . = ..()
+ if(prob(1))
+ overlays += image(icon, "[initial(icon_state)]-egg")
+
+/obj/structure/outcrop/diamond
+ name = "shiny outcrop"
+ desc = "A shiny rocky outcrop."
+ icon_state = "outcrop-diamond"
+ mindrop = 2
+ upperdrop = 4
+ outcropdrop = /obj/item/weapon/ore/diamond
+
+/obj/structure/outcrop/phoron
+ name = "shiny outcrop"
+ desc = "A shiny rocky outcrop."
+ icon_state = "outcrop-phoron"
+ mindrop = 4
+ upperdrop = 8
+ outcropdrop = /obj/item/weapon/ore/phoron
+
+/obj/structure/outcrop/iron
+ name = "rugged outcrop"
+ desc = "A rugged rocky outcrop."
+ icon_state = "outcrop-iron"
+ mindrop = 10
+ upperdrop = 20
+ outcropdrop = /obj/item/weapon/ore/iron
+
+/obj/structure/outcrop/coal
+ name = "rugged outcrop"
+ desc = "A rugged rocky outcrop."
+ icon_state = "outcrop-coal"
+ mindrop = 10
+ upperdrop = 20
+ outcropdrop = /obj/item/weapon/ore/coal
+
+/obj/structure/outcrop/lead
+ name = "rugged outcrop"
+ desc = "A rugged rocky outcrop."
+ icon_state = "outcrop-lead"
+ mindrop = 2
+ upperdrop = 5
+ outcropdrop = /obj/item/weapon/ore/lead
+
+/obj/structure/outcrop/gold
+ name = "hollow outcrop"
+ desc = "A hollow rocky outcrop."
+ icon_state = "outcrop-gold"
+ mindrop = 4
+ upperdrop = 6
+ outcropdrop = /obj/item/weapon/ore/gold
+
+/obj/structure/outcrop/silver
+ name = "hollow outcrop"
+ desc = "A hollow rocky outcrop."
+ icon_state = "outcrop-silver"
+ mindrop = 6
+ upperdrop = 8
+ outcropdrop = /obj/item/weapon/ore/silver
+
+/obj/structure/outcrop/platinum
+ name = "hollow outcrop"
+ desc = "A hollow rocky outcrop."
+ icon_state = "outcrop-platinum"
+ mindrop = 2
+ upperdrop = 5
+ outcropdrop = /obj/item/weapon/ore/osmium
+
+/obj/structure/outcrop/uranium
+ name = "spiky outcrop"
+ desc = "A spiky rocky outcrop, it glows faintly."
+ icon_state = "outcrop-uranium"
+ mindrop = 4
+ upperdrop = 8
+ outcropdrop = /obj/item/weapon/ore/uranium
+
+/obj/structure/outcrop/attackby(obj/item/W as obj, mob/user as mob)
+ if (istype(W, /obj/item/weapon/pickaxe))
+ to_chat(user, "[user] begins to hack away at \the [src].")
+ if(do_after(user,40))
+ to_chat(user, "You have finished digging!")
+ for(var/i=0;i<(rand(mindrop,upperdrop));i++)
+ new outcropdrop(get_turf(src))
+ qdel(src)
+ return
+
+/obj/random/outcrop //In case you want an outcrop without pre-determining the type of ore.
+ name = "random rock outcrop"
+ desc = "This is a random rock outcrop."
+ icon = 'icons/obj/outcrop.dmi'
+ icon_state = "outcrop-random"
+
+/obj/random/outcrop/item_to_spawn()
+ return pick(prob(100);/obj/structure/outcrop,
+ prob(100);/obj/structure/outcrop/iron,
+ prob(100);/obj/structure/outcrop/coal,
+ prob(65);/obj/structure/outcrop/silver,
+ prob(50);/obj/structure/outcrop/gold,
+ prob(30);/obj/structure/outcrop/uranium,
+ prob(30);/obj/structure/outcrop/phoron,
+ prob(7);/obj/structure/outcrop/diamond,
+ prob(15);/obj/structure/outcrop/platinum,
+ prob(15);/obj/structure/outcrop/lead)
\ No newline at end of file
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index bb23604a49..7e7d26c1bf 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -11,6 +11,10 @@ var/list/mining_overlay_cache = list()
name = "rock"
icon = 'icons/turf/walls.dmi'
icon_state = "rock"
+ var/rock_side_icon_state = "rock_side"
+ var/sand_icon_state = "asteroid"
+ var/rock_icon_state = "rock"
+ var/random_icon = 0
oxygen = 0
nitrogen = 0
opacity = 1
@@ -54,6 +58,14 @@ var/list/mining_overlay_cache = list()
has_resources = 1
+// Alternative rock wall sprites.
+/turf/simulated/mineral/light
+ icon_state = "rock-light"
+ rock_side_icon_state = "rock_side-light"
+ sand_icon_state = "sand-light"
+ rock_icon_state = "rock-light"
+ random_icon = 1
+
/turf/simulated/mineral/ignore_mapgen
ignore_mapgen = 1
@@ -66,6 +78,23 @@ var/list/mining_overlay_cache = list()
blocks_air = 0
can_build_into_floor = TRUE
+//Alternative sand floor sprite.
+turf/simulated/mineral/floor/light
+ icon_state = "sand-light"
+ sand_icon_state = "sand-light"
+
+turf/simulated/mineral/floor/light_border
+ icon_state = "sand-light-border"
+ sand_icon_state = "sand-light-border"
+
+turf/simulated/mineral/floor/light_nub
+ icon_state = "sand-light-nub"
+ sand_icon_state = "sand-light-nub"
+
+turf/simulated/mineral/floor/light_corner
+ icon_state = "sand-light-corner"
+ sand_icon_state = "sand-light-corner"
+
/turf/simulated/mineral/floor/ignore_mapgen
ignore_mapgen = 1
@@ -130,6 +159,9 @@ var/list/mining_overlay_cache = list()
update_icon(1)
if(density && mineral)
. = INITIALIZE_HINT_LATELOAD
+ if(random_icon)
+ dir = pick(alldirs)
+ . = INITIALIZE_HINT_LATELOAD
/turf/simulated/mineral/LateInitialize()
if(density && mineral)
@@ -147,13 +179,13 @@ var/list/mining_overlay_cache = list()
name = "rock"
icon = 'icons/turf/walls.dmi'
- icon_state = "rock"
+ icon_state = rock_icon_state
//Apply overlays if we should have borders
for(var/direction in cardinal)
var/turf/T = get_step(src,direction)
if(istype(T) && !T.density)
- add_overlay(get_cached_border("rock_side",direction,icon,"rock_side"))
+ add_overlay(get_cached_border(rock_side_icon_state,direction,icon,rock_side_icon_state))
if(archaeo_overlay)
add_overlay(archaeo_overlay)
@@ -165,7 +197,7 @@ var/list/mining_overlay_cache = list()
else
name = "sand"
icon = 'icons/turf/flooring/asteroid.dmi'
- icon_state = "asteroid"
+ icon_state = sand_icon_state
if(sand_dug)
add_overlay("dug_overlay")
@@ -179,7 +211,7 @@ var/list/mining_overlay_cache = list()
else
var/turf/T = get_step(src, direction)
if(istype(T) && T.density)
- add_overlay(get_cached_border("rock_side",direction,'icons/turf/walls.dmi',"rock_side"))
+ add_overlay(get_cached_border(rock_side_icon_state,direction,'icons/turf/walls.dmi',rock_side_icon_state))
if(overlay_detail)
add_overlay('icons/turf/flooring/decals.dmi',overlay_detail)
diff --git a/icons/obj/ledges.dmi b/icons/obj/ledges.dmi
new file mode 100644
index 0000000000..a292ee0a9b
Binary files /dev/null and b/icons/obj/ledges.dmi differ
diff --git a/icons/obj/outcrop.dmi b/icons/obj/outcrop.dmi
new file mode 100644
index 0000000000..bea3810fe8
Binary files /dev/null and b/icons/obj/outcrop.dmi differ
diff --git a/icons/turf/flooring/asteroid.dmi b/icons/turf/flooring/asteroid.dmi
index f623dfeb8e..f9c0b2cdf8 100644
Binary files a/icons/turf/flooring/asteroid.dmi and b/icons/turf/flooring/asteroid.dmi differ
diff --git a/icons/turf/walls.dmi b/icons/turf/walls.dmi
index 1569985184..52f1fa13e3 100644
Binary files a/icons/turf/walls.dmi and b/icons/turf/walls.dmi differ
diff --git a/polaris.dme b/polaris.dme
index fe78da6b6a..646b599622 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1091,6 +1091,7 @@
#include "code\game\objects\structures\janicart.dm"
#include "code\game\objects\structures\kitchen_spike.dm"
#include "code\game\objects\structures\lattice.dm"
+#include "code\game\objects\structures\ledges.dm"
#include "code\game\objects\structures\lightpost.dm"
#include "code\game\objects\structures\loot_piles.dm"
#include "code\game\objects\structures\mirror.dm"
@@ -1803,6 +1804,7 @@
#include "code\modules\mining\machine_stacking.dm"
#include "code\modules\mining\machine_unloading.dm"
#include "code\modules\mining\mine_items.dm"
+#include "code\modules\mining\mine_outcrops.dm"
#include "code\modules\mining\mine_turfs.dm"
#include "code\modules\mining\mineral_effect.dm"
#include "code\modules\mining\mint.dm"