diff --git a/_maps/templates/shelter_1.dmm b/_maps/templates/shelter_1.dmm
new file mode 100644
index 00000000000..0c601ae2fdc
--- /dev/null
+++ b/_maps/templates/shelter_1.dmm
@@ -0,0 +1,23 @@
+"a" = (/turf/closed/wall/shuttle/survival/pod,/area/survivalpod)
+"b" = (/obj/structure/sign/mining/survival{tag = "icon-survival (NORTH)"; icon_state = "survival"; dir = 1},/turf/closed/wall/shuttle/survival/pod,/area/survivalpod)
+"c" = (/obj/structure/fans,/turf/open/floor/pod,/area/survivalpod)
+"d" = (/obj/machinery/smartfridge/survival_pod,/turf/open/floor/pod,/area/survivalpod)
+"e" = (/obj/item/device/gps/computer,/turf/open/floor/pod,/area/survivalpod)
+"f" = (/obj/structure/sign/mining/survival{dir = 8},/turf/closed/wall/shuttle/survival/pod,/area/survivalpod)
+"g" = (/obj/machinery/sleeper/survival_pod,/turf/open/floor/pod,/area/survivalpod)
+"h" = (/turf/open/floor/pod,/area/survivalpod)
+"i" = (/obj/structure/bed/pod,/obj/item/weapon/bedsheet/black,/turf/open/floor/pod,/area/survivalpod)
+"j" = (/obj/structure/sign/mining/survival{tag = "icon-survival (EAST)"; icon_state = "survival"; dir = 4},/turf/closed/wall/shuttle/survival/pod,/area/survivalpod)
+"k" = (/obj/structure/table/survival_pod,/turf/open/floor/pod,/area/survivalpod)
+"l" = (/obj/structure/tubes,/obj/structure/chair/comfy/black{dir = 8},/turf/open/floor/pod,/area/survivalpod)
+"m" = (/obj/structure/sign/mining/survival,/turf/closed/wall/shuttle/survival/pod,/area/survivalpod)
+"n" = (/obj/structure/fans/tiny,/obj/machinery/door/airlock/survival_pod,/turf/open/floor/pod,/area/survivalpod)
+"o" = (/obj/structure/sign/mining,/turf/closed/wall/shuttle/survival/pod,/area/survivalpod)
+
+(1,1,1) = {"
+aabaa
+acdea
+fghij
+akhla
+amnoa
+"}
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index bcfbdc8e37c..80f9fda0168 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -448,5 +448,13 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define SLIME_FRIENDSHIP_STAY 3 //Min friendship to order it to stay
#define SLIME_FRIENDSHIP_ATTACK 8 //Min friendship to order it to attack
+
#define DEADCHAT_DEATHRATTLE "deathrattle"
#define DEADCHAT_REGULAR "regular-deadchat"
+
+// Bluespace shelter deploy checks
+#define SHELTER_DEPLOY_ALLOWED "allowed"
+#define SHELTER_DEPLOY_BAD_TURFS "bad turfs"
+#define SHELTER_DEPLOY_BAD_AREA "bad area"
+#define SHELTER_DEPLOY_ANCHORED_OBJECTS "anchored objects"
+
diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm
index b88a9362eb4..ac4bc050b30 100644
--- a/code/_globalvars/lists/mapping.dm
+++ b/code/_globalvars/lists/mapping.dm
@@ -62,3 +62,4 @@ var/list/datum/map_template/space_ruins_templates = list()
var/list/datum/map_template/lava_ruins_templates = list()
var/list/datum/map_template/shuttle_templates = list()
+var/list/datum/map_template/shelter_templates = list()
diff --git a/code/datums/helper_datums/map_template.dm b/code/datums/helper_datums/map_template.dm
index a6bd818abad..58314f4fbae 100644
--- a/code/datums/helper_datums/map_template.dm
+++ b/code/datums/helper_datums/map_template.dm
@@ -87,6 +87,7 @@
preloadRuinTemplates()
preloadShuttleTemplates()
+ preloadShelterTemplates()
/proc/preloadRuinTemplates()
// Still supporting bans by filename
@@ -122,3 +123,13 @@
shuttle_templates[S.shuttle_id] = S
map_templates[S.shuttle_id] = S
+
+/proc/preloadShelterTemplates()
+ for(var/item in subtypesof(/datum/map_template/shelter))
+ var/datum/map_template/shelter/shelter_type = item
+ if(!(initial(shelter_type.mappath)))
+ continue
+ var/datum/map_template/shelter/S = new shelter_type()
+
+ shelter_templates[S.shelter_id] = S
+ map_templates[S.shelter_id] = S
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index 475e987361a..b03124a9b1b 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -205,133 +205,63 @@
icon = 'icons/obj/mining.dmi'
w_class = 1
origin_tech = "engineering=3;bluespace=3"
+ var/template_id = "shelter_alpha"
+ var/datum/map_template/shelter/template
var/used = FALSE
+/obj/item/weapon/survivalcapsule/proc/get_template()
+ if(template)
+ return
+ template = shelter_templates[template_id]
+ if(!template)
+ throw EXCEPTION("Shelter template ([template_id]) not found!")
+ qdel(src)
+
+/obj/item/weapon/survivalcapsule/Destroy()
+ template = null // without this, capsules would be one use. per round.
+ . = ..()
+
+/obj/item/weapon/survivalcapsule/examine(mob/user)
+ . = ..()
+ get_template()
+ user << "This capsule has the [template.name] stored."
+ user << template.description
+
/obj/item/weapon/survivalcapsule/attack_self()
+ // Can't grab when capsule is New() because templates aren't loaded then
+ get_template()
if(used == FALSE)
- src.loc.visible_message("\The [src] begins to shake. Stand back!")
+ src.loc.visible_message("\The [src] begins \
+ to shake. Stand back!")
used = TRUE
sleep(50)
- var/turf/T = get_turf(src)
- var/clear = TRUE
- for(var/turf/turf in range(2,T))
- if(istype(turf, /turf/closed) && !istype(turf, /turf/closed/mineral))
- clear = FALSE
- break
- for(var/obj/obj in turf)
- if(obj.density && obj.anchored)
- clear = FALSE
- break
- if(!clear)
- src.loc.visible_message("\The [src] doesn't have room to deploy! You need to clear a 5x5 area!")
+ var/turf/deploy_location = get_turf(src)
+ var/status = template.check_deploy(deploy_location)
+ switch(status)
+ if(SHELTER_DEPLOY_BAD_AREA)
+ src.loc.visible_message("\The [src] \
+ will not function in this area.")
+ if(SHELTER_DEPLOY_BAD_TURFS, SHELTER_DEPLOY_ANCHORED_OBJECTS)
+ var/width = template.width
+ var/height = template.height
+ src.loc.visible_message("\The [src] \
+ doesn't have room to deploy! You need to clear a \
+ [width]x[height] area!")
+
+ if(status != SHELTER_DEPLOY_ALLOWED)
used = FALSE
return
+
playsound(get_turf(src), 'sound/effects/phasein.ogg', 100, 1)
- PoolOrNew(/obj/effect/particle_effect/smoke, src.loc)
+
+ var/turf/T = deploy_location
if(T.z != ZLEVEL_MINING && T.z != ZLEVEL_LAVALAND)//only report capsules away from the mining/lavaland level
message_admins("[key_name_admin(usr)] (?) (FLW) activated a bluespace capsule away from the mining level! (JMP)")
log_admin("[key_name(usr)] activated a bluespace capsule away from the mining level at [T.x], [T.y], [T.z]")
- load()
+ template.load(deploy_location, centered = TRUE)
+ PoolOrNew(/obj/effect/particle_effect/smoke, get_turf(src))
qdel(src)
-/obj/item/weapon/survivalcapsule/proc/load()
- var/turf/start_turf = get_turf(src.loc)
- var/turf/cur_turf
- var/x_size = 5
- var/y_size = 5
- var/list/walltypes = list(/turf/closed/wall/shuttle/survival/pod)
- var/floor_type = /turf/open/floor/pod
- var/room
- var/onshuttle = 0
-
- //Center the room/spawn it
- start_turf = locate(start_turf.x -2, start_turf.y - 2, start_turf.z)
-
- var/area/A = get_area(src)
- if(istype(A, /area/shuttle))
- onshuttle = 1
- room = spawn_room(start_turf, x_size, y_size, walltypes, floor_type, "Emergency Shelter", onshuttle)
-
- start_turf = get_turf(src.loc)
-
- //Fill it
-
- //The door
- cur_turf = locate(start_turf.x, start_turf.y-2, start_turf.z)
- new /obj/machinery/door/airlock/survival_pod(cur_turf)
-
-
- //Bed middle right
- cur_turf = locate(start_turf.x+1, start_turf.y, start_turf.z)
- new /obj/structure/bed/pod(cur_turf)
- new /obj/item/weapon/bedsheet/black(cur_turf)
-
- //Chair bottom right
- cur_turf = locate(start_turf.x+1, start_turf.y-1, start_turf.z)
- new /obj/structure/tubes(cur_turf)
- var/obj/structure/chair/comfy/black/C = new (cur_turf)
- C.dir = 8
-
- //GPS computer top right
- cur_turf = locate(start_turf.x+1, start_turf.y+1, start_turf.z)
- new /obj/item/device/gps/computer(cur_turf)
-
- //Donk Pocket Storage Top/middle
- cur_turf = locate(start_turf.x, start_turf.y+1, start_turf.z)
- new /obj/machinery/smartfridge/survival_pod(cur_turf)
-
- //Table in Bottom Left
- cur_turf = locate(start_turf.x-1, start_turf.y-1, start_turf.z)
- new /obj/structure/table/survival_pod(cur_turf)
-
- //Sleeper Middle Left
- cur_turf = locate(start_turf.x-1, start_turf.y, start_turf.z)
- new /obj/machinery/sleeper/survival_pod(cur_turf)
-
- //Fans Top Left
- cur_turf = locate(start_turf.x-1, start_turf.y+1, start_turf.z)
- new /obj/structure/fans(cur_turf)
-
- //Signs
- cur_turf = locate(start_turf.x-2, start_turf.y, start_turf.z)
- var/obj/structure/sign/mining/survival/S1 = new(cur_turf)
- S1.dir = WEST
-
- cur_turf = locate(start_turf.x+2, start_turf.y, start_turf.z)
- var/obj/structure/sign/mining/survival/S2 = new(cur_turf)
- S2.dir = EAST
-
- cur_turf = locate(start_turf.x, start_turf.y+2, start_turf.z)
- var/obj/structure/sign/mining/survival/S3 = new(cur_turf)
- S3.dir = NORTH
-
- cur_turf = locate(start_turf.x-1, start_turf.y-2, start_turf.z)
- var/obj/structure/sign/mining/survival/S4 = new(cur_turf)
- S4.dir = SOUTH
-
- cur_turf = locate(start_turf.x+1, start_turf.y-2, start_turf.z)
- new /obj/structure/sign/mining(cur_turf)
-
- var/area/survivalpod/L = new /area/survivalpod
-
- var/turf/threshhold = locate(start_turf.x, start_turf.y-2, start_turf.z)
- threshhold.ChangeTurf(/turf/open/floor/pod)
- var/turf/open/floor/pod/doorturf = threshhold
- doorturf.air.parse_gas_string("o2=21;n2=82;TEMP=293.15")
- if(!onshuttle)
- L.contents += threshhold
- threshhold.overlays.Cut()
-
- new /obj/structure/fans/tiny(threshhold) //a tiny fan, to keep the air in.
-
- var/list/turfs = room["floors"]
- for(var/turf/open/floor/F in turfs)
- F.air.parse_gas_string("o2=21;n2=82;TEMP=293.15")
- F.overlays.Cut()
- if(!onshuttle)
- L.contents += F
-
-
//Pod turfs and objects
diff --git a/code/modules/mining/shelters.dm b/code/modules/mining/shelters.dm
new file mode 100644
index 00000000000..efb14b9b146
--- /dev/null
+++ b/code/modules/mining/shelters.dm
@@ -0,0 +1,42 @@
+/datum/map_template/shelter
+ var/shelter_id
+ var/description
+ var/blacklisted_turfs
+ var/whitelisted_turfs
+ var/banned_areas
+
+/datum/map_template/shelter/New()
+ . = ..()
+ blacklisted_turfs = typecacheof(/turf/closed)
+ whitelisted_turfs = list()
+ banned_areas = typecacheof(/area/shuttle)
+
+/datum/map_template/shelter/proc/check_deploy(turf/deploy_location)
+ var/affected = get_affected_turfs(deploy_location, centered=TRUE)
+ for(var/turf/T in affected)
+ var/area/A = get_area(T)
+ if(is_type_in_typecache(A, banned_areas))
+ return SHELTER_DEPLOY_BAD_AREA
+
+ var/banned = is_type_in_typecache(T, blacklisted_turfs)
+ var/permitted = is_type_in_typecache(T, whitelisted_turfs)
+ if(banned && !permitted)
+ return SHELTER_DEPLOY_BAD_TURFS
+
+ for(var/obj/O in T)
+ if(O.density && O.anchored)
+ return SHELTER_DEPLOY_ANCHORED_OBJECTS
+ return SHELTER_DEPLOY_ALLOWED
+
+/datum/map_template/shelter/alpha
+ name = "Shelter Alpha"
+ shelter_id = "shelter_alpha"
+ description = "A cosy self-contained pressurized shelter, with \
+ built-in navigation, entertainment, medical facilities and a \
+ sleeping area! Order now, and we'll throw in a TINY FAN, \
+ absolutely free!"
+ mappath = "_maps/templates/shelter_1.dmm"
+
+/datum/map_template/shelter/alpha/New()
+ . = ..()
+ whitelisted_turfs = typecacheof(/turf/closed/mineral)
diff --git a/tgstation.dme b/tgstation.dme
index b90a016d52a..a1062f3055f 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1227,6 +1227,7 @@
#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\shelters.dm"
#include "code\modules\mining\laborcamp\laborminerals.dm"
#include "code\modules\mining\laborcamp\laborshuttle.dm"
#include "code\modules\mining\laborcamp\laborstacker.dm"