Port's TG's Maploader

This commit is contained in:
Neerti
2017-09-08 08:14:43 -04:00
parent 9ce3c85127
commit 1bc28c07c0
32 changed files with 1472 additions and 444 deletions

View File

@@ -1,4 +1,4 @@
obj/machinery/atmospherics/binary
/obj/machinery/atmospherics/binary
dir = SOUTH
initialize_directions = SOUTH|NORTH
use_power = 1
@@ -9,8 +9,16 @@ obj/machinery/atmospherics/binary
var/datum/pipe_network/network1
var/datum/pipe_network/network2
New()
/obj/machinery/atmospherics/binary/New()
..()
air1 = new
air2 = new
air1.volume = 200
air2.volume = 200
/obj/machinery/atmospherics/binary/init_dir()
switch(dir)
if(NORTH)
initialize_directions = NORTH|SOUTH
@@ -20,14 +28,9 @@ obj/machinery/atmospherics/binary
initialize_directions = EAST|WEST
if(WEST)
initialize_directions = EAST|WEST
air1 = new
air2 = new
air1.volume = 200
air2.volume = 200
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
/obj/machinery/atmospherics/binary/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
@@ -41,7 +44,7 @@ obj/machinery/atmospherics/binary
return null
Destroy()
/obj/machinery/atmospherics/binary/Destroy()
. = ..()
if(node1)
@@ -54,19 +57,24 @@ obj/machinery/atmospherics/binary
node1 = null
node2 = null
initialize()
if(node1 && node2) return
/obj/machinery/atmospherics/binary/initialize()
if(node1 && node2)
return
init_dir()
var/node2_connect = dir
var/node1_connect = turn(dir, 180)
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
@@ -75,7 +83,7 @@ obj/machinery/atmospherics/binary
update_icon()
update_underlays()
build_network()
/obj/machinery/atmospherics/binary/build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
@@ -87,7 +95,7 @@ obj/machinery/atmospherics/binary
network2.build_network(node2, src)
return_network(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/binary/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
@@ -98,7 +106,7 @@ obj/machinery/atmospherics/binary
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
/obj/machinery/atmospherics/binary/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
@@ -106,7 +114,7 @@ obj/machinery/atmospherics/binary
return 1
return_network_air(datum/pipe_network/reference)
/obj/machinery/atmospherics/binary/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
@@ -116,7 +124,7 @@ obj/machinery/atmospherics/binary
return results
disconnect(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/binary/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network1)
node1 = null

View File

@@ -247,6 +247,7 @@
if(P.node || P.mode == 0)
continue
for(var/obj/machinery/atmospherics/target in get_step(src, P.dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
P.node = target

View File

@@ -18,9 +18,11 @@
use_power = 0
level = 1
/obj/machinery/atmospherics/portables_connector/init_dir()
initialize_directions = dir
/obj/machinery/atmospherics/portables_connector/New()
initialize_directions = dir
init_dir()
..()
/obj/machinery/atmospherics/portables_connector/update_icon()
@@ -73,11 +75,15 @@
node = null
/obj/machinery/atmospherics/portables_connector/initialize()
if(node) return
if(node)
return
init_dir()
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node = target

View File

@@ -1,4 +1,4 @@
obj/machinery/atmospherics/trinary
/obj/machinery/atmospherics/trinary
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
use_power = 0
@@ -13,8 +13,19 @@ obj/machinery/atmospherics/trinary
var/datum/pipe_network/network2
var/datum/pipe_network/network3
New()
/obj/machinery/atmospherics/trinary/New()
..()
init_dir()
air1 = new
air2 = new
air3 = new
air1.volume = 200
air2.volume = 200
air3.volume = 200
/obj/machinery/atmospherics/trinary/init_dir()
switch(dir)
if(NORTH)
initialize_directions = EAST|NORTH|SOUTH
@@ -24,16 +35,9 @@ obj/machinery/atmospherics/trinary
initialize_directions = EAST|WEST|SOUTH
if(WEST)
initialize_directions = WEST|NORTH|EAST
air1 = new
air2 = new
air3 = new
air1.volume = 200
air2.volume = 200
air3.volume = 200
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
/obj/machinery/atmospherics/trinary/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
@@ -50,7 +54,7 @@ obj/machinery/atmospherics/trinary
return null
Destroy()
/obj/machinery/atmospherics/trinary/Destroy()
. = ..()
if(node1)
@@ -67,25 +71,31 @@ obj/machinery/atmospherics/trinary
node2 = null
node3 = null
initialize()
if(node1 && node2 && node3) return
/obj/machinery/atmospherics/trinary/initialize()
if(node1 && node2 && node3)
return
init_dir()
var/node1_connect = turn(dir, -180)
var/node2_connect = turn(dir, -90)
var/node3_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node3 = target
@@ -94,7 +104,7 @@ obj/machinery/atmospherics/trinary
update_icon()
update_underlays()
build_network()
/obj/machinery/atmospherics/trinary/build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
@@ -111,7 +121,7 @@ obj/machinery/atmospherics/trinary
network3.build_network(node3, src)
return_network(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/trinary/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
@@ -125,7 +135,7 @@ obj/machinery/atmospherics/trinary
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
/obj/machinery/atmospherics/trinary/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
@@ -135,7 +145,7 @@ obj/machinery/atmospherics/trinary
return 1
return_network_air(datum/pipe_network/reference)
/obj/machinery/atmospherics/trinary/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
@@ -147,7 +157,7 @@ obj/machinery/atmospherics/trinary
return results
disconnect(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/trinary/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network1)
node1 = null

View File

@@ -47,10 +47,10 @@
update_underlays()
/obj/machinery/atmospherics/tvalve/New()
initialize_directions()
init_dir()
..()
/obj/machinery/atmospherics/tvalve/proc/initialize_directions()
/obj/machinery/atmospherics/tvalve/init_dir()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|EAST
@@ -189,21 +189,26 @@
var/node2_dir
var/node3_dir
init_dir()
node1_dir = turn(dir, 180)
node2_dir = turn(dir, -90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node3 = target
@@ -371,7 +376,7 @@
icon_state = "map_tvalvem1"
state = 1
/obj/machinery/atmospherics/tvalve/mirrored/initialize_directions()
/obj/machinery/atmospherics/tvalve/mirrored/init_dir()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|WEST

View File

@@ -11,15 +11,18 @@
var/welded = 0 //defining this here for ventcrawl stuff
New()
/obj/machinery/atmospherics/unary/New()
..()
initialize_directions = dir
init_dir()
air_contents = new
air_contents.volume = 200
/obj/machinery/atmospherics/unary/init_dir()
initialize_directions = dir
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
/obj/machinery/atmospherics/unary/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
@@ -30,7 +33,7 @@
return null
Destroy()
/obj/machinery/atmospherics/unary/Destroy()
. = ..()
if(node)
@@ -39,12 +42,16 @@
node = null
initialize()
if(node) return
/obj/machinery/atmospherics/unary/initialize()
if(node)
return
init_dir()
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node = target
@@ -53,14 +60,14 @@
update_icon()
update_underlays()
build_network()
/obj/machinery/atmospherics/unary/build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
return_network(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/unary/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node)
@@ -68,13 +75,13 @@
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
/obj/machinery/atmospherics/unary/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
return 1
return_network_air(datum/pipe_network/reference)
/obj/machinery/atmospherics/unary/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network == reference)
@@ -82,7 +89,7 @@
return results
disconnect(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/unary/disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
qdel(network)
node = null

View File

@@ -38,13 +38,12 @@
/obj/machinery/atmospherics/valve/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/valve/New()
/obj/machinery/atmospherics/valve/init_dir()
switch(dir)
if(NORTH || SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST || WEST)
initialize_directions = EAST|WEST
..()
/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
@@ -142,6 +141,7 @@
return
/obj/machinery/atmospherics/valve/initialize()
init_dir()
normalize_dir()
var/node1_dir
@@ -155,11 +155,13 @@
node2_dir = direction
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target

View File

@@ -1,5 +1,5 @@
obj/machinery/atmospherics/pipe/simple/heat_exchanging
/obj/machinery/atmospherics/pipe/simple/heat_exchanging
icon = 'icons/atmos/heat.dmi'
icon_state = "intact"
pipe_icon = "hepipe"
@@ -17,13 +17,17 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
buckle_lying = 1
// BubbleWrap
New()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/New()
..()
initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
init_dir()
// BubbleWrap END
color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default.
initialize()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/init_dir()
initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/initialize()
init_dir()
normalize_dir()
var/node1_dir
var/node2_dir
@@ -36,10 +40,12 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
node2_dir = direction
for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir))
target.init_dir()
if(target.initialize_directions_he & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir))
target.init_dir()
if(target.initialize_directions_he & get_dir(target,src))
node2 = target
break
@@ -51,7 +57,7 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
return
process()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process()
if(!parent)
..()
else
@@ -103,7 +109,7 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
icon = 'icons/atmos/junction.dmi'
icon_state = "intact"
pipe_icon = "hejunction"
@@ -112,9 +118,7 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
minimum_temperature_difference = 300
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
// BubbleWrap
New()
.. ()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/init_dir()
switch ( dir )
if ( SOUTH )
initialize_directions = NORTH
@@ -128,14 +132,17 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
if ( WEST )
initialize_directions = EAST
initialize_directions_he = WEST
// BubbleWrap END
initialize()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/initialize()
init_dir()
for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he))
target.init_dir()
if(target.initialize_directions_he & get_dir(target,src))
node2 = target
break

