Refactored random map generator system and added several terrain generators.

Created a global list to track base turfs for explosions/shuttle moves.
Remaps the asteroid to be a moonlet. Tidies up some references to 'asteroid', removes moonbase from the accessible z level list.
This commit is contained in:
Zuhayr
2015-06-03 04:36:19 +09:30
parent d4327658ab
commit ebe62cefd8
47 changed files with 1453 additions and 1175 deletions

View File

@@ -167,6 +167,9 @@ var/list/admin_verbs_debug = list(
/client/proc/restart_controller,
/client/proc/print_random_map,
/client/proc/create_random_map,
/client/proc/apply_random_map,
/client/proc/overlay_random_map,
/client/proc/delete_random_map,
/client/proc/show_plant_genes,
/client/proc/enable_debug_verbs,
/client/proc/callproc,

View File

@@ -84,7 +84,7 @@
//Dig out the tasty ores.
if(resource_field.len)
var/turf/harvesting = pick(resource_field)
var/turf/simulated/harvesting = pick(resource_field)
while(resource_field.len && !harvesting.resources)
harvesting.has_resources = 0
@@ -253,7 +253,7 @@
var/tx = T.x - 2
var/ty = T.y - 2
var/turf/mine_turf
var/turf/simulated/mine_turf
for(var/iy = 0,iy < 5, iy++)
for(var/ix = 0, ix < 5, ix++)
mine_turf = locate(tx + ix, ty + iy, T.z)

View File

@@ -20,7 +20,7 @@
"exotic matter" = 0
)
for(var/turf/T in range(2, get_turf(user)))
for(var/turf/simulated/T in range(2, get_turf(user)))
if(!T.has_resources)
continue

View File

@@ -1,5 +1,8 @@
/**********************Mineral deposits**************************/
/turf/unsimulated/mineral
name = "impassable rock"
icon = 'icons/turf/walls.dmi'
icon_state = "rock-dark"
/turf/simulated/mineral //wall piece
name = "Rock"
@@ -11,6 +14,7 @@
density = 1
blocks_air = 1
temperature = T0C
var/mined_turf = /turf/simulated/floor/plating/airless/asteroid
var/ore/mineral
var/mined_ore = 0
var/last_act = 0
@@ -28,21 +32,20 @@
has_resources = 1
/turf/simulated/mineral/New()
spawn(0)
MineralSpread()
spawn(2)
var/list/step_overlays = list("s" = NORTH, "n" = SOUTH, "w" = EAST, "e" = WEST)
for(var/direction in step_overlays)
var/turf/turf_to_check = get_step(src,step_overlays[direction])
updateMineralOverlays(1)
if(istype(turf_to_check,/turf/simulated/floor/plating/airless/asteroid))
var/turf/simulated/floor/plating/airless/asteroid/T = turf_to_check
T.updateMineralOverlays()
else if(istype(turf_to_check,/turf/space) || istype(turf_to_check,/turf/simulated/floor))
turf_to_check.overlays += image('icons/turf/walls.dmi', "rock_side_[direction]")
/turf/simulated/mineral/proc/updateMineralOverlays(var/update_neighbors)
var/list/step_overlays = list("s" = NORTH, "n" = SOUTH, "w" = EAST, "e" = WEST)
for(var/direction in step_overlays)
var/turf/turf_to_check = get_step(src,step_overlays[direction])
if(update_neighbors && istype(turf_to_check,/turf/simulated/floor/plating/airless/asteroid))
var/turf/simulated/floor/plating/airless/asteroid/T = turf_to_check
T.updateMineralOverlays()
else if(istype(turf_to_check,/turf/space) || istype(turf_to_check,/turf/simulated/floor))
turf_to_check.overlays += image('icons/turf/walls.dmi', "rock_side_[direction]")
/turf/simulated/mineral/ex_act(severity)
switch(severity)
@@ -280,8 +283,7 @@
//Add some rubble, you did just clear out a big chunk of rock.
var/turf/simulated/floor/plating/airless/asteroid/N = ChangeTurf(/turf/simulated/floor/plating/airless/asteroid)
N.overlay_detail = "asteroid[rand(0,9)]"
var/turf/simulated/floor/plating/airless/asteroid/N = ChangeTurf(mined_turf)
// Kill and update the space overlays around us.
for(var/direction in step_overlays)
@@ -292,13 +294,9 @@
if(istype(get_step(T, step_overlays[next_direction]),/turf/simulated/mineral))
T.overlays += image('icons/turf/walls.dmi', "rock_side_[next_direction]")
// Update the
N.updateMineralOverlays(1)
if(rand(1,500) == 1)
visible_message("<span class='notice'>An old dusty crate was buried within!</span>")
new /obj/structure/closet/crate/secure/loot(src)
if(istype(N))
N.overlay_detail = "asteroid[rand(0,9)]"
N.updateMineralOverlays(1)
/turf/simulated/mineral/proc/excavate_find(var/prob_clean = 0, var/datum/find/F)
//with skill and luck, players can cleanly extract finds
@@ -391,7 +389,7 @@
/turf/simulated/floor/plating/airless/asteroid //floor piece
name = "asteroid"
name = "sand"
icon = 'icons/turf/floors.dmi'
icon_state = "asteroid"
oxygen = 0

