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