View File

@@ -34,6 +34,10 @@
return 1
// This is used to set up what directions pipes will connect to. Called inside New(), initialize(), and when pipes look at another pipe, incase they didn't get to initialize() yet.
/obj/machinery/atmospherics/proc/init_dir()
return
/obj/machinery/atmospherics/pipe/return_air()
if(!parent)
parent = new /datum/pipeline()
@@ -170,19 +174,9 @@
icon = null
alpha = 255
switch(dir)
if(SOUTH || NORTH)
initialize_directions = SOUTH|NORTH
if(EAST || WEST)
initialize_directions = EAST|WEST
if(NORTHEAST)
initialize_directions = NORTH|EAST
if(NORTHWEST)
initialize_directions = NORTH|WEST
if(SOUTHEAST)
initialize_directions = SOUTH|EAST
if(SOUTHWEST)
initialize_directions = SOUTH|WEST
init_dir()
/obj/machinery/atmospherics/pipe/simple/hide(var/i)
if(istype(loc, /turf/simulated))
@@ -210,6 +204,21 @@
else return 1
/obj/machinery/atmospherics/pipe/simple/init_dir()
switch(dir)
if(SOUTH || NORTH)
initialize_directions = SOUTH|NORTH
if(EAST || WEST)
initialize_directions = EAST|WEST
if(NORTHEAST)
initialize_directions = NORTH|EAST
if(NORTHWEST)
initialize_directions = NORTH|WEST
if(SOUTHEAST)
initialize_directions = SOUTH|EAST
if(SOUTHWEST)
initialize_directions = SOUTH|WEST
/obj/machinery/atmospherics/pipe/simple/proc/burst()
src.visible_message("<span class='danger'>\The [src] bursts!</span>");
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
@@ -270,6 +279,7 @@
return
/obj/machinery/atmospherics/pipe/simple/initialize()
init_dir()
normalize_dir()
var/node1_dir
var/node2_dir
@@ -282,11 +292,13 @@
node2_dir = direction
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
@@ -436,6 +448,9 @@
alpha = 255
icon = null
init_dir()
/obj/machinery/atmospherics/pipe/manifold/init_dir()
switch(dir)
if(NORTH)
initialize_directions = EAST|SOUTH|WEST
@@ -544,11 +559,13 @@
update_icon()
/obj/machinery/atmospherics/pipe/manifold/initialize()
init_dir()
var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
@@ -561,6 +578,7 @@
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
@@ -573,6 +591,7 @@
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node3 = target
@@ -823,24 +842,28 @@
/obj/machinery/atmospherics/pipe/manifold4w/initialize()
for(var/obj/machinery/atmospherics/target in get_step(src,1))
target.init_dir()
if(target.initialize_directions & 2)
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,2))
target.init_dir()
if(target.initialize_directions & 1)
if (check_connect_types(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,4))
target.init_dir()
if(target.initialize_directions & 8)
if (check_connect_types(target,src))
node3 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,8))
target.init_dir()
if(target.initialize_directions & 4)
if (check_connect_types(target,src))
node4 = target
@@ -958,6 +981,9 @@
/obj/machinery/atmospherics/pipe/cap/New()
..()
init_dir()
/obj/machinery/atmospherics/pipe/cap/init_dir()
initialize_directions = dir
/obj/machinery/atmospherics/pipe/cap/hide(var/i)
@@ -1006,7 +1032,9 @@
overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap")
/obj/machinery/atmospherics/pipe/cap/initialize()
init_dir()
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node = target
@@ -1079,9 +1107,12 @@
/obj/machinery/atmospherics/pipe/tank/New()
icon_state = "air"
initialize_directions = dir
init_dir()
..()
/obj/machinery/atmospherics/pipe/tank/init_dir()
initialize_directions = dir
/obj/machinery/atmospherics/pipe/tank/process()
if(!parent)
..()
@@ -1110,9 +1141,11 @@
update_underlays()
/obj/machinery/atmospherics/pipe/tank/initialize()
init_dir()
var/connect_direction = dir
for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
@@ -1241,9 +1274,12 @@
var/build_killswitch = 1
/obj/machinery/atmospherics/pipe/vent/New()
initialize_directions = dir
init_dir()
..()
/obj/machinery/atmospherics/pipe/vent/init_dir()
initialize_directions = dir
/obj/machinery/atmospherics/pipe/vent/high_volume
name = "Larger vent"
volume = 1000
@@ -1279,9 +1315,11 @@
icon_state = "exposed"
/obj/machinery/atmospherics/pipe/vent/initialize()
init_dir()
var/connect_direction = dir
for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
target.init_dir()
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target