View File

@@ -18,12 +18,12 @@
/turf/simulated/floor/engine/ex_act(severity)
switch(severity)
if(1.0)
ChangeTurf(/turf/space)
ChangeTurf(get_base_turf(src.z))
qdel(src)
return
if(2.0)
if (prob(50))
ChangeTurf(/turf/space)
ChangeTurf(get_base_turf(src.z))
qdel(src)
return
else
@@ -31,7 +31,7 @@
/turf/simulated/floor/engine/blob_act()
if (prob(25))
ChangeTurf(/turf/space)
ChangeTurf(get_base_turf(src.z))
qdel(src)
return
return

View File

@@ -107,7 +107,7 @@
continue
if(O.invisibility == 101)
O.singularity_act(src, current_size)
ChangeTurf(/turf/space)
ChangeTurf(get_base_turf(src.z))
return 2
/turf/simulated/wall/singularity_pull(S, current_size)

View File

@@ -0,0 +1,22 @@
/*
This module is used to generate the debris fields/distribution maps/procedural stations.
*/
#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 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

View File

@@ -0,0 +1,65 @@
/datum/random_map/automata
descriptor = "generic caves"
initial_wall_cell = 55
var/iterations = 0 // Number of times to apply the automata rule.
var/cell_live_value = WALL_CHAR // Cell is alive if it has this value.
var/cell_dead_value = FLOOR_CHAR // As above for death.
var/cell_threshold = 5 // Cell becomes alive with this many live neighbors.
// Automata-specific procs and processing.
/datum/random_map/automata/generate_map()
for(var/i=1;i<=iterations;i++)
iterate(i)
/datum/random_map/automata/get_additional_spawns(var/value, var/turf/T)
return
/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
// 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++
if(count >= cell_threshold)
revive_cell(current_cell, next_map, (iteration == iterations))
else
kill_cell(current_cell, next_map, (iteration == iterations))
map = 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)
/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
/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

View File

@@ -0,0 +1,52 @@
/datum/random_map/automata/cave_system
iterations = 5
descriptor = "moon caves"
wall_type = /turf/simulated/mineral
floor_type = /turf/simulated/floor/plating/airless/asteroid
target_turf_type = /turf/unsimulated/mask
var/mineral_sparse = /turf/simulated/mineral/random
var/mineral_rich = /turf/simulated/mineral/random/high_chance
var/list/ore_turfs = list()
/datum/random_map/automata/cave_system/get_appropriate_path(var/value)
switch(value)
if(DOOR_CHAR)
return mineral_sparse
if(EMPTY_CHAR)
return mineral_rich
if(FLOOR_CHAR)
return floor_type
if(WALL_CHAR)
return wall_type
/datum/random_map/automata/cave_system/get_map_char(var/value)
switch(value)
if(DOOR_CHAR)
return "x"
if(EMPTY_CHAR)
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/ore_count = round(map.len/20)
while((ore_count>0) && (ore_turfs.len>0))
if(!priority_process) sleep(-1)
var/check_cell = pick(ore_turfs)
ore_turfs -= check_cell
if(prob(75))
map[check_cell] = DOOR_CHAR // Mineral block
else
map[check_cell] = EMPTY_CHAR // Rare mineral block.
ore_count--
return 1

