diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 1e972dd46d2..70a336934aa 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -33,7 +33,7 @@ datum/controller/game_controller
var/mob/list/expensive_mobs = list()
var/list/shuttle_list // For debugging and VV
- var/datum/ore_distribution/asteroid_ore_map // For debugging and VV.
+ var/datum/random_map/ore/asteroid_ore_map // For debugging and VV.
datum/controller/game_controller/New()
@@ -109,8 +109,9 @@ datum/controller/game_controller/proc/setup_objects()
T.broadcast_status()
//Create the mining ore distribution map.
- asteroid_ore_map = new /datum/ore_distribution()
- asteroid_ore_map.populate_distribution_map()
+ // These values determine the specific area that the map is applied to.
+ // If you do not use the official Baycode asteroid map, you will need to change them.
+ asteroid_ore_map = new /datum/random_map/ore(null,13,32,5,217,223)
//Shitty hack to fix mining turf overlays, for some reason New() is not being called.
for(var/turf/simulated/floor/plating/airless/asteroid/T in world)
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index 263a91769b6..73c453824ce 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -1,26 +1,17 @@
//TODO: rewrite and standardise all controller datums to the datum/controller type
//TODO: allow all controllers to be deleted for clean restarts (see WIP master controller stuff) - MC done - lighting done
-/client/proc/show_distribution_map()
+/client/proc/print_random_map()
set category = "Debug"
- set name = "Show Distribution Map"
- set desc = "Print the asteroid ore distribution map to the world."
+ set name = "Display Random Map"
+ set desc = "Show the contents of a random map."
if(!holder) return
- if(master_controller && master_controller.asteroid_ore_map)
- master_controller.asteroid_ore_map.print_distribution_map(usr)
-
-/client/proc/remake_distribution_map()
- set category = "Debug"
- set name = "Remake Distribution Map"
- set desc = "Rebuild the asteroid ore distribution map."
-
- if(!holder) return
-
- if(master_controller && master_controller.asteroid_ore_map)
- master_controller.asteroid_ore_map = new /datum/ore_distribution()
- master_controller.asteroid_ore_map.populate_distribution_map()
+ var/datum/random_map/choice = input("Choose a map to debug.") as null|anything in random_maps
+ if(!choice)
+ return
+ choice.display_map(usr)
/client/proc/restart_controller(controller in list("Master","Failsafe","Lighting","Supply"))
set category = "Debug"
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index d20105a67e6..4a19264defe 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -148,8 +148,7 @@ var/list/admin_verbs_debug = list(
/client/proc/reload_admins,
/client/proc/reload_mentors,
/client/proc/restart_controller,
- /client/proc/remake_distribution_map,
- /client/proc/show_distribution_map,
+ /client/proc/print_random_map,
/client/proc/show_plant_genes,
/client/proc/enable_debug_verbs,
/client/proc/callproc,
diff --git a/code/modules/mining/drilling/distribution.dm b/code/modules/mining/drilling/distribution.dm
deleted file mode 100644
index 33654da273d..00000000000
--- a/code/modules/mining/drilling/distribution.dm
+++ /dev/null
@@ -1,233 +0,0 @@
-//If anyone can think of a less shitty way to work out x,y points on a linear string of integers please tell me.
-#define MAP_CELL ((y-1)*real_size)+x
-#define MAP_CENTRE (((y-1)+size/2)*real_size)+(x+size/2)
-#define MAP_TOP_LEFT ((y-1)*real_size)+x
-#define MAP_TOP_RIGHT ((y-1)*real_size)+(x+size)
-#define MAP_BOTTOM_LEFT (((y+size)-1)*real_size)+x
-#define MAP_BOTTOM_RIGHT ((((y+size)-1)*real_size)+(x+size))
-#define MAP_MID_TOP MAP_TOP_LEFT + (size/2)
-#define MAP_MID_BOTTOM MAP_BOTTOM_LEFT + (size/2)
-#define MAP_MID_LEFT (((y-1)+size/2)*real_size)+x
-#define MAP_MID_RIGHT (((y-1)+size/2)*real_size)+(x+size)
-
-#define MIN_SURFACE_COUNT 1000
-#define MAX_SURFACE_COUNT 5000
-#define MIN_RARE_COUNT 1000
-#define MAX_RARE_COUNT 5000
-#define MIN_DEEP_COUNT 100
-#define MAX_DEEP_COUNT 300
-#define ITERATE_BEFORE_FAIL 200
-
-#define RESOURCE_HIGH_MAX 4
-#define RESOURCE_HIGH_MIN 2
-#define RESOURCE_MID_MAX 3
-#define RESOURCE_MID_MIN 1
-#define RESOURCE_LOW_MAX 1
-#define RESOURCE_LOW_MIN 0
-
-/*
-Surface minerals:
- silicates
- iron
- gold
- silver
-
-Rare minerals:
- uranium
- diamond
-
-Deep minerals:
- phoron
- osmium (platinum)
- tritium (hydrogen)
-*/
-
-/datum/ore_distribution
-
- var/real_size = 65 //Overall map size ((must be power of 2)+1)
- var/chunk_size = 4 //Size each cell represents on map (like hell we're generating up to 100 256^2 grids at roundstart)
- var/list/map[4225] //The actual map. real_size squared.
- var/range = 255 //Max random range of cells in map.
-
- var/random_variance_chance = 25
- var/random_element = 0.5
-
-/datum/ore_distribution/proc/map_is_sane()
- if(!map) return 0
-
- var/rare_count = 0
- var/surface_count = 0
- var/deep_count = 0
-
- for(var/cell in map)
- if(cell>(range*0.60))
- deep_count++
- else if(cell>(range*0.40))
- rare_count++
- else
- surface_count++
-
- if(surface_count < MIN_SURFACE_COUNT || surface_count > MAX_SURFACE_COUNT) return 0
- if(rare_count < MIN_RARE_COUNT || rare_count > MAX_RARE_COUNT) return 0
- if(deep_count < MIN_DEEP_COUNT || deep_count > MAX_DEEP_COUNT) return 0
- return 1
-
-//Halfassed diamond-square algorithm with some fuckery since it's a single dimension array.
-/datum/ore_distribution/proc/populate_distribution_map()
-
- //Seed beginning values.
- var/x = 1
- var/y = 1
- var/size = real_size-1
- map[MAP_TOP_LEFT] = (range/3)+rand(range/5)
- map[MAP_TOP_RIGHT] = (range/3)+rand(range/5)
- map[MAP_BOTTOM_LEFT] = (range/3)+rand(range/5)
- map[MAP_BOTTOM_RIGHT] = (range/3)+rand(range/5)
-
- //Fill in and smooth it out.
- var/attempts = 0
- do
- attempts++
- generate_distribution_map(1,1,size)
- while(attempts < ITERATE_BEFORE_FAIL && !map_is_sane())
-
- if(attempts >= ITERATE_BEFORE_FAIL)
- world << "Could not generate a sane distribution map. Aborting."
- map = null
- return
- else
- apply_to_asteroid()
-
-/datum/ore_distribution/proc/clear_distribution_map()
- for(var/x = 1, x <= real_size, x++)
- for(var/y = 1, y <= real_size, y++)
- map[MAP_CELL] = 0
-
-/datum/ore_distribution/proc/print_distribution_map(var/mob/usr)
- var/line = ""
- for(var/x = 1, x <= real_size, x++)
- for(var/y = 1, y <= real_size, y++)
- line += num2text(round(map[MAP_CELL]/25.5))
- if(usr)
- usr << line
- else
- world << line
- line = ""
-
-/datum/ore_distribution/proc/generate_distribution_map(var/x,var/y,var/input_size)
-
- var/size = input_size
-
- map[MAP_MID_TOP] = (map[MAP_TOP_LEFT] + map[MAP_TOP_RIGHT])/2
- map[MAP_MID_RIGHT] = (map[MAP_BOTTOM_RIGHT] + map[MAP_TOP_RIGHT])/2
- map[MAP_MID_BOTTOM] = (map[MAP_BOTTOM_LEFT] + map[MAP_BOTTOM_RIGHT])/2
- map[MAP_MID_LEFT] = (map[MAP_TOP_LEFT] + map[MAP_BOTTOM_RIGHT])/2
- map[MAP_CENTRE] = (map[MAP_MID_LEFT]+map[MAP_MID_RIGHT]+map[MAP_MID_BOTTOM]+map[MAP_MID_TOP])/4
-
- if(prob(random_variance_chance))
- map[MAP_CENTRE] *= (rand(1) ? (1.0-random_element) : (1.0+random_element))
- map[MAP_CENTRE] = max(0,min(range,map[MAP_CENTRE]))
-
- if(size>3)
- generate_distribution_map(x,y,input_size/2)
- generate_distribution_map(x+(input_size/2),y,input_size/2)
- generate_distribution_map(x,y+(input_size/2),input_size/2)
- generate_distribution_map(x+(input_size/2),y+(input_size/2),input_size/2)
-
-/datum/ore_distribution/proc/apply_to_asteroid()
-
- // THESE VALUES DETERMINE THE AREA THAT THE DISTRIBUTION MAP IS APPLIED TO.
- // IF YOU DO NOT RUN OFFICIAL BAYCODE ASTEROID MAP YOU NEED TO CHANGE THEM.
- // ORIGIN IS THE BOTTOM LEFT CORNER OF THE SQUARE CONTAINING ALL ASTEROID
- // TILES YOU WISH TO APPLY THE DISTRIBUTION MAP TO.
-
- var/origin_x = 13 //We start here...
- var/origin_y = 32 //...and here...
- var/limit_x = 217 //...and iterate until here...
- var/limit_y = 223 //...and here...
- var/asteroid_z = 5 //...on this Z-level.
-
- var/tx = origin_x
- var/ty = origin_y
-
- for(var/y = 1, y <= real_size, y++)
-
- for(var/x = 1, x <= real_size, x++)
-
- var/turf/target_turf
-
- for(var/i=0,i limit_x || ty+i > limit_y)
- continue
-
- target_turf = locate(tx+j, ty+i, asteroid_z)
-
- if(target_turf && target_turf.has_resources)
- target_turf.resources = list()
- target_turf.resources["silicates"] = rand(3,5)
- target_turf.resources["carbonaceous rock"] = rand(3,5)
-
- switch(map[MAP_CELL])
- if(0 to 100)
- target_turf.resources["iron"] = rand(RESOURCE_HIGH_MIN,RESOURCE_HIGH_MAX)
- target_turf.resources["gold"] = rand(RESOURCE_LOW_MIN,RESOURCE_LOW_MAX)
- target_turf.resources["silver"] = rand(RESOURCE_LOW_MIN,RESOURCE_LOW_MAX)
- target_turf.resources["uranium"] = rand(RESOURCE_LOW_MIN,RESOURCE_LOW_MAX)
- target_turf.resources["diamond"] = 0
- target_turf.resources["phoron"] = 0
- target_turf.resources["osmium"] = 0
- target_turf.resources["hydrogen"] = 0
- if(100 to 124)
- target_turf.resources["iron"] = 0
- target_turf.resources["gold"] = rand(RESOURCE_MID_MIN,RESOURCE_MID_MAX)
- target_turf.resources["silver"] = rand(RESOURCE_MID_MIN,RESOURCE_MID_MAX)
- target_turf.resources["uranium"] = rand(RESOURCE_MID_MIN,RESOURCE_MID_MAX)
- target_turf.resources["diamond"] = 0
- target_turf.resources["phoron"] = rand(RESOURCE_MID_MIN,RESOURCE_MID_MAX)
- target_turf.resources["osmium"] = rand(RESOURCE_MID_MIN,RESOURCE_MID_MAX)
- target_turf.resources["hydrogen"] = 0
- if(125 to 255)
- target_turf.resources["iron"] = 0
- target_turf.resources["gold"] = 0
- target_turf.resources["silver"] = 0
- target_turf.resources["uranium"] = rand(RESOURCE_LOW_MIN,RESOURCE_LOW_MAX)
- target_turf.resources["diamond"] = rand(RESOURCE_LOW_MIN,RESOURCE_LOW_MAX)
- target_turf.resources["phoron"] = rand(RESOURCE_HIGH_MIN,RESOURCE_HIGH_MAX)
- target_turf.resources["osmium"] = rand(RESOURCE_HIGH_MIN,RESOURCE_HIGH_MAX)
- target_turf.resources["hydrogen"] = rand(RESOURCE_MID_MIN,RESOURCE_MID_MAX)
-
- tx += chunk_size
- tx = origin_x
- ty += chunk_size
-
- world << "Resource map generation complete."
- return
-
-#undef MAP_CELL
-#undef MAP_CENTRE
-#undef MAP_TOP_LEFT
-#undef MAP_TOP_RIGHT
-#undef MAP_BOTTOM_LEFT
-#undef MAP_BOTTOM_RIGHT
-#undef MAP_MID_TOP
-#undef MAP_MID_BOTTOM
-#undef MAP_MID_LEFT
-#undef MAP_MID_RIGHT
-
-#undef MIN_SURFACE_COUNT
-#undef MAX_SURFACE_COUNT
-#undef MIN_RARE_COUNT
-#undef MAX_RARE_COUNT
-#undef MIN_DEEP_COUNT
-#undef MAX_DEEP_COUNT
-#undef ITERATE_BEFORE_FAIL
-
-#undef RESOURCE_HIGH_MAX
-#undef RESOURCE_HIGH_MIN
-#undef RESOURCE_MID_MAX
-#undef RESOURCE_MID_MIN
-#undef RESOURCE_LOW_MAX
-#undef RESOURCE_LOW_MIN
diff --git a/code/modules/random_map/mining_distribution.dm b/code/modules/random_map/mining_distribution.dm
new file mode 100644
index 00000000000..adf5e3fb70f
--- /dev/null
+++ b/code/modules/random_map/mining_distribution.dm
@@ -0,0 +1,212 @@
+#define MIN_SURFACE_COUNT 1000
+#define MAX_SURFACE_COUNT 5000
+#define MIN_RARE_COUNT 1000
+#define MAX_RARE_COUNT 5000
+#define MIN_DEEP_COUNT 100
+#define MAX_DEEP_COUNT 300
+
+#define RESOURCE_HIGH_MAX 4
+#define RESOURCE_HIGH_MIN 2
+#define RESOURCE_MID_MAX 3
+#define RESOURCE_MID_MIN 1
+#define RESOURCE_LOW_MAX 1
+#define RESOURCE_LOW_MIN 0
+
+/*
+Surface minerals:
+ silicates
+ iron
+ gold
+ silver
+Rare minerals:
+ uranium
+ diamond
+Deep minerals:
+ phoron
+ osmium (platinum)
+ tritium (hydrogen)
+*/
+
+/datum/random_map/ore
+
+ descriptor = "resource distribution map"
+ real_size = 65 // Must be (power of 2)+1 for diamond-square.
+ cell_range = 255 // These values are used to seed ore values rather than to determine a turf type.
+ iterations = 0 // We'll handle that on our end.
+
+ var/chunk_size = 4 // Size each cell represents on map
+ var/random_variance_chance = 25 // % chance of applying random_element.
+ var/random_element = 0.5 // Determines the variance when smoothing out cell values.
+ var/deep_val = 50
+ var/rare_val = 100
+
+/datum/random_map/ore/New()
+ deep_val = cell_range*0.60
+ rare_val = cell_range*0.40
+ ..()
+
+/datum/random_map/ore/check_map_sanity()
+
+ var/rare_count = 0
+ var/surface_count = 0
+ var/deep_count = 0
+
+ for(var/x = 1, x <= real_size, x++)
+ for(var/y = 1, y <= real_size, y++)
+ var/current_cell = get_map_cell(x,y)
+ if(!within_bounds(current_cell))
+ continue
+ switch(map[current_cell])
+ if(0 to rare_val)
+ surface_count++
+ if(rare_val to deep_val)
+ rare_count++
+ if(deep_val to INFINITY)
+ deep_count++
+
+ if((surface_count < MIN_SURFACE_COUNT) || (surface_count > MAX_SURFACE_COUNT))
+ world << "Insufficient surface minerals. Rerolling..."
+ return 0
+ else if((rare_count < MIN_RARE_COUNT) || (rare_count > MAX_RARE_COUNT))
+ world << "Insufficient rare minerals. Rerolling..."
+ return 0
+ else if((deep_count < MIN_DEEP_COUNT) || (deep_count > MAX_DEEP_COUNT))
+ world << "Insufficient deep minerals. Rerolling..."
+ return 0
+ else
+ return 1
+
+//Halfassed diamond-square algorithm with some fuckery since it's a single dimension array.
+/datum/random_map/ore/seed_map()
+
+ // Instantiate the grid.
+ for(var/x = 1, x <= real_size, x++)
+ for(var/y = 1, y <= real_size, y++)
+ map[get_map_cell(x,y)] = -1
+
+ // Now dump in the actual random data.
+ size = real_size-1
+ map[get_map_cell(1,1)] = (cell_range/3)+rand(cell_range/5)
+ map[get_map_cell(1,real_size)] = (cell_range/3)+rand(cell_range/5)
+ map[get_map_cell(real_size,real_size)] = (cell_range/3)+rand(cell_range/5)
+ map[get_map_cell(real_size,1)] = (cell_range/3)+rand(cell_range/5)
+ iterate(1,1,1,size) // Handle iteration here since we use different args to parent.
+
+/datum/random_map/ore/display_map(atom/user)
+
+ if(!user)
+ user = world
+
+ for(var/x = 1, x <= real_size, x++)
+ var/line = ""
+ for(var/y = 1, y <= real_size, y++)
+ var/current_cell = get_map_cell(x,y)
+ if(within_bounds(current_cell) && map[current_cell])
+ switch(map[current_cell])
+ if(0 to rare_val)
+ line += "S"
+ if(rare_val to deep_val)
+ line += "R"
+ if(deep_val to INFINITY)
+ line += "D"
+ else
+ line += "?"
+ else
+ line += "X"
+ user << line
+
+/datum/random_map/ore/iterate(var/iteration,var/x,var/y,var/input_size)
+
+ // Infinite loop check!
+ if(iteration>=iterate_before_fail)
+ world << "Iteration count exceeded, aborting."
+ return
+
+ // Make sure we're using the right size for our subdivisions.
+ size = input_size
+ var/hsize = round(size/2)
+
+ /*
+ (x,y+size)-----(x+hsize,y+size)-----(x+size,y+size)
+ | | |
+ | | |
+ | | |
+ (x,y+hsize)----(x+hsize,y+hsize)----(x+size,y)
+ | | |
+ | | |
+ | | |
+ (x,y)----------(x+hsize,y)----------(x+size,y)
+ */
+ // Central edge values become average of corners.
+ map[get_map_cell(x+hsize,y+size)] = round((map[get_map_cell(x,y+size)] + map[get_map_cell(x+size,y+size)])/2)
+ map[get_map_cell(x+hsize,y)] = round((map[get_map_cell(x,y)]+map[get_map_cell(x+size,y)])/2)
+ map[get_map_cell(x,y+hsize)] = round((map[get_map_cell(x,y+size)]+map[get_map_cell(x,y)])/2)
+ map[get_map_cell(x+size,y)] = round((map[get_map_cell(x+size,y+size)]+map[get_map_cell(x+size,y)])/2)
+
+ // Centre value becomes the average of all other values + possible random variance.
+ var/current_cell = get_map_cell(x+hsize,y+hsize)
+ map[current_cell] = round((map[get_map_cell(x+hsize,y+size)]+map[get_map_cell(x+hsize,y)]+map[get_map_cell(x,y+hsize)]+map[get_map_cell(x+size,y)])/4)
+ if(prob(random_variance_chance))
+ map[current_cell] *= (rand(1) ? (1.0-random_element) : (1.0+random_element))
+ map[current_cell] = max(0,min(cell_range,map[current_cell]))
+
+ // Recurse until size is too small to subdivide.
+ if(size>3)
+ iteration++
+ iterate(iteration, x, y, hsize)
+ iterate(iteration, x+hsize, y, hsize)
+ iterate(iteration, x, y+hsize, hsize)
+ iterate(iteration, x+hsize, y+hsize, hsize)
+
+/datum/random_map/ore/apply_to_turf(var/x,var/y,var/turf/T)
+
+ var/tx = (x-1)*chunk_size
+ var/ty = (y-1)*chunk_size
+
+ for(var/i=0,ilimit_y)
+ continue
+ for(var/j=0,jlimit_x)
+ continue
+
+ T = locate(tx+j, ty+i, origin_z)
+ if(!T || !T.has_resources)
+ continue
+
+ T.resources = list()
+ T.resources["silicates"] = rand(3,5)
+ T.resources["carbonaceous rock"] = rand(3,5)
+
+ switch(map[get_map_cell(x,y)])
+ if(0 to 100)
+ T.resources["iron"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
+ T.resources["gold"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
+ T.resources["silver"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
+ T.resources["uranium"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
+ T.resources["diamond"] = 0
+ T.resources["phoron"] = 0
+ T.resources["osmium"] = 0
+ T.resources["hydrogen"] = 0
+ if(100 to 124)
+ T.resources["gold"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
+ T.resources["silver"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
+ T.resources["uranium"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
+ T.resources["phoron"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
+ T.resources["osmium"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
+ T.resources["hydrogen"] = 0
+ T.resources["diamond"] = 0
+ T.resources["iron"] = 0
+ if(125 to 255)
+ T.resources["uranium"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
+ T.resources["diamond"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
+ T.resources["phoron"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
+ T.resources["osmium"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
+ T.resources["hydrogen"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
+ T.resources["iron"] = 0
+ T.resources["gold"] = 0
+ T.resources["silver"] = 0
+ return
+
+/datum/random_map/ore/cleanup()
+ return 1
\ No newline at end of file