View File

@@ -214,3 +214,11 @@
#define WORLD_ICON_SIZE 32 //Needed for the R-UST port
#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 //Needed for the R-UST port
// Maploader bounds indices
#define MAP_MINX 1
#define MAP_MINY 2
#define MAP_MINZ 3
#define MAP_MAXX 4
#define MAP_MAXY 5
#define MAP_MAXZ 6

View File

@@ -662,3 +662,13 @@ proc/dd_sortedTextList(list/incoming)
L.Swap(start++,end--)
return L
//Copies a list, and all lists inside it recusively
//Does not copy any other reference type
/proc/deepCopyList(list/l)
if(!islist(l))
return l
. = l.Copy()
for(var/i = 1 to l.len)
if(islist(.[i]))
.[i] = .(.[i])

View File

@@ -331,4 +331,61 @@ proc/TextPreview(var/string,var/len=40)
/proc/strip_improper(var/text)
return replacetext(replacetext(text, "\proper", ""), "\improper", "")
//Used for applying byonds text macros to strings that are loaded at runtime
/proc/apply_text_macros(string)
var/next_backslash = findtext(string, "\\")
if(!next_backslash)
return string
var/leng = length(string)
var/next_space = findtext(string, " ", next_backslash + 1)
if(!next_space)
next_space = leng - next_backslash
if(!next_space) //trailing bs
return string
var/base = next_backslash == 1 ? "" : copytext(string, 1, next_backslash)
var/macro = lowertext(copytext(string, next_backslash + 1, next_space))
var/rest = next_backslash > leng ? "" : copytext(string, next_space + 1)
//See http://www.byond.com/docs/ref/info.html#/DM/text/macros
switch(macro)
//prefixes/agnostic
if("the")
rest = text("\the []", rest)
if("a")
rest = text("\a []", rest)
if("an")
rest = text("\an []", rest)
if("proper")
rest = text("\proper []", rest)
if("improper")
rest = text("\improper []", rest)
if("roman")
rest = text("\roman []", rest)
//postfixes
if("th")
base = text("[]\th", rest)
if("s")
base = text("[]\s", rest)
if("he")
base = text("[]\he", rest)
if("she")
base = text("[]\she", rest)
if("his")
base = text("[]\his", rest)
if("himself")
base = text("[]\himself", rest)
if("herself")
base = text("[]\herself", rest)
if("hers")
base = text("[]\hers", rest)
. = base
if(rest)
. += .(rest)
#define gender2text(gender) capitalize(gender)

View File

@@ -541,15 +541,25 @@ var/datum/controller/master/Master = new()
stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])"))
/datum/controller/master/StartLoadingMap()
if(map_loading)
admin_notice("<span class='danger'>Another map is attempting to be loaded before first map released lock. Delaying.</span>", R_DEBUG)
else
admin_notice("<span class='danger'>Map is now being built. Locking.</span>", R_DEBUG)
//disallow more than one map to load at once, multithreading it will just cause race conditions
while(map_loading)
stoplag()
for(var/S in subsystems)
var/datum/controller/subsystem/SS = S
SS.StartLoadingMap()
// ZAS might displace objects as the map loads if an air tick is processed mid-load.
air_processing_killed = TRUE
map_loading = TRUE
/datum/controller/master/StopLoadingMap(bounds = null)
admin_notice("<span class='danger'>Map is finished. Unlocking.</span>", R_DEBUG)
air_processing_killed = FALSE
map_loading = FALSE
for(var/S in subsystems)
var/datum/controller/subsystem/SS = S

View File