View File

@@ -0,0 +1,55 @@
/datum/random_map/building
descriptor = "generic room"
limit_x = 7
limit_y = 7
/datum/random_map/building/generate_map()
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
var/current_cell = get_map_cell(x,y)
if(!within_bounds(current_cell))
continue
if(x == 1 || y == 1 || x == limit_x || y == limit_y)
map[current_cell] = WALL_CHAR
else
map[current_cell] = FLOOR_CHAR
/datum/random_map/building/handle_post_overlay_on(var/datum/random_map/target_map, var/tx, var/ty)
var/list/possible_doors
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
var/current_cell = get_map_cell(x,y)
if(!within_bounds(current_cell))
continue
if(!(x == 1 || y == 1 || x == limit_x || y == limit_y))
continue
if(tx+x > target_map.limit_x)
continue
if(ty+y > target_map.limit_y)
continue
var/place_door
// #.# ... .## ##.
// #X# #X# .X. .X. == place a door
// ... # # .## ##.
// (tx+x)-1,(ty+y-1) (tx+x),(ty+y)-1 (tx+x)+1,(ty+y)-1
// (tx+x)-1,(ty+y) (tx+x),(ty+y) (tx+x)+1,(ty+y)
// (tx+x)-1,(ty+y+1) (tx+x),(ty+y)+1 (tx+x)+1,(ty+y)+1
if(place_door)
possible_doors |= target_map.get_map_cell(tx+x,ty+y)
if(possible_doors.len)
// Place at least one door.
var/placing_door = pick(possible_doors)
possible_doors -= placing_door
target_map.map[placing_door] = DOOR_CHAR
// Keep placing doors until we get bored or lose interest.
while(possible_doors && !prob(30))
placing_door = pick(possible_doors)
possible_doors -= placing_door
target_map.map[placing_door] = DOOR_CHAR
return

View File

@@ -0,0 +1,65 @@
/datum/random_map/maze
descriptor = "maze"
initial_wall_cell = 100
var/list/checked_coord_cache = list()
var/list/openlist = list()
var/list/closedlist = list()
/datum/random_map/maze/set_map_size()
// Map has to be odd so that there are walls on all sides.
if(limit_x%2==0) limit_x++
if(limit_y%2==0) limit_y++
..()
/datum/random_map/maze/generate_map()
// Grab a random point on the map to begin the maze cutting at.
var/start_x = rand(1,limit_x-2)
var/start_y = rand(1,limit_y-2)
if(start_x%2!=0) start_x++
if(start_y%2!=0) start_y++
// Create the origin cell to start us off.
openlist += new /datum/maze_cell(start_x,start_y)
while(openlist.len)
// Grab a maze point to use and remove it from the open list.
var/datum/maze_cell/next = pick(openlist)
openlist -= next
if(!isnull(closedlist[next.name]))
continue
// Preliminary marking-off...
closedlist[next.name] = next
map[get_map_cell(next.x,next.y)] = FLOOR_CHAR
// Apply the values required and fill gap between this cell and origin point.
if(next.ox && next.oy)
if(next.ox < next.x)
map[get_map_cell(next.x-1,next.y)] = FLOOR_CHAR
else if(next.ox == next.x)
if(next.oy < next.y)
map[get_map_cell(next.x,next.y-1)] = FLOOR_CHAR
else
map[get_map_cell(next.x,next.y+1)] = FLOOR_CHAR
else
map[get_map_cell(next.x+1,next.y)] = FLOOR_CHAR
// Grab valid neighbors for use in the open list!
add_to_openlist(next.x,next.y+2,next.x,next.y)
add_to_openlist(next.x-2,next.y,next.x,next.y)
add_to_openlist(next.x+2,next.y,next.x,next.y)
add_to_openlist(next.x,next.y-2,next.x,next.y)
// Cleanup. Map stays in memory for display proc.
checked_coord_cache.Cut()
openlist.Cut()
closedlist.Cut()
/datum/random_map/maze/proc/add_to_openlist(var/tx, var/ty, var/nx, var/ny)
if(tx < 1 || ty < 1 || tx > limit_x || ty > limit_y || !isnull(checked_coord_cache["[tx]-[ty]"]))
return 0
checked_coord_cache["[tx]-[ty]"] = 1
map[get_map_cell(tx,ty)] = DOOR_CHAR
var/datum/maze_cell/new_cell = new(tx,ty,nx,ny)
openlist |= new_cell

