diff --git a/code/_helpers/math.dm b/code/_helpers/math.dm new file mode 100644 index 0000000000..d6c1de0bc6 --- /dev/null +++ b/code/_helpers/math.dm @@ -0,0 +1,5 @@ +/proc/IsPowerOfTwo(var/val) + return (val & (val-1)) == 0 + +/proc/RoundUpToPowerOfTwo(var/val) + return 2 ** -round(-log(2,val)) diff --git a/code/modules/random_map/_random_map_setup.dm b/code/modules/random_map/_random_map_setup.dm index 01c57f2f76..50570e848c 100644 --- a/code/modules/random_map/_random_map_setup.dm +++ b/code/modules/random_map/_random_map_setup.dm @@ -3,20 +3,29 @@ */ #define MIN_SURFACE_COUNT 500 -#define MIN_RARE_COUNT 200 -#define MIN_DEEP_COUNT 100 -#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 +#define MIN_RARE_COUNT 200 +#define MIN_DEEP_COUNT 100 +#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 -#define FLOOR_CHAR 0 -#define WALL_CHAR 1 -#define DOOR_CHAR 2 -#define EMPTY_CHAR 3 -#define ROOM_TEMP_CHAR 4 -#define MONSTER_CHAR 5 -#define ARTIFACT_TURF_CHAR 6 -#define ARTIFACT_CHAR 7 \ No newline at end of file +#define FLOOR_CHAR 0 +#define WALL_CHAR 1 +#define DOOR_CHAR 2 +#define EMPTY_CHAR 3 +#define ROOM_TEMP_CHAR 4 +#define MONSTER_CHAR 5 +#define ARTIFACT_TURF_CHAR 6 +#define ARTIFACT_CHAR 7 + +#define TRANSLATE_COORD(X,Y) ((((Y) - 1) * limit_x) + (X)) +#define TRANSLATE_AND_VERIFY_COORD(X,Y) TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,map.len) + +#define TRANSLATE_AND_VERIFY_COORD_MLEN(X,Y,LEN) \ + tmp_cell = TRANSLATE_COORD(X,Y);\ + if (tmp_cell < 1 || tmp_cell > LEN) {\ + tmp_cell = null;\ + } diff --git a/code/modules/random_map/automata/automata.dm b/code/modules/random_map/automata/automata.dm index f3867d78bd..544b625a33 100644 --- a/code/modules/random_map/automata/automata.dm +++ b/code/modules/random_map/automata/automata.dm @@ -1,3 +1,7 @@ +#define CELL_ALIVE(VAL) (VAL == cell_live_value) +#define KILL_CELL(CELL, NEXT_MAP) NEXT_MAP[CELL] = cell_dead_value; +#define REVIVE_CELL(CELL, NEXT_MAP) NEXT_MAP[CELL] = cell_live_value; + /datum/random_map/automata descriptor = "generic caves" initial_wall_cell = 55 @@ -8,58 +12,60 @@ // Automata-specific procs and processing. /datum/random_map/automata/generate_map() - for(var/i=1;i<=iterations;i++) - iterate(i) + for(var/iter = 1 to iterations) + var/list/next_map[limit_x*limit_y] + var/count + var/is_not_border_left + var/is_not_border_right + var/ilim_u + var/ilim_d + var/bottom_lim = ((limit_y - 1) * limit_x) -/datum/random_map/automata/get_additional_spawns(var/value, var/turf/T) - return + if (!islist(map)) + set_map_size() -/datum/random_map/automata/proc/iterate(var/iteration) - var/list/next_map[limit_x*limit_y] - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - var/current_cell = get_map_cell(x,y) - next_map[current_cell] = map[current_cell] - var/count = 0 + for (var/i in 1 to (limit_x * limit_y)) + count = 0 - // Every attempt to place this in a proc or a list has resulted in - // the generator being totally bricked and useless. Fuck it. We're - // hardcoding this shit. Feel free to rewrite and PR a fix. ~ Z - var/tmp_cell = get_map_cell(x,y) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x+1,y+1) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x-1,y-1) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x+1,y-1) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x-1,y+1) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x-1,y) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x,y-1) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x+1,y) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ - tmp_cell = get_map_cell(x,y+1) - if(tmp_cell && cell_is_alive(map[tmp_cell])) count++ + is_not_border_left = i != 1 && ((i - 1) % limit_x) + is_not_border_right = i % limit_x + + if (CELL_ALIVE(map[i])) // Center row. + ++count + if (is_not_border_left && CELL_ALIVE(map[i - 1])) + ++count + if (is_not_border_right && CELL_ALIVE(map[i + 1])) + ++count + + if (i > limit_x) // top row + ilim_u = i - limit_x + if (CELL_ALIVE(map[ilim_u])) + ++count + if (is_not_border_left && CELL_ALIVE(map[ilim_u - 1])) + ++count + if (is_not_border_right && CELL_ALIVE(map[ilim_u + 1])) + ++count + + if (i <= bottom_lim) // bottom row + ilim_d = i + limit_x + if (CELL_ALIVE(map[ilim_d])) + ++count + if (is_not_border_left && CELL_ALIVE(map[ilim_d - 1])) + ++count + if (is_not_border_right && CELL_ALIVE(map[ilim_d + 1])) + ++count if(count >= cell_threshold) - revive_cell(current_cell, next_map, (iteration == iterations)) - else - kill_cell(current_cell, next_map, (iteration == iterations)) - map = next_map + REVIVE_CELL(i, next_map) + else // Nope. Can't be alive. Kill it. + KILL_CELL(i, next_map) -// Check if a given tile counts as alive for the automata generations. -/datum/random_map/automata/proc/cell_is_alive(var/value) - return (value == cell_live_value) && (value != cell_dead_value) + CHECK_TICK -/datum/random_map/automata/proc/revive_cell(var/target_cell, var/list/use_next_map, var/final_iter) - if(!use_next_map) - use_next_map = map - use_next_map[target_cell] = cell_live_value + map = next_map -/datum/random_map/automata/proc/kill_cell(var/target_cell, var/list/use_next_map, var/final_iter) - if(!use_next_map) - use_next_map = map - use_next_map[target_cell] = cell_dead_value \ No newline at end of file +/datum/random_map/automata/get_additional_spawns(value, turf/T) + return + +#undef KILL_CELL +#undef REVIVE_CELL \ No newline at end of file diff --git a/code/modules/random_map/automata/caves.dm b/code/modules/random_map/automata/caves.dm index e1f2092bdb..c5121dcf57 100644 --- a/code/modules/random_map/automata/caves.dm +++ b/code/modules/random_map/automata/caves.dm @@ -18,28 +18,36 @@ return "X" return ..(value) -/datum/random_map/automata/cave_system/revive_cell(var/target_cell, var/list/use_next_map, var/final_iter) - ..() - if(final_iter) - ore_turfs |= target_cell - -/datum/random_map/automata/cave_system/kill_cell(var/target_cell, var/list/use_next_map, var/final_iter) - ..() - if(final_iter) - ore_turfs -= target_cell - // Create ore turfs. /datum/random_map/automata/cave_system/cleanup() + var/tmp_cell + for (var/x = 1 to limit_x) + for (var/y = 1 to limit_y) + tmp_cell = TRANSLATE_COORD(x, y) + if (CELL_ALIVE(map[tmp_cell])) + ore_turfs += tmp_cell + + testing("ASGEN: Found [ore_turfs.len] ore turfs.") var/ore_count = round(map.len/20) + var/door_count = 0 + var/empty_count = 0 while((ore_count>0) && (ore_turfs.len>0)) - if(!priority_process) sleep(-1) + + if(!priority_process) + CHECK_TICK + var/check_cell = pick(ore_turfs) ore_turfs -= check_cell if(prob(75)) map[check_cell] = DOOR_CHAR // Mineral block + door_count += 1 else map[check_cell] = EMPTY_CHAR // Rare mineral block. + empty_count += 1 ore_count-- + + testing("ASGEN: Set [door_count] turfs to random minerals.") + testing("ASGEN: Set [empty_count] turfs to high-chance random minerals.") return 1 /datum/random_map/automata/cave_system/apply_to_turf(var/x,var/y) @@ -60,4 +68,4 @@ else if(map[current_cell] == EMPTY_CHAR) T.make_ore(1) get_additional_spawns(map[current_cell],T,get_spawn_dir(x, y)) - return T \ No newline at end of file + return T diff --git a/code/modules/random_map/noise/noise.dm b/code/modules/random_map/noise/noise.dm index 8e45a21c3f..50a56f9f12 100644 --- a/code/modules/random_map/noise/noise.dm +++ b/code/modules/random_map/noise/noise.dm @@ -10,6 +10,7 @@ var/cell_base // Set in New() var/initial_cell_range // Set in New() var/smoothing_iterations = 0 + var/smooth_single_tiles // Single turfs of different value are not allowed /datum/random_map/noise/New() initial_cell_range = cell_range/5 @@ -19,10 +20,10 @@ /datum/random_map/noise/set_map_size() // Make sure the grid is a square with limits that are // (n^2)+1, otherwise diamond-square won't work. - if(!ISPOWEROFTWO((limit_x-1))) - limit_x = ROUNDUPTOPOWEROFTWO(limit_x) + 1 - if(!ISPOWEROFTWO((limit_y-1))) - limit_y = ROUNDUPTOPOWEROFTWO(limit_y) + 1 + if(!IsPowerOfTwo((limit_x-1))) + limit_x = RoundUpToPowerOfTwo(limit_x) + 1 + if(!IsPowerOfTwo((limit_y-1))) + limit_y = RoundUpToPowerOfTwo(limit_y) + 1 // Sides must be identical lengths. if(limit_x > limit_y) limit_y = limit_x @@ -35,13 +36,13 @@ // Instantiate the grid. for(var/x = 1, x <= limit_x, x++) for(var/y = 1, y <= limit_y, y++) - map[get_map_cell(x,y)] = 0 + map[TRANSLATE_COORD(x,y)] = 0 // Now dump in the actual random data. - map[get_map_cell(1,1)] = cell_base+rand(initial_cell_range) - map[get_map_cell(1,limit_y)] = cell_base+rand(initial_cell_range) - map[get_map_cell(limit_x,limit_y)] = cell_base+rand(initial_cell_range) - map[get_map_cell(limit_x,1)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(1,1)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(1,limit_y)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(limit_x,limit_y)] = cell_base+rand(initial_cell_range) + map[TRANSLATE_COORD(limit_x,1)] = cell_base+rand(initial_cell_range) /datum/random_map/noise/generate_map() // Begin recursion. @@ -52,6 +53,9 @@ if(isnull(val)) val = 0 return "[val]" +/datum/random_map/noise/proc/noise2value(var/value) + return min(9,max(0,round((value/cell_range)*10))) + /datum/random_map/noise/proc/subdivide(var/iteration,var/x,var/y,var/input_size) var/isize = input_size @@ -69,33 +73,33 @@ (x,y)----------(x+hsize,y)----------(x+isize,y) */ // Central edge values become average of corners. - map[get_map_cell(x+hsize,y+isize)] = round((\ - map[get_map_cell(x,y+isize)] + \ - map[get_map_cell(x+isize,y+isize)] \ + map[TRANSLATE_COORD(x+hsize,y+isize)] = round((\ + map[TRANSLATE_COORD(x,y+isize)] + \ + map[TRANSLATE_COORD(x+isize,y+isize)] \ )/2) - map[get_map_cell(x+hsize,y)] = round(( \ - map[get_map_cell(x,y)] + \ - map[get_map_cell(x+isize,y)] \ + map[TRANSLATE_COORD(x+hsize,y)] = round(( \ + map[TRANSLATE_COORD(x,y)] + \ + map[TRANSLATE_COORD(x+isize,y)] \ )/2) map[get_map_cell(x,y+hsize)] = round(( \ - map[get_map_cell(x,y+isize)] + \ - map[get_map_cell(x,y)] \ + map[TRANSLATE_COORD(x,y+isize)] + \ + map[TRANSLATE_COORD(x,y)] \ )/2) - map[get_map_cell(x+isize,y+hsize)] = round(( \ - map[get_map_cell(x+isize,y+isize)] + \ - map[get_map_cell(x+isize,y)] \ + map[TRANSLATE_COORD(x+isize,y+hsize)] = round(( \ + map[TRANSLATE_COORD(x+isize,y+isize)] + \ + map[TRANSLATE_COORD(x+isize,y)] \ )/2) // Centre value becomes the average of all other values + possible random variance. - var/current_cell = get_map_cell(x+hsize,y+hsize) + var/current_cell = TRANSLATE_COORD(x+hsize,y+hsize) map[current_cell] = round(( \ - map[get_map_cell(x+hsize,y+isize)] + \ - map[get_map_cell(x+hsize,y)] + \ - map[get_map_cell(x,y+hsize)] + \ - map[get_map_cell(x+isize,y)] \ + map[TRANSLATE_COORD(x+hsize,y+isize)] + \ + map[TRANSLATE_COORD(x+hsize,y)] + \ + map[TRANSLATE_COORD(x,y+hsize)] + \ + map[TRANSLATE_COORD(x+isize,y)] \ )/4) if(prob(random_variance_chance)) @@ -104,7 +108,8 @@ // Recurse until size is too small to subdivide. if(isize>3) - if(!priority_process) sleep(-1) + if(!priority_process) + CHECK_TICK iteration++ subdivide(iteration, x, y, hsize) subdivide(iteration, x+hsize, y, hsize) @@ -112,50 +117,48 @@ subdivide(iteration, x+hsize, y+hsize, hsize) /datum/random_map/noise/cleanup() - - for(var/i = 1;i<=smoothing_iterations;i++) + var/is_not_border_left + var/is_not_border_right + for(var/i = 1 to smoothing_iterations) var/list/next_map[limit_x*limit_y] - for(var/x = 1, x <= limit_x, x++) - for(var/y = 1, y <= limit_y, y++) - - var/current_cell = get_map_cell(x,y) + for(var/x = 1 to limit_x) + for(var/y = 1 to limit_y) + var/current_cell = TRANSLATE_COORD(x,y) next_map[current_cell] = map[current_cell] - var/val_count = 0 - var/total = 0 + var/val_count = 1 + var/total = map[current_cell] + + is_not_border_left = (x != 1) + is_not_border_right = (x != limit_x) + + // Center row. Center value's already been done above. + if (is_not_border_left) + total += map[TRANSLATE_COORD(x - 1, y)] + ++val_count + if (is_not_border_right) + total += map[TRANSLATE_COORD(x + 1, y)] + ++val_count + + if (y != 1) // top row + total += map[TRANSLATE_COORD(x, y - 1)] + ++val_count + if (is_not_border_left) + total += map[TRANSLATE_COORD(x - 1, y - 1)] + ++val_count + if (is_not_border_right) + total += map[TRANSLATE_COORD(x + 1, y - 1)] + ++val_count + + if (y != limit_y) // bottom row + total += map[TRANSLATE_COORD(x, y + 1)] + ++val_count + if (is_not_border_left) + total += map[TRANSLATE_COORD(x - 1, y + 1)] + ++val_count + if (is_not_border_right) + total += map[TRANSLATE_COORD(x + 1, y + 1)] + ++val_count - // Get the average neighboring value. - var/tmp_cell = get_map_cell(x+1,y+1) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x-1,y-1) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x+1,y-1) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x-1,y+1) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x-1,y) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x,y-1) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x+1,y) - if(tmp_cell) - total += map[tmp_cell] - val_count++ - tmp_cell = get_map_cell(x,y+1) - if(tmp_cell) - total += map[tmp_cell] - val_count++ total = round(total/val_count) if(abs(map[current_cell]-total) <= cell_smooth_amt) @@ -165,4 +168,33 @@ else if(map[current_cell] < total) map[current_cell]-=cell_smooth_amt map[current_cell] = max(0,min(cell_range,map[current_cell])) - map = next_map \ No newline at end of file + map = next_map + + if(smooth_single_tiles) + var/list/buddies = list() + for(var/x in 1 to limit_x - 1) + for(var/y in 1 to limit_y - 1) + var/mapcell = get_map_cell(x,y) + var/list/neighbors = get_neighbors(x, y) + buddies.Cut() + for(var/cell in neighbors) + if(noise2value(map[cell]) == noise2value(map[mapcell])) + buddies |= cell + if(!length(buddies)) + map[mapcell] = map[pick(neighbors)] + +/datum/random_map/noise/proc/get_neighbors(x, y, include_diagonals) + . = list() + if(!include_diagonals) + var/static/list/ortho_offsets = list(list(-1, 0), list(1, 0), list(0, 1), list(0,-1)) + for(var/list/offset in ortho_offsets) + var/tmp_cell = get_map_cell(x+offset[1],y+offset[2]) + if(tmp_cell) + . += tmp_cell + else + for(var/dx in -1 to 1) + for(var/dy in -1 to 1) + var/tmp_cell = get_map_cell(x+dx,y+dy) + if(tmp_cell) + . += tmp_cell + . -= get_map_cell(x,y) diff --git a/polaris.dme b/polaris.dme index a2aa7e433b..7b2ec209f7 100644 --- a/polaris.dme +++ b/polaris.dme @@ -107,6 +107,7 @@ #include "code\_helpers\global_lists.dm" #include "code\_helpers\icons.dm" #include "code\_helpers\logging.dm" +#include "code\_helpers\math.dm" #include "code\_helpers\matrices.dm" #include "code\_helpers\mobs.dm" #include "code\_helpers\names.dm"