@@ -0,0 +1,29 @@
//
// Creation subsystem, which is responsible for initializing newly created objects.
//
SUBSYSTEM_DEF(creation)
name = "Creation"
priority = 14
wait = 5
// flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
flags = SS_NO_FIRE|SS_NO_INIT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
var/list/atoms_needing_initialize = list()
var/map_loading = FALSE
/datum/controller/subsystem/creation/StartLoadingMap()
map_loading = TRUE
/datum/controller/subsystem/creation/StopLoadingMap()
map_loading = FALSE
/datum/controller/subsystem/creation/proc/initialize_late_atoms()
admin_notice("<span class='danger'>Initializing atoms in submap.</span>", R_DEBUG)
var/total_atoms = atoms_needing_initialize.len
for(var/atom/movable/A in atoms_needing_initialize)
if(!QDELETED(A))
A.initialize()
atoms_needing_initialize -= A
admin_notice("<span class='danger'>Initalized [total_atoms] atoms in submap.</span>", R_DEBUG)

View File

@@ -21,6 +21,9 @@
/atom/movable/New()
..()
if(auto_init && ticker && ticker.current_state == GAME_STATE_PLAYING)
if(SScreation && SScreation.map_loading) // If a map is being loaded, newly created objects need to wait for it to finish.
SScreation.atoms_needing_initialize += src
else
initialize()
/atom/movable/Destroy()

View File

@@ -267,7 +267,7 @@
return 0
/obj/machinery/alarm/proc/master_is_operating()
return alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER | BROKEN))
return alarm_area && alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER | BROKEN))
/obj/machinery/alarm/proc/elect_master()
for(var/obj/machinery/alarm/AA in alarm_area)

View File

@@ -90,6 +90,10 @@
if(STATUS_DISPLAY_BLANK) //blank
return 1
if(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) //emergency shuttle timer
if(!emergency_shuttle)
message1 = "-ETA-"
message2 = "Never" // You're here forever.
return 1
if(emergency_shuttle.waiting_to_leave())
message1 = "-ETD-"
if(emergency_shuttle.shuttle.is_launching())
@@ -172,12 +176,16 @@
maptext = new_text
/obj/machinery/status_display/proc/get_shuttle_timer_arrival()
if(!emergency_shuttle)
return "Error"
var/timeleft = emergency_shuttle.estimate_arrival_time()
if(timeleft < 0)
return ""
return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]"
/obj/machinery/status_display/proc/get_shuttle_timer_departure()
if(!emergency_shuttle)
return "Error"
var/timeleft = emergency_shuttle.estimate_launch_time()
if(timeleft < 0)
return ""

View File

@@ -87,9 +87,11 @@
if(delete_me)
qdel(src)
/obj/effect/landmark/Destroy()
/obj/effect/landmark/Destroy(var/force = FALSE)
if(delete_me || force)
landmarks_list -= src
return ..()
return QDEL_HINT_LETMELIVE
/obj/effect/landmark/start
name = "start"

View File

@@ -136,7 +136,10 @@ var/list/admin_verbs_spawn = list(
/datum/admins/proc/spawn_atom, //allows us to spawn instances,
/client/proc/respawn_character,
/client/proc/virus2_editor,
/client/proc/spawn_chemdisp_cartridge
/client/proc/spawn_chemdisp_cartridge,
/client/proc/map_template_load,
/client/proc/map_template_upload,
/client/proc/map_template_load_on_new_z
)
var/list/admin_verbs_server = list(
/datum/admins/proc/capture_map,

View File

@@ -0,0 +1,69 @@
/client/proc/map_template_load()
set category = "Debug"
set name = "Map template - Place At Loc"
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()
template.preload_size(template.mappath)
for(var/S in template.get_affected_turfs(T,centered = TRUE))
preview += image('icons/misc/debug_group.dmi',S ,"red")
usr.client.images += preview
if(alert(usr,"Confirm location.", "Template Confirm","No","Yes") == "Yes")
if(template.annihilate && alert(usr,"This template is set to annihilate everything in the red square. \
\nEVERYTHING IN THE RED SQUARE WILL BE DELETED, ARE YOU ABSOLUTELY SURE?", "Template Confirm","No","Yes") == "No")
usr.client.images -= preview
return
if(template.load(T, centered = TRUE))
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has placed a map template ([template.name]).</span>")
else
to_chat(usr, "Failed to place map")
usr.client.images -= preview
/client/proc/map_template_load_on_new_z()
set category = "Debug"
set name = "Map template - New Z"
var/datum/map_template/template
var/map = input(usr, "Choose a Map Template to place on a new Z-level.","Place Map Template") as null|anything in map_templates
if(!map)
return
template = map_templates[map]
if(alert(usr,"Confirm map load.", "Template Confirm","No","Yes") == "Yes")
if(template.load_new_z())
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has placed a map template ([template.name]) on Z level [world.maxz].</span>")
else
to_chat(usr, "Failed to place map")
/client/proc/map_template_upload()
set category = "Debug"
set name = "Map Template - Upload"
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")
to_chat(usr, "Bad map file: [map]")
return
var/datum/map_template/M = new(map, "[map]")
if(M.preload_size(map))
to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])")
map_templates[M.name] = M
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has uploaded a map template ([map])</span>")
else
to_chat(usr, "Map template '[map]' failed to load properly")

View File

@@ -40,7 +40,8 @@ proc/createRandomZlevel()
var/map = pick(potentialRandomZlevels)
var/file = file(map)
if(isfile(file))
maploader.load_map(file)
var/datum/map_template/template = new(file, "away mission")
template.load_new_z()
world.log << "away mission loaded: [map]"
for(var/obj/effect/landmark/L in landmarks_list)

View File