View File

@@ -0,0 +1,18 @@
var/maze_cell_count = 0
/datum/maze_cell
var/name
var/uid
var/x
var/y
var/ox
var/oy
/datum/maze_cell/New(var/nx,var/ny,var/nox,var/noy)
maze_cell_count++
uid = maze_cell_count
name = "cell #[uid]"
x = nx
y = ny
ox = nox
oy = noy

View File

@@ -1,242 +0,0 @@
#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)
admin_notice("<span class='danger'>Insufficient surface minerals. Rerolling...</span>", R_DEBUG)
return 0
else if(rare_count < MIN_RARE_COUNT)
admin_notice("<span class='danger'>Insufficient rare minerals. Rerolling...</span>", R_DEBUG)
return 0
else if(deep_count < MIN_DEEP_COUNT)
admin_notice("<span class='danger'>Insufficient deep minerals. Rerolling...</span>", R_DEBUG)
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)
admin_notice("<span class='danger'>Iteration count exceeded, aborting.</span>", R_DEBUG)
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

View File

@@ -0,0 +1,40 @@
/datum/random_map/noise/desert
descriptor = "desert"
smoothing_iterations = 3
/datum/random_map/noise/desert/replace_space
descriptor = "desert (replacement)"
target_turf_type = /turf/space
/datum/random_map/noise/desert/get_map_char(var/value)
return "<font color='#[value][value][value][value][value][value]'>[pick(list(",",".","'","`"))]</font>"
/datum/random_map/noise/desert/get_appropriate_path(var/value)
var/val = min(9,max(0,round((value/cell_range)*10)))
if(isnull(val)) val = 0
switch(val)
if(0 to 1)
return /turf/simulated/floor/beach/water
else
return /turf/simulated/floor/beach/sand/desert
/datum/random_map/noise/desert/get_additional_spawns(var/value, var/turf/T)
var/val = min(9,max(0,round((value/cell_range)*10)))
if(isnull(val)) val = 0
switch(val)
if(2 to 3)
if(prob(60))
var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass)
new grass_path(T)
if(prob(5))
var/mob_type = pick(list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse))
new mob_type(T)
if(5 to 6)
if(prob(20))
var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass)
new grass_path(T)
if(7 to 9)
if(prob(60))
new /obj/structure/flora/bush(T)
else if(prob(20))
new /obj/structure/flora/tree/dead(T)

View File

@@ -0,0 +1,44 @@
// This is basically filler at this point. Subsidence and all kinds of fun
// hazards will be included when it is done.
/datum/random_map/noise/volcanism
descriptor = "volcanism"
smoothing_iterations = 6
target_turf_type = /turf/simulated
// Get rid of those dumb little single-tile volcanic areas.
/datum/random_map/noise/volcanism/cleanup()
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
var/current_cell = get_map_cell(x,y)
if(map[current_cell] < 178)
continue
var/count
var/tmp_cell = get_map_cell(x+1,y+1)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x-1,y-1)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x+1,y-1)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x-1,y+1)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x-1,y)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x,y-1)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x+1,y)
if(tmp_cell && map[tmp_cell] >= 178) count++
tmp_cell = get_map_cell(x,y+1)
if(tmp_cell && map[tmp_cell] >= 178) count++
if(!count)
map[current_cell] = 177
/datum/random_map/noise/volcanism/get_appropriate_path(var/value)
return
/datum/random_map/noise/volcanism/get_additional_spawns(var/value, var/turf/T)
if(value>=178)
if(istype(T,/turf/simulated/floor/plating/airless/asteroid))
T.ChangeTurf(/turf/simulated/floor/airless/lava)
else if(istype(T,/turf/simulated/mineral))
var/turf/simulated/mineral/M = T
M.mined_turf = /turf/simulated/floor/airless/lava

