mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-14 04:02:31 +00:00
Merge with dev.
This commit is contained in:
242
code/modules/random_map/mining_distribution.dm
Normal file
242
code/modules/random_map/mining_distribution.dm
Normal file
@@ -0,0 +1,242 @@
|
||||
#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
|
||||
|
||||
/*
|
||||
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 iterating on our end (recursive, with args).
|
||||
|
||||
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 = 0.8 // Threshold for deep metals, set in new as percentage of cell_range.
|
||||
var/rare_val = 0.7 // Threshold for rare metal, set in new as percentage of cell_range.
|
||||
var/cell_base // Set in New()
|
||||
var/initial_cell_range // Set in New()
|
||||
|
||||
/datum/random_map/ore/New()
|
||||
rare_val = cell_range * rare_val
|
||||
deep_val = cell_range * deep_val
|
||||
|
||||
initial_cell_range = cell_range/5
|
||||
cell_base = cell_range/2
|
||||
..()
|
||||
|
||||
/datum/random_map/ore/check_map_sanity()
|
||||
|
||||
var/rare_count = 0
|
||||
var/surface_count = 0
|
||||
var/deep_count = 0
|
||||
|
||||
// Increment map sanity counters.
|
||||
for(var/value in map)
|
||||
if(value < rare_val)
|
||||
surface_count++
|
||||
else if(value < deep_val)
|
||||
rare_count++
|
||||
else
|
||||
deep_count++
|
||||
// Sanity check.
|
||||
if(surface_count < MIN_SURFACE_COUNT)
|
||||
world << "<span class='danger'>Insufficient surface minerals. Rerolling...</span>"
|
||||
return 0
|
||||
else if(rare_count < MIN_RARE_COUNT)
|
||||
world << "<span class='danger'>Insufficient rare minerals. Rerolling...</span>"
|
||||
return 0
|
||||
else if(deep_count < MIN_DEEP_COUNT)
|
||||
world << "<span class='danger'>Insufficient deep minerals. Rerolling...</span>"
|
||||
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)] = 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,real_size)] = cell_base+rand(initial_cell_range)
|
||||
map[get_map_cell(real_size,real_size)] = cell_base+rand(initial_cell_range)
|
||||
map[get_map_cell(real_size,1)] = cell_base+rand(initial_cell_range)
|
||||
iterate(1,1,1,(real_size-1)) // Start the recursion here.
|
||||
|
||||
/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])
|
||||
if(map[current_cell] < rare_val)
|
||||
line += "S"
|
||||
else if(map[current_cell] < deep_val)
|
||||
line += "R"
|
||||
else
|
||||
line += "D"
|
||||
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 << "<span class='danger'>Iteration count exceeded, aborting.</span>"
|
||||
return
|
||||
|
||||
var/isize = input_size
|
||||
var/hsize = round(input_size/2)
|
||||
|
||||
/*
|
||||
(x,y+isize)----(x+hsize,y+isize)----(x+size,y+isize)
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
(x,y+hsize)----(x+hsize,y+hsize)----(x+isize,y)
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
(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)] \
|
||||
)/2)
|
||||
|
||||
map[get_map_cell(x+hsize,y)] = round(( \
|
||||
map[get_map_cell(x,y)] + \
|
||||
map[get_map_cell(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)] \
|
||||
)/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)] \
|
||||
)/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+isize)]+map[get_map_cell(x+hsize,y)]+map[get_map_cell(x,y+hsize)]+map[get_map_cell(x+isize,y)])/4)
|
||||
|
||||
if(prob(random_variance_chance))
|
||||
map[current_cell] *= (rand(1,2)==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(isize>3)
|
||||
sleep(-1)
|
||||
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_map()
|
||||
for(var/x = 0, x < real_size, x++)
|
||||
if((origin_x + x) > limit_x) continue
|
||||
for(var/y = 0, y < real_size, y++)
|
||||
if((origin_y + y) > limit_y) continue
|
||||
sleep(-1)
|
||||
apply_to_turf(x,y)
|
||||
|
||||
/datum/random_map/ore/apply_to_turf(var/x,var/y)
|
||||
|
||||
var/tx = origin_x+((x-1)*chunk_size)
|
||||
var/ty = origin_y+((y-1)*chunk_size)
|
||||
|
||||
for(var/i=0,i<chunk_size,i++)
|
||||
if(ty+i>limit_y)
|
||||
continue
|
||||
for(var/j=0,j<chunk_size,j++)
|
||||
if(tx+j>limit_x)
|
||||
continue
|
||||
|
||||
var/turf/T = locate(tx+j, ty+i, origin_z)
|
||||
if(!T || !T.has_resources)
|
||||
continue
|
||||
|
||||
sleep(-1)
|
||||
|
||||
T.resources = list()
|
||||
T.resources["silicates"] = rand(3,5)
|
||||
T.resources["carbonaceous rock"] = rand(3,5)
|
||||
|
||||
var/current_cell = map[get_map_cell(x,y)]
|
||||
if(current_cell < rare_val) // Surface metals.
|
||||
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
|
||||
else if(current_cell < deep_val) // Rare metals.
|
||||
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
|
||||
else // Deep metals.
|
||||
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
|
||||
|
||||
#undef MIN_SURFACE_COUNT
|
||||
#undef MIN_RARE_COUNT
|
||||
#undef MIN_DEEP_COUNT
|
||||
#undef RESOURCE_HIGH_MAX
|
||||
#undef RESOURCE_HIGH_MIN
|
||||
#undef RESOURCE_MID_MAX
|
||||
#undef RESOURCE_MID_MIN
|
||||
#undef RESOURCE_LOW_MAX
|
||||
#undef RESOURCE_LOW_MIN
|
||||
173
code/modules/random_map/random_map.dm
Normal file
173
code/modules/random_map/random_map.dm
Normal file
@@ -0,0 +1,173 @@
|
||||
#define ORE_COUNT 1000
|
||||
/*
|
||||
This module is used to generate the debris fields/distribution maps/procedural stations.
|
||||
*/
|
||||
|
||||
var/global/list/random_maps = list()
|
||||
|
||||
/datum/random_map
|
||||
var/descriptor = "asteroid" // Display name.
|
||||
var/real_size = 246 // Size of each edge (must be square :().
|
||||
var/cell_range = 2 // Random range for initial cells.
|
||||
var/iterations = 5 // Number of times to apply the automata rule.
|
||||
var/max_attempts = 5 // Fail if a sane map isn't generated by this point.
|
||||
var/raw_map_size // Used for creating new maps each iteration. Value must be real_size^2
|
||||
var/list/map = list() // Actual map.
|
||||
var/origin_x = 1 // Origin point, left.
|
||||
var/origin_y = 1 // Origin point, bottom.
|
||||
var/origin_z = 1 // Target Z-level.
|
||||
var/limit_x = 256 // Maximum x bound.
|
||||
var/limit_y = 256 // Maximum y bound.
|
||||
var/iterate_before_fail = 120 // Infinite loop safeguard.
|
||||
|
||||
/datum/random_map/proc/get_map_cell(var/x,var/y)
|
||||
return ((y-1)*real_size)+x
|
||||
|
||||
/datum/random_map/proc/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))
|
||||
if(map[current_cell] == 2)
|
||||
line += "#"
|
||||
else
|
||||
line += "."
|
||||
user << line
|
||||
|
||||
/datum/random_map/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly)
|
||||
|
||||
// Store this for debugging.
|
||||
random_maps |= src
|
||||
|
||||
// Initialize map.
|
||||
set_map_size()
|
||||
|
||||
// Get origins for applying the map later.
|
||||
if(tx) origin_x = tx
|
||||
if(ty) origin_y = ty
|
||||
if(tz) origin_z = tz
|
||||
if(tlx) limit_x = tlx
|
||||
if(tly) limit_y = tly
|
||||
|
||||
// testing needed to see how reliable this is (asynchronous calls, called during worldgen), DM ref is not optimistic
|
||||
if(seed) rand_seed(seed)
|
||||
|
||||
var/start_time = world.timeofday
|
||||
world << "<span class='danger'>Generating [descriptor].</span>"
|
||||
for(var/i = 0;i<max_attempts;i++)
|
||||
if(generate())
|
||||
world << "<span class='danger'>[capitalize(descriptor)] generation completed in [round(0.1*(world.timeofday-start_time),0.1)] seconds.</span>"
|
||||
return
|
||||
world << "<span class='danger'>[capitalize(descriptor)] generation failed in [round(0.1*(world.timeofday-start_time),0.1)] seconds: could not produce sane map.</span>"
|
||||
|
||||
/datum/random_map/proc/within_bounds(var/val)
|
||||
return (val>0) && (val<=raw_map_size)
|
||||
|
||||
/datum/random_map/proc/set_map_size(var/raw_size)
|
||||
if(!raw_size)
|
||||
raw_size = real_size * real_size
|
||||
raw_map_size = raw_size
|
||||
map.len = raw_map_size
|
||||
|
||||
/datum/random_map/proc/seed_map()
|
||||
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(prob(55))
|
||||
map[current_cell] = 2
|
||||
else
|
||||
map[current_cell] = 1
|
||||
|
||||
/datum/random_map/proc/clear_map()
|
||||
for(var/x = 1, x <= real_size, x++)
|
||||
for(var/y = 1, y <= real_size, y++)
|
||||
map[get_map_cell(x,y)] = 0
|
||||
|
||||
/datum/random_map/proc/generate()
|
||||
seed_map()
|
||||
for(var/i=1;i<=iterations;i++)
|
||||
iterate(i)
|
||||
if(check_map_sanity())
|
||||
cleanup()
|
||||
apply_to_map()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/random_map/proc/iterate(var/iteration)
|
||||
var/list/next_map[raw_map_size]
|
||||
for(var/x = 1, x <= real_size, x++)
|
||||
for(var/y = 1, y <= real_size, y++)
|
||||
var/current_cell = get_map_cell(x,y)
|
||||
// Sanity check.
|
||||
if(!within_bounds(current_cell))
|
||||
continue
|
||||
// Copy over original value.
|
||||
next_map[current_cell] = map[current_cell]
|
||||
// Check all neighbors.
|
||||
var/count = 0
|
||||
for(var/cell in list(current_cell,get_map_cell(x+1,y+1),get_map_cell(x-1,y-1),get_map_cell(x+1,y-1),get_map_cell(x-1,y+1),get_map_cell(x-1,y),get_map_cell(x,y-1),get_map_cell(x+1,y),get_map_cell(x,y+1)))
|
||||
if(within_bounds(cell) && map[cell] == 2)
|
||||
count++
|
||||
if(count>=5)
|
||||
next_map[current_cell] = 2 // becomes a wall
|
||||
else
|
||||
next_map[current_cell] = 1 // becomes a floor
|
||||
map = next_map
|
||||
|
||||
/datum/random_map/proc/check_map_sanity()
|
||||
return 1
|
||||
|
||||
/datum/random_map/proc/apply_to_map()
|
||||
for(var/x = 0, x < real_size, x++)
|
||||
if((origin_x + x) > limit_x) continue
|
||||
for(var/y = 0, y < real_size, y++)
|
||||
if((origin_y + y) > limit_y) continue
|
||||
sleep(-1)
|
||||
apply_to_turf(origin_x+x,origin_y+y)
|
||||
|
||||
/datum/random_map/proc/apply_to_turf(var/x,var/y)
|
||||
var/current_cell = get_map_cell(x,y)
|
||||
if(!within_bounds(current_cell))
|
||||
return
|
||||
var/turf/T = locate(x,y,origin_z)
|
||||
if(!T || !istype(T,/turf/unsimulated/mask))
|
||||
return
|
||||
switch(map[current_cell])
|
||||
if(1)
|
||||
T.ChangeTurf(/turf/simulated/floor/plating/airless/asteroid)
|
||||
if(2)
|
||||
T.ChangeTurf(/turf/simulated/mineral)
|
||||
if(3)
|
||||
T.ChangeTurf(/turf/simulated/mineral/random)
|
||||
if(4)
|
||||
T.ChangeTurf(/turf/simulated/mineral/random/high_chance)
|
||||
|
||||
/datum/random_map/proc/cleanup()
|
||||
|
||||
sleep(-1)
|
||||
// Create ore.
|
||||
var/ore_count = ORE_COUNT
|
||||
while(ore_count)
|
||||
var/check_cell = get_map_cell(rand(1,real_size),rand(1,real_size))
|
||||
if(!(within_bounds(check_cell)) || map[check_cell] != 2)
|
||||
continue
|
||||
if(prob(25))
|
||||
map[check_cell] = 4
|
||||
else
|
||||
map[check_cell] = 3
|
||||
ore_count--
|
||||
|
||||
sleep(-1)
|
||||
|
||||
// Place random asteroid rooms.
|
||||
var/rooms_placed = 0
|
||||
for(var/i = 0, i < max_secret_rooms, i++)
|
||||
if(make_mining_asteroid_secret())
|
||||
rooms_placed++
|
||||
world << "<span class='danger'>Placed [rooms_placed] secrets.</span>"
|
||||
return 1
|
||||
Reference in New Issue
Block a user