@@ -1,4 +1,4 @@
var/global/dmm_suite/maploader = new
var/global/dmm_suite/maploader = null
dmm_suite{
/*

View File

@@ -0,0 +1,63 @@
dmm_suite{
/*
dmm_suite version 1.0
Released January 30th, 2011.
NOTE: Map saving functionality removed
defines the object /dmm_suite
- Provides the proc load_map()
- Loads the specified map file onto the specified z-level.
- provides the proc write_map()
- Returns a text string of the map in dmm format
ready for output to a file.
- provides the proc save_map()
- Returns a .dmm file if map is saved
- Returns FALSE if map fails to save
The dmm_suite provides saving and loading of map files in BYOND's native DMM map
format. It approximates the map saving and loading processes of the Dream Maker
and Dream Seeker programs so as to allow editing, saving, and loading of maps at
runtime.
------------------------
To save a map at runtime, create an instance of /dmm_suite, and then call
write_map(), which accepts three arguments:
- A turf representing one corner of a three dimensional grid (Required).
- Another turf representing the other corner of the same grid (Required).
- Any, or a combination, of several bit flags (Optional, see documentation).
The order in which the turfs are supplied does not matter, the /dmm_writer will
determine the grid containing both, in much the same way as DM's block() function.
write_map() will then return a string representing the saved map in dmm format;
this string can then be saved to a file, or used for any other purose.
------------------------
To load a map at runtime, create an instance of /dmm_suite, and then call load_map(),
which accepts two arguments:
- A .dmm file to load (Required).
- A number representing the z-level on which to start loading the map (Optional).
The /dmm_suite will load the map file starting on the specified z-level. If no
z-level was specified, world.maxz will be increased so as to fit the map. Note
that if you wish to load a map onto a z-level that already has objects on it,
you will have to handle the removal of those objects. Otherwise the new map will
simply load the new objects on top of the old ones.
Also note that all type paths specified in the .dmm file must exist in the world's
code, and that the /dmm_reader trusts that files to be loaded are in fact valid
.dmm files. Errors in the .dmm format will cause runtime errors.
*/
verb/load_map(var/dmm_file as file, var/x_offset as num, var/y_offset as num, var/z_offset as num, var/cropMap as num, var/measureOnly as num, no_changeturf 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).
// cropMap: When true, the map will be cropped to fit the existing world dimensions (Optional).
// measureOnly: When true, no changes will be made to the world (Optional).
// no_changeturf: When true, turf/AfterChange won't be called on loaded turfs
}
}

View File

@@ -0,0 +1,165 @@
var/list/global/map_templates = list()
// Called when the world starts, in world.dm
/proc/load_map_templates()
for(var/T in subtypesof(/datum/map_template))
var/datum/map_template/template = T
if(!(initial(template.mappath))) // If it's missing the actual path its probably a base type or being used for inheritence.
continue
template = new T()
map_templates[template.name] = template
return TRUE
/datum/map_template
var/name = "Default Template Name"
var/desc = "Some text should go here. Maybe."
var/width = 0
var/height = 0
var/mappath = null
var/loaded = 0 // Times loaded this round
var/annihilate = FALSE // If true, all (movable) atoms at the location where the map is loaded will be deleted before the map is loaded in.
var/static/dmm_suite/maploader = new
/datum/map_template/New(path = null, rename = null)
if(path)
mappath = path
if(mappath)
preload_size(mappath)
if(rename)
name = rename
/datum/map_template/proc/preload_size(path)
var/bounds = maploader.load_map(file(path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE)
if(bounds)
width = bounds[MAP_MAXX] // Assumes all templates are rectangular, have a single Z level, and begin at 1,1,1
height = bounds[MAP_MAXY]
return bounds
/datum/map_template/proc/initTemplateBounds(var/list/bounds)
var/list/obj/machinery/atmospherics/atmos_machines = list()
var/list/atom/atoms = list()
var/list/area/areas = list()
// var/list/turf/turfs = list()
for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]),
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
var/turf/B = L
atoms += B
for(var/A in B)
atoms += A
// turfs += B
areas |= get_area(B)
if(istype(A, /obj/machinery/atmospherics))
atmos_machines += A
var/i = 0
// Apparently when areas get initialize()'d they initialize their turfs as well.
// If this is ever changed, uncomment the block of code below.
// admin_notice("<span class='danger'>Initializing newly created simulated turfs in submap.</span>", R_DEBUG)
// for(var/turf/simulated/T in turfs)
// T.initialize()
// i++
// admin_notice("<span class='danger'>[i] turf\s initialized.</span>", R_DEBUG)
// i = 0
SScreation.initialize_late_atoms()
admin_notice("<span class='danger'>Initializing newly created area(s) in submap.</span>", R_DEBUG)
for(var/area/A in areas)
A.initialize()
i++
admin_notice("<span class='danger'>[i] area\s initialized.</span>", R_DEBUG)
i = 0
admin_notice("<span class='danger'>Initializing atmos pipenets and machinery in submap.</span>", R_DEBUG)
for(var/obj/machinery/atmospherics/machine in atmos_machines)
machine.initialize()
i++
for(var/obj/machinery/atmospherics/machine in atmos_machines)
machine.build_network()
for(var/obj/machinery/atmospherics/unary/U in machines)
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
var/obj/machinery/atmospherics/unary/vent_pump/T = U
T.broadcast_status()
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
T.broadcast_status()
admin_notice("<span class='danger'>[i] pipe\s initialized.</span>", R_DEBUG)
admin_notice("<span class='danger'>Rebuilding powernets due to submap creation.</span>", R_DEBUG)
makepowernets()
admin_notice("<span class='danger'>Submap initializations finished.</span>", R_DEBUG)
/datum/map_template/proc/load_new_z()
var/x = round(world.maxx/2)
var/y = round(world.maxy/2)
var/list/bounds = maploader.load_map(file(mappath), x, y)
if(!bounds)
return FALSE
// repopulate_sorted_areas()
//initialize things that are normally initialized after map load
initTemplateBounds(bounds)
log_game("Z-level [name] loaded at at [x],[y],[world.maxz]")
return TRUE
/datum/map_template/proc/load(turf/T, centered = FALSE)
var/old_T = T
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
if(annihilate)
annihilate_bounds(old_T, centered)
var/list/bounds = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE)
if(!bounds)
return
// if(!SSmapping.loading_ruins) //Will be done manually during mapping ss init
// repopulate_sorted_areas()
//initialize things that are normally initialized after map load
initTemplateBounds(bounds)
log_game("[name] loaded at at [T.x],[T.y],[T.z]")
loaded++
return TRUE
/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE)
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))
/datum/map_template/proc/annihilate_bounds(turf/origin, centered = FALSE)
var/deleted_atoms = 0
admin_notice("<span class='danger'>Annihilating objects in submap loading locatation.</span>", R_DEBUG)
var/list/turfs_to_clean = get_affected_turfs(origin, centered)
if(turfs_to_clean.len)
for(var/turf/T in turfs_to_clean)
for(var/atom/movable/AM in T)
++deleted_atoms
qdel(AM)
admin_notice("<span class='danger'>Annihilated [deleted_atoms] objects.</span>", R_DEBUG)
//for your ever biggening badminnery kevinz000
//❤ - Cyberboss
/proc/load_new_z_level(var/file, var/name)
var/datum/map_template/template = new(file, name)
template.load_new_z()