View File

@@ -0,0 +1,168 @@
// NOTE: Maps generated with this datum as the base are not DIRECTLY compatible with maps generated from
// the automata, building or maze datums, as the noise generator uses 0-255 instead of WALL_CHAR/FLOOR_CHAR.
// TODO: Consider writing a conversion proc for noise-to-regular maps.
/datum/random_map/noise
descriptor = "distribution map"
var/cell_range = 255 // These values are used to seed ore values rather than to determine a turf type.
var/cell_smooth_amt = 5
var/random_variance_chance = 25 // % chance of applying random_element.
var/random_element = 0.5 // Determines the variance when smoothing out cell values.
var/cell_base // Set in New()
var/initial_cell_range // Set in New()
var/smoothing_iterations = 0
/datum/random_map/noise/New()
initial_cell_range = cell_range/5
cell_base = cell_range/2
..()
/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
// Sides must be identical lengths.
if(limit_x > limit_y)
limit_y = limit_x
else if(limit_y > limit_x)
limit_x = limit_y
..()
// Diamond-square algorithm.
/datum/random_map/noise/seed_map()
// 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
// 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)
/datum/random_map/noise/generate_map()
// Begin recursion.
subdivide(1,1,1,(limit_y-1))
/datum/random_map/noise/get_map_char(var/value)
var/val = min(9,max(0,round((value/cell_range)*10)))
if(isnull(val)) val = 0
return "[val]"
/datum/random_map/noise/proc/subdivide(var/iteration,var/x,var/y,var/input_size)
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)
if(!priority_process) sleep(-1)
iteration++
subdivide(iteration, x, y, hsize)
subdivide(iteration, x+hsize, y, hsize)
subdivide(iteration, x, y+hsize, hsize)
subdivide(iteration, x+hsize, y+hsize, hsize)
/datum/random_map/noise/cleanup()
for(var/i = 1;i<=smoothing_iterations;i++)
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/val_count = 0
var/total = 0
// 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)
map[current_cell] = total
else if(map[current_cell] < total)
map[current_cell]+=cell_smooth_amt
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

View File

@@ -0,0 +1,90 @@
/datum/random_map/noise/ore
descriptor = "ore distribution map"
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/chunk_size = 4 // Size each cell represents on map
/datum/random_map/noise/ore/New()
rare_val = cell_range * rare_val
deep_val = cell_range * deep_val
..()
/datum/random_map/noise/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)
admin_notice("<span class='danger'>Insufficient surface minerals. Rerolling...</span>", R_DEBUG)
return 0
else if(rare_count < MIN_RARE_COUNT)
admin_notice("<span class='danger'>Insufficient rare minerals. Rerolling...</span>", R_DEBUG)
return 0
else if(deep_count < MIN_DEEP_COUNT)
admin_notice("<span class='danger'>Insufficient deep minerals. Rerolling...</span>", R_DEBUG)
return 0
else
return 1
/datum/random_map/noise/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++)
for(var/j=0,j<chunk_size,j++)
var/turf/simulated/T = locate(tx+j, ty+i, origin_z)
if(!istype(T) || !T.has_resources)
continue
if(!priority_process) 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/noise/ore/get_map_char(var/value)
if(value < rare_val)
return "S"
else if(value < deep_val)
return "R"
else
return "D"

View File

