diff --git a/code/LINDA/LINDA_turf_tile.dm b/code/LINDA/LINDA_turf_tile.dm
index 63e5e4fe325..3aeacb942a7 100644
--- a/code/LINDA/LINDA_turf_tile.dm
+++ b/code/LINDA/LINDA_turf_tile.dm
@@ -56,10 +56,6 @@
/turf/simulated/New()
..()
- levelupdate()
- if(smooth)
- smooth_icon(src)
- visibilityChanged()
if(!blocks_air)
air = new
@@ -259,7 +255,7 @@
atmos_overlay = get_atmos_overlay_by_name(new_overlay_type)
if (atmos_overlay)
overlays += atmos_overlay
- atmos_overlay_type = new_overlay_type
+ atmos_overlay_type = new_overlay_type
/turf/simulated/proc/get_atmos_overlay_by_name(var/name)
switch(name)
diff --git a/code/__HELPERS/icon_smoothing.dm b/code/__HELPERS/icon_smoothing.dm
index 5ae2ddb07a8..d9b7091247f 100644
--- a/code/__HELPERS/icon_smoothing.dm
+++ b/code/__HELPERS/icon_smoothing.dm
@@ -61,81 +61,80 @@
/proc/smooth_icon(atom/A)
if(qdeleted(A))
return
- spawn(0) //don't remove this, otherwise smoothing breaks
- if(A && A.smooth)
- var/adjacencies = calculate_adjacencies(A)
+ if(A && A.smooth)
+ var/adjacencies = calculate_adjacencies(A)
- //NW CORNER
- var/nw = "1-i"
- if((adjacencies & N_NORTH) && (adjacencies & N_WEST))
- if(adjacencies & N_NORTHWEST)
- nw = "1-f"
- else
- nw = "1-nw"
+ //NW CORNER
+ var/nw = "1-i"
+ if((adjacencies & N_NORTH) && (adjacencies & N_WEST))
+ if(adjacencies & N_NORTHWEST)
+ nw = "1-f"
else
- if(adjacencies & N_NORTH)
- nw = "1-n"
- else if(adjacencies & N_WEST)
- nw = "1-w"
+ nw = "1-nw"
+ else
+ if(adjacencies & N_NORTH)
+ nw = "1-n"
+ else if(adjacencies & N_WEST)
+ nw = "1-w"
- //NE CORNER
- var/ne = "2-i"
- if((adjacencies & N_NORTH) && (adjacencies & N_EAST))
- if(adjacencies & N_NORTHEAST)
- ne = "2-f"
- else
- ne = "2-ne"
+ //NE CORNER
+ var/ne = "2-i"
+ if((adjacencies & N_NORTH) && (adjacencies & N_EAST))
+ if(adjacencies & N_NORTHEAST)
+ ne = "2-f"
else
- if(adjacencies & N_NORTH)
- ne = "2-n"
- else if(adjacencies & N_EAST)
- ne = "2-e"
+ ne = "2-ne"
+ else
+ if(adjacencies & N_NORTH)
+ ne = "2-n"
+ else if(adjacencies & N_EAST)
+ ne = "2-e"
- //SW CORNER
- var/sw = "3-i"
- if((adjacencies & N_SOUTH) && (adjacencies & N_WEST))
- if(adjacencies & N_SOUTHWEST)
- sw = "3-f"
- else
- sw = "3-sw"
+ //SW CORNER
+ var/sw = "3-i"
+ if((adjacencies & N_SOUTH) && (adjacencies & N_WEST))
+ if(adjacencies & N_SOUTHWEST)
+ sw = "3-f"
else
- if(adjacencies & N_SOUTH)
- sw = "3-s"
- else if(adjacencies & N_WEST)
- sw = "3-w"
+ sw = "3-sw"
+ else
+ if(adjacencies & N_SOUTH)
+ sw = "3-s"
+ else if(adjacencies & N_WEST)
+ sw = "3-w"
- //SE CORNER
- var/se = "4-i"
- if((adjacencies & N_SOUTH) && (adjacencies & N_EAST))
- if(adjacencies & N_SOUTHEAST)
- se = "4-f"
- else
- se = "4-se"
+ //SE CORNER
+ var/se = "4-i"
+ if((adjacencies & N_SOUTH) && (adjacencies & N_EAST))
+ if(adjacencies & N_SOUTHEAST)
+ se = "4-f"
else
- if(adjacencies & N_SOUTH)
- se = "4-s"
- else if(adjacencies & N_EAST)
- se = "4-e"
+ se = "4-se"
+ else
+ if(adjacencies & N_SOUTH)
+ se = "4-s"
+ else if(adjacencies & N_EAST)
+ se = "4-e"
- if(A.top_left_corner != nw)
- A.overlays -= A.top_left_corner
- A.top_left_corner = nw
- A.overlays += nw
+ if(A.top_left_corner != nw)
+ A.overlays -= A.top_left_corner
+ A.top_left_corner = nw
+ A.overlays += nw
- if(A.top_right_corner != ne)
- A.overlays -= A.top_right_corner
- A.top_right_corner = ne
- A.overlays += ne
+ if(A.top_right_corner != ne)
+ A.overlays -= A.top_right_corner
+ A.top_right_corner = ne
+ A.overlays += ne
- if(A.bottom_right_corner != sw)
- A.overlays -= A.bottom_right_corner
- A.bottom_right_corner = sw
- A.overlays += sw
+ if(A.bottom_right_corner != sw)
+ A.overlays -= A.bottom_right_corner
+ A.bottom_right_corner = sw
+ A.overlays += sw
- if(A.bottom_left_corner != se)
- A.overlays -= A.bottom_left_corner
- A.bottom_left_corner = se
- A.overlays += se
+ if(A.bottom_left_corner != se)
+ A.overlays -= A.bottom_left_corner
+ A.bottom_left_corner = se
+ A.overlays += se
/proc/find_type_in_direction(atom/source, direction, range=1)
var/x_offset = 0
diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm
index 52d05ac6d65..6641bf50e7d 100644
--- a/code/_globalvars/lists/misc.dm
+++ b/code/_globalvars/lists/misc.dm
@@ -1,5 +1,5 @@
var/global/list/alphabet = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
-var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
+var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
var/global/list/zero_character_only = list("0")
var/global/list/hex_characters = list("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f")
var/global/list/binary = list("0","1")
@@ -22,3 +22,5 @@ var/list/restricted_camera_networks = list( //Those networks can only be accesse
"UO45R",
"Xeno"
)
+
+var/list/datum/map_template/map_templates = list()
\ No newline at end of file
diff --git a/code/controllers/Processes/air.dm b/code/controllers/Processes/air.dm
index 58456b76d8b..4846b850790 100644
--- a/code/controllers/Processes/air.dm
+++ b/code/controllers/Processes/air.dm
@@ -30,8 +30,8 @@ var/global/datum/controller/process/air_system/air_master
var/watch = start_watch()
log_startup_progress("Processing geometry...")
- setup_allturfs() // Get all currently active tiles that need processing each atmos tick.
setup_overlays() // Assign icons and such for gas-turf-overlays
+ setup_allturfs() // Get all currently active tiles that need processing each atmos tick.
log_startup_progress(" Geometry processed in [stop_watch(watch)]s.")
/datum/controller/process/air_system/doWork()
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 3aa23ee09f9..d2bd83461f8 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -41,6 +41,7 @@ datum/controller/game_controller/New()
datum/controller/game_controller/proc/setup()
world.tick_lag = config.Ticklag
+ preloadTemplates()
if(!config.disable_away_missions)
createRandomZlevel()
@@ -58,12 +59,12 @@ datum/controller/game_controller/proc/setup_objects()
var/watch = start_watch()
var/count = 0
var/overwatch = start_watch() // Overall.
-
+
log_startup_progress("Populating asset cache...")
populate_asset_cache()
log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
- watch = start_watch()
+ watch = start_watch()
log_startup_progress("Initializing objects...")
for(var/atom/movable/object in world)
object.initialize()
@@ -82,8 +83,8 @@ datum/controller/game_controller/proc/setup_objects()
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
T.broadcast_status()
count++
- log_startup_progress(" Initialized [count] atmospherics machines in [stop_watch(watch)]s.")
-
+ log_startup_progress(" Initialized [count] atmospherics machines in [stop_watch(watch)]s.")
+
watch = start_watch()
count = 0
log_startup_progress("Initializing pipe networks...")
@@ -91,5 +92,5 @@ datum/controller/game_controller/proc/setup_objects()
machine.build_network()
count++
log_startup_progress(" Initialized [count] pipe networks in [stop_watch(watch)]s.")
-
+
log_startup_progress("Finished object initializations in [stop_watch(overwatch)]s.")
diff --git a/code/datums/helper_datums/map_template.dm b/code/datums/helper_datums/map_template.dm
new file mode 100644
index 00000000000..22419fa6edb
--- /dev/null
+++ b/code/datums/helper_datums/map_template.dm
@@ -0,0 +1,67 @@
+/datum/map_template
+ var/name = "Default Template Name"
+ var/width = 0
+ var/height = 0
+ var/mappath = null
+ var/mapfile = null
+ var/loaded = 0 // Times loaded this round
+
+/datum/map_template/New(path = null, map = null, rename = null)
+ if(path)
+ mappath = path
+ preload_size(mappath)
+ if(map)
+ mapfile = map
+ if(rename)
+ name = rename
+
+/datum/map_template/proc/preload_size(path)
+ var/quote = ascii2text(34)
+ var/map_file = file2text(path)
+ var/key_len = length(copytext(map_file,2,findtext(map_file,quote,2,0)))
+ //assuming one map per file since more makes no sense for templates anyway
+ var/mapstart = findtext(map_file,"\n(1,1,") //todo replace with something saner
+ var/content = copytext(map_file,findtext(map_file,quote+"\n",mapstart,0)+2,findtext(map_file,"\n"+quote,mapstart,0)+1)
+ var/line_len = length(copytext(content,1,findtext(content,"\n",2,0)))
+
+ width = line_len/key_len
+ height = length(content)/(line_len+1)
+
+/datum/map_template/proc/load(turf/T, centered = 0)
+ if(centered)
+ T = locate(T.x - round(width / 2), T.y - round(height / 2), T.z)
+ if(!T)
+ return
+ if(T.x+width > world.maxx)
+ return
+ if(T.y+height > world.maxy)
+ return
+
+ maploader.load_map(get_file(), T.x-1, T.y-1, T.z)
+ late_setup_level(
+ block(T, locate(T.x + width - 1, T.y + height - 1, T.z)),
+ block(locate(T.x - 1, T.y - 1, T.z), locate(T.x + width, T.y + height, T.z)))
+
+ log_game("[name] loaded at at [T.x],[T.y],[T.z]")
+
+/datum/map_template/proc/get_file()
+ if(mapfile)
+ return mapfile
+ if(mappath)
+ mapfile = file(mappath)
+ return mapfile
+
+/datum/map_template/proc/get_affected_turfs(turf/T, centered = 0)
+ var/turf/placement = T
+ if(centered)
+ var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z)
+ if(corner)
+ placement = corner
+ return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z))
+
+
+/proc/preloadTemplates(path = "_maps/map_files/templates/") //see master controller setup
+ var/list/filelist = flist(path)
+ for(var/map in filelist)
+ var/datum/map_template/T = new(path = "[path][map]", rename = "[map]")
+ map_templates[T.name] = T
\ No newline at end of file
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 952a647f3aa..2bcabd8ac15 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -30,8 +30,9 @@
/obj/structure/New()
..()
if(smooth)
- smooth_icon(src)
- smooth_icon_neighbors(src)
+ if(ticker && ticker.current_state == GAME_STATE_PLAYING)
+ smooth_icon(src)
+ smooth_icon_neighbors(src)
icon_state = ""
if(climbable)
verbs += /obj/structure/proc/climb_on
@@ -42,7 +43,9 @@
if(ticker)
cameranet.updateVisibility(src)
if(smooth)
- smooth_icon_neighbors(src)
+ var/turf/T = get_turf(src)
+ spawn(0)
+ smooth_icon_neighbors(T)
return ..()
/obj/structure/proc/climb_on()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index ad478bb3893..17a4233ffa9 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -33,7 +33,8 @@
for(var/obj/structure/table/T in src.loc)
if(T != src)
qdel(T)
- update_icon()
+ if(flipped)
+ update_icon()
/obj/structure/table/proc/destroy()
new parts(loc)
@@ -221,9 +222,10 @@
return
if (istype(W, /obj/item/weapon/wrench))
- to_chat(user, "\blue Now disassembling table")
- playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
- if(do_after(user,50, target = src))
+ user.visible_message("[user] is disassembling \a [src].", "You start disassembling \the [src].")
+ playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
+ if(do_after(user, 50, target = src))
+ playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1)
destroy()
return
@@ -367,55 +369,18 @@
parts = /obj/item/weapon/table_parts/wood
health = 50
canSmoothWith = list(/obj/structure/table/woodentable, /obj/structure/table/woodentable/poker)
+ var/canPokerize = 1
/obj/structure/table/woodentable/attackby(obj/item/I as obj, mob/user as mob, params)
-
- if (istype(I, /obj/item/stack/tile/grass))
+ if(canPokerize && istype(I, /obj/item/stack/tile/grass))
var/obj/item/stack/tile/grass/gr = I
gr.use(1)
new /obj/structure/table/woodentable/poker( src.loc )
qdel(src)
visible_message("[user] adds the grass to the wooden table")
-
-
- if (istype(I, /obj/item/weapon/grab))
- tablepush(I, user)
- return
-
- if (istype(I, /obj/item/weapon/wrench))
- to_chat(user, "\blue Now disassembling the wooden table")
- playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
- sleep(50)
- new /obj/item/weapon/table_parts/wood( src.loc )
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- qdel(src)
- return
-
- if(isrobot(user))
- return
- if(istype(I, /obj/item/weapon/melee/energy/blade))
- var/datum/effect/system/spark_spread/spark_system = new /datum/effect/system/spark_spread()
- spark_system.set_up(5, 0, src.loc)
- spark_system.start()
- playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1)
- playsound(src.loc, "sparks", 50, 1)
- for(var/mob/O in viewers(user, 4))
- O.show_message("\blue The wooden table was sliced apart by [user]!", 1, "\red You hear wood coming apart.", 2)
- new /obj/item/weapon/table_parts/wood( src.loc )
- qdel(src)
- return
-
- if(!(I.flags & ABSTRACT) && !(istype(I, /obj/item/stack/tile/grass)))
- if(user.drop_item())
- I.Move(loc)
- var/list/click_params = params2list(params)
- //Center the icon where the user clicked.
- if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
- return
- //Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- I.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- I.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
-
+ return 1
+ else
+ return ..()
return 1
@@ -425,51 +390,11 @@
icon = 'icons/obj/smooth_structures/poker_table.dmi'
icon_state = "pokertable"
canSmoothWith = list(/obj/structure/table/woodentable/poker, /obj/structure/table/woodentable)
+ canPokerize = 0
-
-/obj/structure/table/woodentable/poker/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
-
- if (istype(W, /obj/item/weapon/grab))
- tablepush(W, user)
- return
-
- if (istype(W, /obj/item/weapon/wrench))
- to_chat(user, "\blue Now disassembling the wooden table")
- playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
- sleep(50)
- new /obj/item/weapon/table_parts/wood( src.loc )
- new /obj/item/stack/tile/grass( src.loc)
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- qdel(src)
- return
-
- if(isrobot(user))
- return
- if(istype(W, /obj/item/weapon/melee/energy/blade))
- var/datum/effect/system/spark_spread/spark_system = new /datum/effect/system/spark_spread()
- spark_system.set_up(5, 0, src.loc)
- spark_system.start()
- playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1)
- playsound(src.loc, "sparks", 50, 1)
- for(var/mob/O in viewers(user, 4))
- O.show_message("\blue The wooden table was sliced apart by [user]!", 1, "\red You hear wood coming apart.", 2)
- new /obj/item/weapon/table_parts/wood( src.loc )
- new /obj/item/stack/tile/grass( src.loc)
- qdel(src)
- return
-
- if(!(W.flags & ABSTRACT))
- if(user.drop_item())
- W.Move(loc)
- var/list/click_params = params2list(params)
- //Center the icon where the user clicked.
- if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
- return
- //Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- W.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- W.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
-
- return 1
+/obj/structure/table/woodentable/poker/destroy()
+ new /obj/item/stack/tile/grass(loc)
+ ..()
/obj/structure/glasstable_frame
name = "glass table frame"
@@ -513,64 +438,24 @@
canSmoothWith = null
/obj/structure/table/glass/flip(var/direction)
- src.collapse()
+ collapse()
/obj/structure/table/glass/proc/collapse() //glass table collapse is called twice in this code, more efficent to just have a proc
src.visible_message("\The [src] shatters, and the frame collapses!", "You hear metal collapsing and glass shattering.")
playsound(src.loc, "shatter", 50, 1)
- new /obj/item/weapon/table_parts/glass(loc)
- new /obj/item/weapon/shard(loc)
- qdel(src)
+ destroy(1)
+
+/obj/structure/table/glass/destroy(dirty)
+ if(dirty)
+ new /obj/item/weapon/shard(loc)
+ else
+ new /obj/item/stack/sheet/glass(loc)
+ ..()
/obj/structure/table/glass/tablepush(obj/item/I, mob/user)
if(..())
collapse()
-/obj/structure/table/glass/attackby(obj/item/I as obj, mob/user as mob, params)
-
- if (istype(I, /obj/item/weapon/grab))
- tablepush(I, user)
- return
-
- if (istype(I, /obj/item/weapon/wrench))
- to_chat(user, "\blue Now disassembling the glass table")
- playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
- sleep(50)
- new /obj/item/weapon/table_parts/glass( src.loc )
- new /obj/item/stack/sheet/glass( src.loc )
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- qdel(src)
- return
-
- if(isrobot(user))
- return
- if(istype(I, /obj/item/weapon/melee/energy/blade))
- var/datum/effect/system/spark_spread/spark_system = new /datum/effect/system/spark_spread()
- spark_system.set_up(5, 0, src.loc)
- spark_system.start()
- playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1)
- playsound(src.loc, "sparks", 50, 1)
- for(var/mob/O in viewers(user, 4))
- O.show_message("\The [src] was sliced apart by [user]!", 1, "You hear glass being sliced apart.", 2)
- new /obj/item/weapon/table_parts/glass( src.loc )
- new /obj/item/stack/sheet/glass( src.loc )
- qdel(src)
- return
-
- if(!(I.flags & ABSTRACT))
- if(user.drop_item())
- I.Move(loc)
- var/list/click_params = params2list(params)
- //Center the icon where the user clicked.
- if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
- return
- //Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- I.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- I.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
-
- return 1
-
-
/*
* Reinforced tables
*/
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index 9023edcda55..be8828a2dc9 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -14,6 +14,7 @@
/turf/simulated/New()
..()
levelupdate()
+ visibilityChanged()
/turf/simulated/proc/burn_tile()
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index 0a569d91378..a328769d8dc 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -62,8 +62,8 @@
/turf/simulated/floor/carpet/New()
..()
- spawn(1)
- update_icon()
+ if(broken || burnt)
+ make_plating()
/turf/simulated/floor/carpet/update_icon()
if(!..())
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 363b7d7b150..7c0035cc445 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -37,6 +37,21 @@
..()
for(var/atom/movable/AM in src)
Entered(AM)
+ if(smooth && ticker && ticker.current_state == GAME_STATE_PLAYING)
+ smooth_icon(src)
+
+/hook/startup/proc/smooth_world()
+ var/watch = start_watch()
+ log_startup_progress("Smoothing atoms...")
+ for(var/turf/T in world)
+ if(T.smooth)
+ smooth_icon(T)
+ for(var/A in T)
+ var/atom/AA = A
+ if(AA.smooth)
+ smooth_icon(AA)
+ log_startup_progress(" Smoothed atoms in [stop_watch(watch)]s.")
+ return 1
/turf/Destroy()
// Adds the adjacent turfs to the current atmos processing
diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm
index f71222c3b5e..cc3b2fcedc7 100644
--- a/code/game/turfs/unsimulated/beach.dm
+++ b/code/game/turfs/unsimulated/beach.dm
@@ -55,7 +55,6 @@
/turf/unsimulated/beach/water/drop/New()
..()
- smooth_icon(src)
spawn(1)
overlays += image(icon, "[top_left_corner]-o", MOB_LAYER + 0.1)
overlays += image(icon, "[top_right_corner]-o", MOB_LAYER + 0.1)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index a2d62b29c8a..8c719c14a80 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -151,7 +151,9 @@ var/list/admin_verbs_debug = list(
/client/proc/test_movable_UI,
/client/proc/test_snap_UI,
/client/proc/cinematic,
- /proc/machine_upgrade
+ /proc/machine_upgrade,
+ /client/proc/map_template_load,
+ /client/proc/map_template_upload
)
var/list/admin_verbs_possess = list(
/proc/possess,
diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm
new file mode 100644
index 00000000000..4a15552a789
--- /dev/null
+++ b/code/modules/admin/verbs/map_template_loadverb.dm
@@ -0,0 +1,45 @@
+/client/proc/map_template_load()
+ set category = "Debug"
+ set name = "Map Template - Place"
+
+ if(!holder)
+ return
+
+ var/datum/map_template/template
+
+ var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in map_templates
+ if(!map)
+ return
+ template = map_templates[map]
+
+ var/turf/T = get_turf(mob)
+ if(!T)
+ return
+
+ var/list/preview = list()
+ for(var/S in template.get_affected_turfs(T,centered = TRUE))
+ preview += image('icons/turf/overlays.dmi',S,"greenOverlay")
+ usr.client.images += preview
+ if(alert(usr,"Confirm location.","Template Confirm","Yes","No") == "Yes")
+ template.load(T, centered = TRUE)
+ message_admins("[key_name_admin(usr)] has placed a map template ([template.name]) at (JMP)")
+ usr.client.images -= preview
+
+/client/proc/map_template_upload()
+ set category = "Debug"
+ set name = "Map Template - Upload"
+
+ if(!holder)
+ return
+
+ var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
+ if(!map)
+ return
+ if(copytext("[map]",-4) != ".dmm")
+ usr << "Bad map file: [map]"
+ return
+
+ var/datum/map_template/M = new(map=map, rename="[map]")
+ M.preload_size(map)
+ map_templates[M.name] = M
+ message_admins("[key_name_admin(usr)] has uploaded a map template ([map])")
diff --git a/code/modules/awaymissions/maploader/dmm_suite.dm b/code/modules/awaymissions/maploader/dmm_suite.dm
index e2311ed7eee..21c2dac0dc8 100644
--- a/code/modules/awaymissions/maploader/dmm_suite.dm
+++ b/code/modules/awaymissions/maploader/dmm_suite.dm
@@ -53,7 +53,7 @@ dmm_suite{
*/
- verb/load_map(var/dmm_file as file, var/z_offset as num){
+ verb/load_map(var/dmm_file as file, var/x_offset as num, var/y_offset as num, var/z_offset as num, do_sleep as num){
// dmm_file: A .dmm file to load (Required).
// z_offset: A number representing the z-level on which to start loading the map (Optional).
}
diff --git a/code/modules/awaymissions/maploader/reader.dm b/code/modules/awaymissions/maploader/reader.dm
index 01b728d4a35..e58714de9f3 100644
--- a/code/modules/awaymissions/maploader/reader.dm
+++ b/code/modules/awaymissions/maploader/reader.dm
@@ -3,7 +3,8 @@
//////////////////////////////////////////////////////////////
//global datum that will preload variables on atoms instanciation
-var/global/dmm_suite/preloader/_preloader = null
+var/global/use_preloader = FALSE
+var/global/dmm_suite/preloader/_preloader = new
/**
@@ -16,9 +17,9 @@ var/global/dmm_suite/preloader/_preloader = null
* 2) Read the map line by line, parsing the result (using parse_grid)
*
*/
-/dmm_suite/load_map(var/dmm_file as file, var/z_offset as num)
+/dmm_suite/load_map(dmm_file as file, x_offset = 0 as num, y_offset = 0 as num, z_offset as num, do_sleep = 1 as num)
if(!z_offset)//what z_level we are creating the map on
- z_offset = world.maxz+1
+ z_offset = world.maxz + 1
var/quote = ascii2text(34)
var/tfile = file2text(dmm_file)//the map file we're creating
@@ -39,7 +40,8 @@ var/global/dmm_suite/preloader/_preloader = null
var/model_key = copytext(tline,2,2+key_len)
var/model_contents = copytext(tline,findtext(tfile,"=")+3,length(tline))
grid_models[model_key] = model_contents
- sleep(-1)
+ if(do_sleep)
+ sleep(-1)
///////////////////////////////////////////////////////////////////////////////////////
//now let's fill the map with turf and objects using the constructed model map
@@ -47,8 +49,8 @@ var/global/dmm_suite/preloader/_preloader = null
//position of the currently processed square
var/zcrd=-1
- var/ycrd=0
- var/xcrd=0
+ var/ycrd=y_offset
+ var/xcrd=x_offset
for(var/zpos=findtext(tfile,"\n(1,1,",lpos,0);zpos!=0;zpos=findtext(tfile,"\n(1,1,",zpos+1,0)) //in case there's several maps to load
@@ -60,8 +62,9 @@ var/global/dmm_suite/preloader/_preloader = null
//if exceeding the world max x or y, increase it
var/x_depth = length(copytext(zgrid,1,findtext(zgrid,"\n",2,0)))
- if(world.maxxz_depth)
break
ycrd--
-
- sleep(-1)
+ if(do_sleep)
+ sleep(-1)
//reached End Of File
if(findtext(tfile,quote+"}",zpos,0)+2==tfile_len)
break
- sleep(-1)
+ if(do_sleep)
+ sleep(-1)
/**
* Fill a given tile with its area/turf/objects/mobs
@@ -110,7 +115,7 @@ var/global/dmm_suite/preloader/_preloader = null
* 4) Instanciates the atom with its variables
*
*/
-/dmm_suite/proc/parse_grid(var/model as text,var/xcrd as num,var/ycrd as num,var/zcrd as num)
+/dmm_suite/proc/parse_grid(model as text, xcrd as num, ycrd as num, zcrd as num, do_sleep = 1)
/*Method parse_grid()
- Accepts a text string containing a comma separated list of type paths of the
same construction as those contained in a .dmm file, and instantiates them.
@@ -143,13 +148,14 @@ var/global/dmm_suite/preloader/_preloader = null
var/variables_start = findtext(full_def,"{")
if(variables_start)//if there's any variable
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
- fields = dmm_splittext(full_def,";")
+ fields = readlist(full_def, ";")
//then fill the members_attributes list with the corresponding variables
members_attributes.len++
members_attributes[index++] = fields
- sleep(-1)
+ if(do_sleep)
+ sleep(-1)
while(dpos != 0)
@@ -165,15 +171,17 @@ var/global/dmm_suite/preloader/_preloader = null
//first instance the /area and remove it from the members list
index = members.len
- var/atom/instance
- _preloader = new(members_attributes[index])//preloader for assigning set variables on atom creation
+ if(members[index] != /area/template_noop)
+ var/atom/instance
+ _preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
- instance = locate(members[index])
- instance.contents.Add(locate(xcrd,ycrd,zcrd))
-
- if(_preloader && instance)
- _preloader.load(instance)
+ instance = locate(members[index])
+ var/turf/crds = locate(xcrd,ycrd,zcrd)
+ if(crds)
+ instance.contents.Add(crds)
+ if(use_preloader && instance)
+ _preloader.load(instance)
members.Remove(members[index])
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
@@ -183,40 +191,47 @@ var/global/dmm_suite/preloader/_preloader = null
first_turf_index++
//instanciate the first /turf
- var/turf/T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],xcrd,ycrd,zcrd)
+ var/turf/T
+ if(members[first_turf_index] != /turf/template_noop)
+ T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],xcrd,ycrd,zcrd)
- //if others /turf are presents, simulates the underlays piling effect
- index = first_turf_index + 1
- while(index <= members.len)
- turfs_underlays.Insert(1,image(T.icon,null,T.icon_state,T.layer,T.dir))//add the current turf image to the underlays list
- var/turf/UT = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)//instance new turf
- add_underlying_turf(UT,T,turfs_underlays)//simulates the DMM piling effect
- T = UT
- index++
+ if(T)
+ //if others /turf are presents, simulates the underlays piling effect
+ index = first_turf_index + 1
+ while(index <= members.len)
+ turfs_underlays.Insert(1,image(T.icon,null,T.icon_state,T.layer,T.dir))//add the current turf image to the underlays list
+ var/turf/UT = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)//instance new turf
+ add_underlying_turf(UT,T,turfs_underlays)//simulates the DMM piling effect
+ T = UT
+ index++
//finally instance all remainings objects/mobs
- for(index=1,index < first_turf_index,index++)
+ for(index in 1 to first_turf_index - 1)
instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)
+ if(do_sleep)
+ sleep(-1)
////////////////
//Helpers procs
////////////////
//Instance an atom at (x,y,z) and gives it the variables in attributes
-/dmm_suite/proc/instance_atom(var/path,var/list/attributes, var/x, var/y, var/z)
+/dmm_suite/proc/instance_atom(path,list/attributes, x, y, z)
var/atom/instance
- _preloader = new(attributes, path)
+ _preloader.setup(attributes, path)
- instance = new path (locate(x,y,z))//first preloader pass
+ var/turf/T = locate(x,y,z)
+ if(T)
+ instance = new path (T)//first preloader pass
- if(_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
+ if(use_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
_preloader.load(instance)
return instance
//text trimming (both directions) helper proc
//optionally removes quotes before and after the text (for variable name)
-/dmm_suite/proc/trim_text(var/what as text,var/trim_quotes=0)
+/dmm_suite/proc/trim_text(what as text,trim_quotes=0)
while(length(what) && (findtext(what," ",1,2)))
what=copytext(what,2,0)
while(length(what) && (findtext(what," ",length(what),0)))
@@ -230,7 +245,7 @@ var/global/dmm_suite/preloader/_preloader = null
//find the position of the next delimiter,skipping whatever is comprised between opening_escape and closing_escape
//returns 0 if reached the last delimiter
-/dmm_suite/proc/find_next_delimiter_position(var/text as text,var/initial_position as num, var/delimiter=",",var/opening_escape=quote,var/closing_escape=quote)
+/dmm_suite/proc/find_next_delimiter_position(text as text,initial_position as num, delimiter=",",opening_escape=quote,closing_escape=quote)
var/position = initial_position
var/next_delimiter = findtext(text,delimiter,position,0)
var/next_opening = findtext(text,opening_escape,position,0)
@@ -245,7 +260,7 @@ var/global/dmm_suite/preloader/_preloader = null
//build a list from variables in text form (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
//return the filled list
-/dmm_suite/proc/dmm_splittext(var/text as text,var/delimiter=",")
+/dmm_suite/proc/readlist(text as text, delimiter=",")
var/list/to_return = list()
@@ -279,12 +294,16 @@ var/global/dmm_suite/preloader/_preloader = null
//Check for list
else if(copytext(trim_right,1,5) == "list")
- trim_right = dmm_splittext(copytext(trim_right,6,length(trim_right)))
+ trim_right = readlist(copytext(trim_right,6,length(trim_right)))
//Check for file
else if(copytext(trim_right,1,2) == "'")
trim_right = file(copytext(trim_right,2,length(trim_right)))
+ //Check for path
+ else if(ispath(text2path(trim_right)))
+ trim_right = text2path(trim_right)
+
to_return[trim_left] = trim_right
else//simple var
@@ -295,7 +314,7 @@ var/global/dmm_suite/preloader/_preloader = null
return to_return
//simulates the DM multiple turfs on one tile underlaying
-/dmm_suite/proc/add_underlying_turf(var/turf/placed,var/turf/underturf, var/list/turfs_underlays)
+/dmm_suite/proc/add_underlying_turf(turf/placed,turf/underturf, list/turfs_underlays)
if(underturf.density)
placed.density = 1
if(underturf.opacity)
@@ -304,11 +323,15 @@ var/global/dmm_suite/preloader/_preloader = null
//atom creation method that preloads variables at creation
/atom/New()
- if(_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
+ if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
_preloader.load(src)
. = ..()
+/dmm_suite/Destroy()
+ ..()
+ return QDEL_HINT_HARDDEL_NOW
+
//////////////////
//Preloader datum
//////////////////
@@ -318,15 +341,19 @@ var/global/dmm_suite/preloader/_preloader = null
var/list/attributes
var/target_path
-/dmm_suite/preloader/New(var/list/the_attributes, var/path)
- .=..()
- if(!the_attributes.len)
- del(src)
- return
- attributes = the_attributes
- target_path = path
+/dmm_suite/preloader/proc/setup(list/the_attributes, path)
+ if(the_attributes.len)
+ use_preloader = TRUE
+ attributes = the_attributes
+ target_path = path
/dmm_suite/preloader/proc/load(atom/what)
for(var/attribute in attributes)
what.vars[attribute] = attributes[attribute]
- del(src)
\ No newline at end of file
+ use_preloader = FALSE
+
+/area/template_noop
+ name = "Area Passthrough"
+
+/turf/template_noop
+ name = "Turf Passthrough"
\ No newline at end of file
diff --git a/code/modules/awaymissions/maploader/swapmaps.dm b/code/modules/awaymissions/maploader/swapmaps.dm
index 8f15d071b0f..8dc9f9f6c99 100644
--- a/code/modules/awaymissions/maploader/swapmaps.dm
+++ b/code/modules/awaymissions/maploader/swapmaps.dm
@@ -156,14 +156,14 @@ swapmap
if(z2>swapmaps_compiled_maxz ||\
y2>swapmaps_compiled_maxy ||\
x2>swapmaps_compiled_maxx)
- del(src)
+ qdel(src)
return
x2=x?(x):world.maxx
y2=y?(y):world.maxy
z2=z?(z):1
AllocateSwapMap()
- Del()
+ Destroy()
// a temporary datum for a chunk can be deleted outright
// for others, some cleanup is necessary
if(!ischunk)
@@ -179,13 +179,14 @@ swapmap
if(!M.key) qdel(M)
else M.loc=null
areas[A.loc]=null
- del(A)
+ qdel(A)
// delete areas that belong only to this map
for(var/area/a in areas)
- if(a && !a.contents.len) del(a)
+ if(a && !a.contents.len) qdel(a)
if(x2>=world.maxx || y2>=world.maxy || z2>=world.maxz) CutXYZ()
- del(areas)
+ qdel(areas)
..()
+ return QDEL_HINT_HARDDEL_NOW
/*
Savefile format:
@@ -226,11 +227,11 @@ swapmap
S["areas"] << areas
for(n in 1 to areas.len) areas[areas[n]]=n
var/oldcd=S.cd
- for(z=z1,z<=z2,++z)
+ for(z in z1 to z2)
S.cd="[z-z1+1]"
- for(y=y1,y<=y2,++y)
+ for(y in y1 to y2)
S.cd="[y-y1+1]"
- for(x=x1,x<=x2,++x)
+ for(x in x1 to x2)
S.cd="[x-x1+1]"
var/turf/T=locate(x,y,z)
S["type"] << T.type
@@ -241,7 +242,7 @@ swapmap
sleep()
S.cd=oldcd
locked=0
- del(areas)
+ qdel(areas)
Read(savefile/S,_id,turf/locorner)
var/x
@@ -269,11 +270,11 @@ swapmap
locked=1
AllocateSwapMap() // adjust x1,y1,z1 - x2,y2,z2 coords
var/oldcd=S.cd
- for(z=z1,z<=z2,++z)
+ for(z in z1 to z2)
S.cd="[z-z1+1]"
- for(y=y1,y<=y2,++y)
+ for(y in y1 to y2)
S.cd="[y-y1+1]"
- for(x=x1,x<=x2,++x)
+ for(x in x1 to x2)
S.cd="[x-x1+1]"
var/tp
S["type"]>>tp
@@ -297,7 +298,7 @@ swapmap
sleep()
S.cd=oldcd
locked=0
- del(areas)
+ qdel(areas)
/*
Find an empty block on the world map in which to load this map.
@@ -321,7 +322,7 @@ swapmap
x1=l[1]
y1=l[2]
z1=l[3]
- del(l)
+ qdel(l)
x2+=x1-1
y2+=y1-1
z2+=z1-1
@@ -377,7 +378,7 @@ swapmap
// save and delete
proc/Unload()
Save()
- del(src)
+ qdel(src)
proc/Save()
if(id==src) return 0
@@ -472,7 +473,7 @@ atom
l=l.Copy()
for(M in src) if(M.key) l-=M
if(l.len) S["contents"]<=se.y;pos_y--){
- for(var/pos_x=nw.x;pos_x<=se.x;pos_x++){
+ for(var/pos_z in nw.z to se.z){
+ for(var/pos_y in nw.y to se.y){
+ for(var/pos_x in nw.x to se.x){
var/turf/test_turf = locate(pos_x,pos_y,pos_z)
var/test_template = make_template(test_turf, flags)
var/template_number = templates.Find(test_template)
@@ -67,7 +67,7 @@ dmm_suite{
}
var/key_length = round/*floor*/(log(letter_digits.len,templates.len-1)+1)
var/list/keys[templates.len]
- for(var/key_pos=1;key_pos<=templates.len;key_pos++){
+ for(var/key_pos in 1 to templates.len){
keys[key_pos] = get_model_key(key_pos,key_length)
dmm_text += {""[keys[key_pos]]" = ([templates[key_pos]])\n"}
}
@@ -163,7 +163,7 @@ dmm_suite{
get_model_key(var/which as num, var/key_length as num){
var/key = ""
var/working_digit = which-1
- for(var/digit_pos=key_length;digit_pos>=1;digit_pos--){
+ for(var/digit_pos in key_length to 1 step -1){
var/place_value = round/*floor*/(working_digit/(letter_digits.len**(digit_pos-1)))
working_digit-=place_value*(letter_digits.len**(digit_pos-1))
key = "[key][letter_digits[place_value+1]]"
diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm
index 85828a90c68..321e4033f0e 100644
--- a/code/modules/awaymissions/zlevel.dm
+++ b/code/modules/awaymissions/zlevel.dm
@@ -1,10 +1,33 @@
-proc/createRandomZlevel()
+/proc/late_setup_level(turfs, smoothTurfs)
+ if(!smoothTurfs)
+ smoothTurfs = turfs
+
+ if(air_master)
+ air_master.setup_allturfs(turfs)
+ for(var/turf/T in turfs)
+ if(T.dynamic_lighting)
+ T.lighting_build_overlays()
+ for(var/obj/structure/cable/PC in T)
+ makepowernet_for(PC)
+ for(var/turf/T in smoothTurfs)
+ if(T.smooth)
+ smooth_icon(T)
+ for(var/R in T)
+ var/atom/A = R
+ if(A.smooth)
+ smooth_icon(A)
+
+/proc/createRandomZlevel()
if(awaydestinations.len) //crude, but it saves another var!
return
var/list/potentialRandomZlevels = list()
log_startup_progress("Searching for away missions...")
- var/list/Lines = file2list("_maps/map_files/RandomZLevels/fileList.txt")
+ var/list/Lines
+ if(fexists("config/away_mission_config.txt"))
+ Lines = file2list("config/away_mission_config.txt")
+ else
+ Lines = file2list("config/example/away_mission_config.txt")
if(!Lines.len) return
for (var/t in Lines)
@@ -35,22 +58,14 @@ proc/createRandomZlevel()
if(potentialRandomZlevels.len)
var/watch = start_watch()
- log_startup_progress(" Loading away mission...")
+ log_startup_progress("Loading away mission...")
var/map = pick(potentialRandomZlevels)
var/file = file(map)
if(isfile(file))
- maploader.load_map(file)
- var/turfs = block(locate(1, 1, world.maxz), locate(world.maxx, world.maxy, world.maxz))
- if(air_master)
- air_master.setup_allturfs(turfs)
- for(var/turf/T in turfs)
- if(T.dynamic_lighting)
- T.lighting_build_overlays()
- for(var/obj/structure/cable/PC in T)
- makepowernet_for(PC)
- smooth_zlevel(world.maxz)
- log_to_dd("Away mission loaded: [map]")
+ maploader.load_map(file, do_sleep = 0)
+ late_setup_level(block(locate(1, 1, world.maxz), locate(world.maxx, world.maxy, world.maxz)))
+ log_to_dd(" Away mission loaded: [map]")
for(var/obj/effect/landmark/L in landmarks_list)
if (L.name != "awaystart")
diff --git a/_maps/map_files/RandomZLevels/fileList.txt b/config/example/away_mission_config.txt
similarity index 94%
rename from _maps/map_files/RandomZLevels/fileList.txt
rename to config/example/away_mission_config.txt
index b9ad6131da0..f440c9a231a 100644
--- a/_maps/map_files/RandomZLevels/fileList.txt
+++ b/config/example/away_mission_config.txt
@@ -15,6 +15,7 @@
#_maps/map_files/RandomZLevels/clownplanet.dmm
#_maps/map_files/RandomZLevels/example.dmm
#_maps/map_files/RandomZLevels/spacebattle.dmm
+#_maps/map_files/RandomZLevels/stationCollision.dmm
#===================================#
# USABLE AWAY MISSIONS #
@@ -26,7 +27,6 @@ _maps/map_files/RandomZLevels/undergroundoutpost45.dmm
_maps/map_files/RandomZLevels/academy.dmm
_maps/map_files/RandomZLevels/blackmarketpackers.dmm
_maps/map_files/RandomZLevels/spacehotel.dmm
-_maps/map_files/RandomZLevels/stationCollision.dmm
_maps/map_files/RandomZLevels/wildwest.dmm
#===================================#
diff --git a/paradise.dme b/paradise.dme
index ca1495b92b1..202eb4130cf 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -255,6 +255,7 @@
#include "code\datums\helper_datums\construction_datum.dm"
#include "code\datums\helper_datums\events.dm"
#include "code\datums\helper_datums\global_iterator.dm"
+#include "code\datums\helper_datums\map_template.dm"
#include "code\datums\helper_datums\teleport.dm"
#include "code\datums\helper_datums\topic_input.dm"
#include "code\datums\spells\area_teleport.dm"
@@ -1009,6 +1010,7 @@
#include "code\modules\admin\verbs\freeze.dm"
#include "code\modules\admin\verbs\getlogs.dm"
#include "code\modules\admin\verbs\honksquad.dm"
+#include "code\modules\admin\verbs\map_template_loadverb.dm"
#include "code\modules\admin\verbs\mapping.dm"
#include "code\modules\admin\verbs\massmodvar.dm"
#include "code\modules\admin\verbs\modifyvariables.dm"