View File

@@ -0,0 +1,466 @@
///////////////////////////////////////////////////////////////
//SS13 Optimized Map loader
//////////////////////////////////////////////////////////////
/*
//global datum that will preload variables on atoms instanciation
GLOBAL_VAR_INIT(use_preloader, FALSE)
GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new)
*/
//global datum that will preload variables on atoms instanciation
var/global/dmm_suite/preloader/_preloader = new()
var/global/use_preloader = FALSE
/dmm_suite
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
// /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g
var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g")
// /^[\s\n]+|[\s\n]+$/
var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g")
var/static/list/modelCache = list()
var/static/space_key
#ifdef TESTING
var/static/turfsSkipped
#endif
/**
* Construct the model map and control the loading process
*
* WORKING :
*
* 1) Makes an associative mapping of model_keys with model
* e.g aa = /turf/unsimulated/wall{icon_state = "rock"}
* 2) Read the map line by line, parsing the result (using parse_grid)
*
*/
/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num)
//How I wish for RAII
if(!measureOnly)
Master.StartLoadingMap()
space_key = null
#ifdef TESTING
turfsSkipped = 0
#endif
. = load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf)
#ifdef TESTING
if(turfsSkipped)
testing("Skipped loading [turfsSkipped] default turfs")
#endif
if(!measureOnly)
Master.StopLoadingMap()
/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf)
var/tfile = dmm_file//the map file we're creating
if(isfile(tfile))
tfile = file2text(tfile)
if(!x_offset)
x_offset = 1
if(!y_offset)
y_offset = 1
if(!z_offset)
z_offset = world.maxz + 1
var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
var/list/grid_models = list()
var/key_len = 0
var/stored_index = 1
while(dmmRegex.Find(tfile, stored_index))
stored_index = dmmRegex.next
// "aa" = (/type{vars=blah})
if(dmmRegex.group[1]) // Model
var/key = dmmRegex.group[1]
if(grid_models[key]) // Duplicate model keys are ignored in DMMs
continue
if(key_len != length(key))
if(!key_len)
key_len = length(key)
else
throw EXCEPTION("Inconsistant key length in DMM")
if(!measureOnly)
grid_models[key] = dmmRegex.group[2]
// (1,1,1) = {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
else if(dmmRegex.group[3]) // Coords
if(!key_len)
throw EXCEPTION("Coords before model definition in DMM")
var/xcrdStart = text2num(dmmRegex.group[3]) + x_offset - 1
//position of the currently processed square
var/xcrd
var/ycrd = text2num(dmmRegex.group[4]) + y_offset - 1
var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1
var/zexpansion = zcrd > world.maxz
if(zexpansion)
if(cropMap)
continue
else
world.maxz = zcrd //create a new z_level if needed
if(!no_changeturf)
WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems")
bounds[MAP_MINX] = min(bounds[MAP_MINX], xcrdStart)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd)
var/list/gridLines = splittext(dmmRegex.group[6], "\n")
var/leadingBlanks = 0
while(leadingBlanks < gridLines.len && gridLines[++leadingBlanks] == "")
if(leadingBlanks > 1)
gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines.
if(!gridLines.len) // Skip it if only blank lines exist.
continue
if(gridLines.len && gridLines[gridLines.len] == "")
gridLines.Cut(gridLines.len) // Remove only one blank line at the end.
bounds[MAP_MINY] = min(bounds[MAP_MINY], ycrd)
ycrd += gridLines.len - 1 // Start at the top and work down
if(!cropMap && ycrd > world.maxy)
if(!measureOnly)
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], ycrd)
else
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], min(ycrd, world.maxy))
var/maxx = xcrdStart
if(measureOnly)
for(var/line in gridLines)
maxx = max(maxx, xcrdStart + length(line) / key_len - 1)
else
for(var/line in gridLines)
if(ycrd <= world.maxy && ycrd >= 1)
xcrd = xcrdStart
for(var/tpos = 1 to length(line) - key_len + 1 step key_len)
if(xcrd > world.maxx)
if(cropMap)
break
else
world.maxx = xcrd
if(xcrd >= 1)
var/model_key = copytext(line, tpos, tpos + key_len)
var/no_afterchange = no_changeturf || zexpansion
if(!no_afterchange || (model_key != space_key))
if(!grid_models[model_key])
throw EXCEPTION("Undefined model key in DMM.")
parse_grid(grid_models[model_key], model_key, xcrd, ycrd, zcrd, no_changeturf || zexpansion)
#ifdef TESTING
else
++turfsSkipped
#endif
CHECK_TICK
maxx = max(maxx, xcrd)
++xcrd
--ycrd
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx)
CHECK_TICK
if(bounds[1] == 1.#INF) // Shouldn't need to check every item
return null
else
// if(!measureOnly)
// if(!no_changeturf)
// for(var/t in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
// var/turf/T = t
// //we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
// T.post_change()
return bounds
/**
* Fill a given tile with its area/turf/objects/mobs
* Variable model is one full map line (e.g /turf/unsimulated/wall{icon_state = "rock"}, /area/mine/explored)
*
* WORKING :
*
* 1) Read the model string, member by member (delimiter is ',')
*
* 2) Get the path of the atom and store it into a list
*
* 3) a) Check if the member has variables (text within '{' and '}')
*
* 3) b) Construct an associative list with found variables, if any (the atom index in members is the same as its variables in members_attributes)
*
* 4) Instanciates the atom with its variables
*
*/
/dmm_suite/proc/parse_grid(model as text, model_key as text, xcrd as num,ycrd as num,zcrd as num, no_changeturf as num)
/*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.
*/
var/list/members //will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/explored)
var/list/members_attributes //will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list())
var/list/cached = modelCache[model]
var/index
if(cached)
members = cached[1]
members_attributes = cached[2]
else
/////////////////////////////////////////////////////////
//Constructing members and corresponding variables lists
////////////////////////////////////////////////////////
members = list()
members_attributes = list()
index = 1
var/old_position = 1
var/dpos
do
//finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/explored)
dpos = find_next_delimiter_position(model, old_position, ",", "{", "}") //find next delimiter (comma here) that's not within {...}
var/full_def = trim_text(copytext(model, old_position, dpos)) //full definition, e.g : /obj/foo/bar{variables=derp}
var/variables_start = findtext(full_def, "{")
var/atom_def = text2path(trim_text(copytext(full_def, 1, variables_start))) //path definition, e.g /obj/foo/bar
old_position = dpos + 1
if(!atom_def) // Skip the item if the path does not exist. Fix your crap, mappers!
continue
members.Add(atom_def)
//transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
var/list/fields = list()
if(variables_start)//if there's any variable
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
fields = readlist(full_def, ";")
if(fields.len)
if(!trim(fields[fields.len]))
--fields.len
for(var/I in fields)
var/value = fields[I]
if(istext(value))
fields[I] = apply_text_macros(value)
//then fill the members_attributes list with the corresponding variables
members_attributes.len++
members_attributes[index++] = fields
CHECK_TICK
while(dpos != 0)
//check and see if we can just skip this turf
//So you don't have to understand this horrid statement, we can do this if
// 1. no_changeturf is set
// 2. the space_key isn't set yet
// 3. there are exactly 2 members
// 4. with no attributes
// 5. and the members are world.turf and world.area
// Basically, if we find an entry like this: "XXX" = (/turf/default, /area/default)
// We can skip calling this proc every time we see XXX
if(no_changeturf && !space_key && members.len == 2 && members_attributes.len == 2 && length(members_attributes[1]) == 0 && length(members_attributes[2]) == 0 && (world.area in members) && (world.turf in members))
space_key = model_key
return
modelCache[model] = list(members, members_attributes)
////////////////
//Instanciation
////////////////
//The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
var/turf/crds = locate(xcrd,ycrd,zcrd)
//first instance the /area and remove it from the members list
index = members.len
if(members[index] != /area/template_noop)
var/atom/instance
_preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
var/atype = members[index]
for(var/area/A in world)
if(A.type == atype)
instance = A
break
if(!instance)
instance = new atype(null)
if(crds)
instance.contents.Add(crds)
if(use_preloader && instance)
_preloader.load(instance)
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
var/first_turf_index = 1
while(!ispath(members[first_turf_index], /turf)) //find first /turf object in members
first_turf_index++
//turn off base new Initialization until the whole thing is loaded
SScreation.StartLoadingMap()
//instanciate the first /turf
var/turf/T
if(members[first_turf_index] != /turf/template_noop)
T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],crds,no_changeturf)
if(T)
//if others /turf are presents, simulates the underlays piling effect
index = first_turf_index + 1
while(index <= members.len - 1) // Last item is an /area
var/underlay = T.appearance
T = instance_atom(members[index],members_attributes[index],crds,no_changeturf)//instance new turf
T.underlays += underlay
index++
//finally instance all remainings objects/mobs
for(index in 1 to first_turf_index-1)
instance_atom(members[index],members_attributes[index],crds,no_changeturf)
//Restore initialization to the previous value
SScreation.StopLoadingMap()
////////////////
//Helpers procs
////////////////
//Instance an atom at (x,y,z) and gives it the variables in attributes
/dmm_suite/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf)
_preloader.setup(attributes, path)
if(crds)
if(!no_changeturf && ispath(path, /turf))
. = crds.ChangeTurf(path, FALSE, TRUE)
else
. = create_atom(path, crds)//first preloader pass
if(use_preloader && .)//second preloader pass, for those atoms that don't ..() in New()
_preloader.load(.)
//custom CHECK_TICK here because we don't want things created while we're sleeping to not initialize
if(TICK_CHECK)
SScreation.StopLoadingMap()
stoplag()
SScreation.StartLoadingMap()
/dmm_suite/proc/create_atom(path, crds)
set waitfor = FALSE
. = new path (crds)
//text trimming (both directions) helper proc
//optionally removes quotes before and after the text (for variable name)
/dmm_suite/proc/trim_text(what as text,trim_quotes=0)
if(trim_quotes)
return trimQuotesRegex.Replace(what, "")
else
return trimRegex.Replace(what, "")
//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(text as text,initial_position as num, delimiter=",",opening_escape="\"",closing_escape="\"")
var/position = initial_position
var/next_delimiter = findtext(text,delimiter,position,0)
var/next_opening = findtext(text,opening_escape,position,0)
while((next_opening != 0) && (next_opening < next_delimiter))
position = findtext(text,closing_escape,next_opening + 1,0)+1
next_delimiter = findtext(text,delimiter,position,0)
next_opening = findtext(text,opening_escape,position,0)
return next_delimiter
//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/readlist(text as text, delimiter=",")
var/list/to_return = list()
var/position
var/old_position = 1
do
//find next delimiter that is not within "..."
position = find_next_delimiter_position(text,old_position,delimiter)
//check if this is a simple variable (as in list(var1, var2)) or an associative one (as in list(var1="foo",var2=7))
var/equal_position = findtext(text,"=",old_position, position)
var/trim_left = trim_text(copytext(text,old_position,(equal_position ? equal_position : position)),1)//the name of the variable, must trim quotes to build a BYOND compliant associatives list
old_position = position + 1
if(equal_position)//associative var, so do the association
var/trim_right = trim_text(copytext(text,equal_position+1,position))//the content of the variable
//Check for string
if(findtext(trim_right,"\"",1,2))
trim_right = copytext(trim_right,2,findtext(trim_right,"\"",3,0))
//Check for number
else if(isnum(text2num(trim_right)))
trim_right = text2num(trim_right)
//Check for null
else if(trim_right == "null")
trim_right = null
//Check for list
else if(copytext(trim_right,1,5) == "list")
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
to_return[trim_left] = null
while(position != 0)
return to_return
/dmm_suite/Destroy()
..()
return QDEL_HINT_HARDDEL_NOW
//////////////////
//Preloader datum
//////////////////
/dmm_suite/preloader
parent_type = /datum
var/list/attributes
var/target_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)
var/value = attributes[attribute]
if(islist(value))
value = deepCopyList(value)
what.vars[attribute] = value
use_preloader = FALSE
/area/template_noop
name = "Area Passthrough"
/turf/template_noop
name = "Turf Passthrough"
icon_state = "template_void"