@@ -0,0 +1,72 @@
/datum/random_map/noise/tundra
descriptor = "tundra"
smoothing_iterations = 1
/datum/random_map/noise/tundra/replace_space
descriptor = "tundra (replacement)"
target_turf_type = /turf/space
/datum/random_map/noise/tundra/get_map_char(var/value)
var/val = min(9,max(0,round((value/cell_range)*10)))
if(isnull(val)) val = 0
switch(val)
if(0)
return "<font color='#000099'>~</font>"
if(1)
return "<font color='#0000BB'>~</font>"
if(2)
return "<font color='#0000DD'>~</font>"
if(3)
return "<font color='#66AA00'>[pick(list(".",","))]</font>"
if(4)
return "<font color='#77CC00'>[pick(list(".",","))]</font>"
if(5)
return "<font color='#88DD00'>[pick(list(".",","))]</font>"
if(6)
return "<font color='#99EE00'>[pick(list(".",","))]</font>"
if(7)
return "<font color='#00BB00'>[pick(list("T","t"))]</font>"
if(8)
return "<font color='#00DD00'>[pick(list("T","t"))]</font>"
if(9)
return "<font color='#00FF00'>[pick(list("T","t"))]</font>"
/datum/random_map/noise/tundra/get_appropriate_path(var/value)
var/val = min(9,max(0,round((value/cell_range)*10)))
if(isnull(val)) val = 0
switch(val)
if(0 to 4)
return /turf/simulated/floor/beach/water/ocean
else
return /turf/simulated/floor/snow
/datum/random_map/noise/tundra/get_additional_spawns(var/value, var/turf/T)
var/val = min(9,max(0,round((value/cell_range)*10)))
if(isnull(val)) val = 0
switch(val)
if(2)
if(prob(5))
new /mob/living/simple_animal/crab(T)
if(6)
if(prob(60))
var/grass_path = pick(typesof(/obj/structure/flora/grass)-/obj/structure/flora/grass)
new grass_path(T)
if(prob(5))
var/mob_type = pick(list(/mob/living/simple_animal/lizard, /mob/living/simple_animal/mouse))
new mob_type(T)
if(7)
if(prob(60))
new /obj/structure/flora/bush(T)
else if(prob(30))
new /obj/structure/flora/tree/pine(T)
else if(prob(20))
new /obj/structure/flora/tree/dead(T)
if(8)
if(prob(70))
new /obj/structure/flora/tree/pine(T)
else if(prob(30))
new /obj/structure/flora/tree/dead(T)
else
new /obj/structure/flora/bush(T)
if(9)
new /obj/structure/flora/tree/pine(T)

View File