View File

@@ -82,6 +82,9 @@ var/global/datum/global_init/init = new ()
// This is kinda important. Set up details of what the hell things are made of.
populate_material_list()
// Loads all the pre-made submap templates.
load_map_templates()
if(config.generate_map)
if(using_map.perform_map_generation())
using_map.refresh_mining_turfs()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

27
maps/submaps/_readme.dm Normal file
View File

@@ -0,0 +1,27 @@
/*
This file will explain what a 'submap' is. Basically, they are smallish maps which are loaded on top of
the main map, using the dmm suite's map loading functionality. Generally this will be done by the game
automatically to sprinkle the play area with hidden buildings and treasure, baddies, or something along
those lines. Admins can also manually place these down where-ever and whenever they want, potentially
loading it into a new Z-level, for events and such.
Submaps have two parts, the map .dmm file itself, and a /datum/map_template object which describes the map.
Both should be included inside the correct places. Submaps are divided based on where the game expects to place
them, and the folder containing them also has their map template file. The divisions are mainly based around
thematic and location differences (e.g. space, caves, outdoors, asteroid, etc).
When a submap is loading, the game will 'lock' certain parts of itself, disallowing the loading of a second map until the first
finishes. When this is happening, atmospherics is also disabled, to prevent ZAS from displacing things and
venting unfinished rooms. There is some noticable lag if the loading takes awhile, but it remains playable
and it doesn't lock up the came entirely. Small submaps should load in less than a second, while loading, say, polaris3.dmm
generally takes the server a minute or two, so try to not make your submap too large if possible.
You can use /area/template_noop and /turf/template_noop to act as 'void' areas/tiles, which won't be applied to the
main map.
Map template datums can have the 'annihilate' var set to TRUE if you need to clear everything where the submap
is being loaded (to clear trees, etc). Be sure to not load the map on top of anything valuable to you when using that, like
irreplacable objects or players, as they will all get deleted if annihilate is on. If you load the submap before
other objects have a chance to spawn (before random map gen), you shouldn't need to use annihilate.
*/