@@ -1,173 +1,206 @@
#define ORE_COUNT 1000
/*
This module is used to generate the debris fields/distribution maps/procedural stations.
*/
// Generates cave systems for the asteroid, and places ore tiles.
var/global/list/random_maps = list()
var/global/list/map_count = 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.
// Strings.
var/name // Set in New()
var/descriptor = "random map" // Display name.
// Locator/value vars.
var/initial_wall_cell = 100 // % Chance that a cell will be seeded as a wall.
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.
var/limit_x = 128 // Default x size.
var/limit_y = 128 // Default y size.
var/auto_apply = 1
// Turf paths.
var/wall_type = /turf/simulated/wall
var/floor_type = /turf/simulated/floor
var/target_turf_type
// Storage for the final iteration of the map.
var/list/map = list() // Actual map.
// If set, all sleep(-1) calls will be skipped.
// Test to see if rand_seed() can be used reliably.
var/priority_process
/datum/random_map/New(var/seed, var/tx, var/ty, var/tz, var/tlx, var/tly, var/do_not_apply, var/do_not_announce)
// Store this for debugging.
if(!map_count[descriptor])
map_count[descriptor] = 1
else
map_count[descriptor]++
name = "[descriptor] #[map_count[descriptor]]"
random_maps[name] = src
// Get origins for applying the map later.
origin_x = (!isnull(tx) ? tx : 1)
origin_y = (!isnull(ty) ? ty : 1)
origin_z = (!isnull(tz) ? tz : 1)
if(tlx) limit_x = tlx
if(tly) limit_y = tly
if(do_not_apply)
auto_apply = null
// Initialize map.
set_map_size()
var/start_time = world.timeofday
if(!do_not_announce) admin_notice("<span class='danger'>Generating [name].</span>", R_DEBUG)
sleep(-1)
// Testing needed to see how reliable this is (asynchronous calls, called during worldgen), DM ref is not optimistic
if(seed)
rand_seed(seed)
priority_process = 1
for(var/i = 0;i<max_attempts;i++)
if(generate())
if(!do_not_announce) admin_notice("<span class='danger'>[capitalize(name)] generation completed in [round(0.1*(world.timeofday-start_time),0.1)] seconds.</span>", R_DEBUG)
return
if(!do_not_announce) admin_notice("<span class='danger'>[capitalize(name)] failed to generate ([round(0.1*(world.timeofday-start_time),0.1)] seconds): could not produce sane map.</span>", R_DEBUG)
/datum/random_map/proc/get_map_cell(var/x,var/y)
return ((y-1)*real_size)+x
var/cell = ((y-1)*limit_x)+x
if((cell < 1) || (cell > map.len))
return null
else
return cell
/datum/random_map/proc/get_map_char(var/value)
switch(value)
if(WALL_CHAR)
return "#"
if(FLOOR_CHAR)
return "."
if(DOOR_CHAR)
return "D"
if(ROOM_TEMP_CHAR)
return "+"
if(MONSTER_CHAR)
return "M"
if(ARTIFACT_TURF_CHAR)
return "_"
if(ARTIFACT_CHAR)
return "A"
else
return " "
/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/dat = "<code>+------+<br>"
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, 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
admin_notice("<span class='danger'>Generating [descriptor].</span>", R_DEBUG)
for(var/i = 0;i<max_attempts;i++)
if(generate())
admin_notice("<span class='danger'>[capitalize(descriptor)] generation completed in [round(0.1*(world.timeofday-start_time),0.1)] seconds.</span>", R_DEBUG)
return
admin_notice("<span class='danger'>[capitalize(descriptor)] generation failed in [round(0.1*(world.timeofday-start_time),0.1)] seconds: could not produce sane map.</span>", R_DEBUG)
dat += get_map_char(map[current_cell])
dat += "<br>"
user << "[dat]+------+</code>"
/datum/random_map/proc/within_bounds(var/val)
return (val>0) && (val<=raw_map_size)
if(!islist(map))
set_map_size()
return (val>0) && (val<=map.len)
/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/set_map_size()
map = list()
map.len = limit_x * limit_y
/datum/random_map/proc/seed_map()
for(var/x = 1, x <= real_size, x++)
for(var/y = 1, y <= real_size, 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)
if(prob(55))
map[current_cell] = 2
if(prob(initial_wall_cell))
map[current_cell] = WALL_CHAR
else
map[current_cell] = 1
map[current_cell] = FLOOR_CHAR
/datum/random_map/proc/clear_map()
for(var/x = 1, x <= real_size, x++)
for(var/y = 1, y <= real_size, y++)
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
map[get_map_cell(x,y)] = 0
/datum/random_map/proc/generate()
seed_map()
for(var/i=1;i<=iterations;i++)
iterate(i)
generate_map()
if(check_map_sanity())
cleanup()
apply_to_map()
if(auto_apply)
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
// Unused for basic map.
/datum/random_map/proc/generate_map()
return 1
/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_map(var/tx, var/ty, var/tz)
if(!tx) tx = isnull(origin_x) ? 1 : origin_x
if(!ty) ty = isnull(origin_y) ? 1 : origin_y
if(!tz) tz = isnull(origin_z) ? 1 : origin_z
/datum/random_map/proc/apply_to_turf(var/x,var/y)
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
if(!priority_process) sleep(-1)
apply_to_turf((tx-1)+x,(ty-1)+y,tz)
/datum/random_map/proc/apply_to_turf(var/x,var/y,var/z)
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)
return 0
var/turf/T = locate(x,y,z)
if(!T || (target_turf_type && !istype(T,target_turf_type)))
return 0
var/newpath = get_appropriate_path(map[current_cell])
if(newpath)
T.ChangeTurf(newpath)
get_additional_spawns(map[current_cell],T)
return T
/datum/random_map/proc/get_appropriate_path(var/value)
switch(value)
if(FLOOR_CHAR)
return floor_type
if(WALL_CHAR)
return wall_type
/datum/random_map/proc/get_additional_spawns(var/value, var/turf/T)
if(value == DOOR_CHAR)
new /obj/machinery/door/airlock(T)
/datum/random_map/proc/cleanup()
return
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--
/datum/random_map/proc/overlay_with(var/datum/random_map/target_map, var/tx, var/ty)
if(!map.len || !istype(target_map))
return
tx-- // Update origin so that x/y index
ty-- // doesn't push it off-kilter by one.
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
var/current_cell = get_map_cell(x,y)
if(!within_bounds(current_cell))
continue
if(tx+x > target_map.limit_x)
continue
if(ty+y > target_map.limit_y)
continue
target_map.map[target_map.get_map_cell(tx+x,ty+y)] = map[current_cell]
handle_post_overlay_on(target_map,tx,ty)
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++
admin_notice("<span class='danger'>Placed [rooms_placed] secrets.</span>", R_DEBUG)
return 1
/datum/random_map/proc/handle_post_overlay_on(var/datum/random_map/target_map, var/tx, var/ty)
return

View File

@@ -0,0 +1,107 @@
/client/proc/print_random_map()
set category = "Debug"
set name = "Display Random Map"
set desc = "Show the contents of a random map."
if(!holder) return
var/choice = input("Choose a map to display.") as null|anything in random_maps
if(!choice)
return
var/datum/random_map/M = random_maps[choice]
if(istype(M))
M.display_map(usr)
/client/proc/delete_random_map()
set category = "Debug"
set name = "Delete Random Map"
set desc = "Delete a random map."
if(!holder) return
var/choice = input("Choose a map to delete.") as null|anything in random_maps
if(!choice)
return
var/datum/random_map/M = random_maps[choice]
random_maps[choice] = null
if(istype(M))
message_admins("[key_name_admin(usr)] has deleted [M.name].")
log_admin("[key_name(usr)] has deleted [M.name].")
qdel(M)
/client/proc/create_random_map()
set category = "Debug"
set name = "Create Random Map"
set desc = "Create a random map."
if(!holder) return
var/map_datum = input("Choose a map to create.") as null|anything in typesof(/datum/random_map)-/datum/random_map
if(!map_datum)
return
var/datum/random_map/M
if(alert("Do you wish to customise the map?",,"Yes","No") == "Yes")
var/seed = input("Seed? (blank for none)") as text|null
var/lx = input("X-size? (blank for default)") as num|null
var/ly = input("Y-size? (blank for default)") as num|null
M = new map_datum(seed,null,null,null,lx,ly,1)
else
M = new map_datum(null,null,null,null,null,null,1)
if(M)
message_admins("[key_name_admin(usr)] has created [M.name].")
log_admin("[key_name(usr)] has created [M.name].")
/client/proc/apply_random_map()
set category = "Debug"
set name = "Apply Random Map"
set desc = "Apply a map to the game world."
if(!holder) return
var/choice = input("Choose a map to apply.") as null|anything in random_maps
if(!choice)
return
var/datum/random_map/M = random_maps[choice]
if(istype(M))
var/tx = input("X? (default to current turf)") as num|null
var/ty = input("Y? (default to current turf)") as num|null
var/tz = input("Z? (default to current turf)") as num|null
if(isnull(tx) || isnull(ty) || isnull(tz))
var/turf/T = get_turf(usr)
tx = !isnull(tx) ? tx : T.x
ty = !isnull(ty) ? ty : T.y
tz = !isnull(tz) ? tz : T.z
message_admins("[key_name_admin(usr)] has applied [M.name] at x[tx],y[ty],z[tz].")
log_admin("[key_name(usr)] has applied [M.name] at x[tx],y[ty],z[tz].")
M.apply_to_map(tx,ty,tz)
/client/proc/overlay_random_map()
set category = "Debug"
set name = "Overlay Random Map"
set desc = "Apply a map to another map."
if(!holder) return
var/choice = input("Choose a map as base.") as null|anything in random_maps
if(!choice)
return
var/datum/random_map/base_map = random_maps[choice]
choice = null
choice = input("Choose a map to overlay.") as null|anything in random_maps
if(!choice)
return
var/datum/random_map/overlay_map = random_maps[choice]
if(istype(base_map) && istype(overlay_map))
var/tx = input("X? (default to 1)") as num|null
var/ty = input("Y? (default to 1)") as num|null
if(!tx) tx = 1
if(!ty) ty = 1
message_admins("[key_name_admin(usr)] has applied [overlay_map.name] to [base_map.name] at x[tx],y[ty].")
log_admin("[key_name(usr)] has applied [overlay_map.name] to [base_map.name] at x[tx],y[ty].")
overlay_map.overlay_with(base_map,tx,ty)
base_map.display_map(usr)