View File

@@ -0,0 +1,5 @@
/datum/map_template/cave
name = "Cave Content"
desc = "Don't dig too deep!"
// To be added: Templates for cave exploration when they are made.

View File

@@ -0,0 +1,5 @@
/datum/map_template/space
name = "Space Content"
desc = "A map template base. In space."
// To be added: Templates for space exploration when they are made.

View File

@@ -0,0 +1,5 @@
/datum/map_template/surface
name = "Surface Content"
desc = "Used to make the surface by 17% less boring."
// To be added: Templates for surface exploration when they are made.

View File

@@ -171,6 +171,7 @@
#include "code\controllers\Processes\vote.dm"
#include "code\controllers\ProcessScheduler\core\process.dm"
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
#include "code\controllers\subsystems\creation.dm"
#include "code\controllers\subsystems\garbage.dm"
#include "code\datums\ai_law_sets.dm"
#include "code\datums\ai_laws.dm"
@@ -1136,6 +1137,7 @@
#include "code\modules\admin\verbs\dice.dm"
#include "code\modules\admin\verbs\getlogs.dm"
#include "code\modules\admin\verbs\grief_fixers.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"
@@ -1503,10 +1505,9 @@
#include "code\modules\lore_codex\lore_data\orgs.dm"
#include "code\modules\lore_codex\lore_data\political_parties.dm"
#include "code\modules\lore_codex\lore_data\species.dm"
#include "code\modules\maps\dmm_suite.dm"
#include "code\modules\maps\reader.dm"
#include "code\modules\maps\swapmaps.dm"
#include "code\modules\maps\writer.dm"
#include "code\modules\maps\tg\dmm_suite.dm"
#include "code\modules\maps\tg\map_template.dm"
#include "code\modules\maps\tg\reader.dm"
#include "code\modules\materials\fifty_spawner_mats.dm"
#include "code\modules\materials\material_recipes.dm"
#include "code\modules\materials\material_sheets.dm"
@@ -2277,5 +2278,9 @@
#include "interface\interface.dm"
#include "interface\skin.dmf"
#include "maps\northern_star\northern_star.dm"
#include "maps\submaps\_readme.dm"
#include "maps\submaps\cave_submaps\cave.dm"
#include "maps\submaps\space_submaps\space.dm"
#include "maps\submaps\surface_submaps\forest.dm"
#include "maps\~map_system\maps.dm"
// END_INCLUDE