2019-12-04 23:48:04 +00:00
|
|
|
--- Procedural generation methods
|
|
|
|
|
|
|
|
function init_mapgen()
|
2019-12-06 03:02:04 +00:00
|
|
|
uid_seed = 2229 -- arbitrarily chosen number
|
2019-12-04 23:48:04 +00:00
|
|
|
|
2019-12-07 21:30:41 +00:00
|
|
|
-- Metadata for different biomes
|
2019-12-09 21:12:48 +00:00
|
|
|
-- tile_frequencies tuples are {frequency, sprite_index}, see index_map.md
|
2019-12-10 00:17:50 +00:00
|
|
|
-- frequencies by convention add up to 1000, but this is arbitrary, the
|
|
|
|
-- only concern is the space consumed by the resulting tables.
|
2019-12-07 21:30:41 +00:00
|
|
|
biome_data = {
|
2019-12-10 00:17:50 +00:00
|
|
|
meadow = {
|
|
|
|
biome_frequency = 20,
|
|
|
|
tile_frequencies = { {525, 2}, {200, 5}, {200, 6}, {55, 18}, {19, 3}, {1, 4} }
|
|
|
|
},
|
2019-12-07 21:30:41 +00:00
|
|
|
grassland = {
|
2019-12-10 00:17:50 +00:00
|
|
|
biome_frequency = 55,
|
|
|
|
tile_frequencies = { {500, 2}, {345, 18}, {4, 3}, {1, 4}, {100, 5}, {50, 6} }
|
2019-12-07 21:30:41 +00:00
|
|
|
},
|
|
|
|
forest = {
|
|
|
|
biome_frequency = 20,
|
2019-12-10 00:17:50 +00:00
|
|
|
tile_frequencies = { {600, 2}, {200, 4}, {50, 3}, {50, 5}, {40, 7}, {59, 6}, {1, 8} }
|
2019-12-07 21:30:41 +00:00
|
|
|
},
|
|
|
|
desert = {
|
|
|
|
biome_frequency = 5,
|
2019-12-10 00:17:50 +00:00
|
|
|
tile_frequencies = { {800, 9}, {109, 11}, {60, 13}, {30, 12}, {1, 10} },
|
2019-12-07 21:30:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-09 02:40:00 +00:00
|
|
|
-- Why is this hard-coded separately from the biome_data? glad you asked.
|
|
|
|
-- Lua's pairs() function appears not to guarantee a consistent return order,
|
|
|
|
-- and we want our world to be deterministically generated,
|
|
|
|
-- so the biome_metadata array needs to have its entries appear consistently.
|
2019-12-10 00:17:50 +00:00
|
|
|
biome_list = {"grassland", "meadow", "forest", "desert"}
|
2019-12-09 02:40:00 +00:00
|
|
|
|
2019-12-07 21:30:41 +00:00
|
|
|
-- this is the frequency list for the biomes themselves
|
|
|
|
biome_metadata = {}
|
|
|
|
|
2019-12-09 02:40:00 +00:00
|
|
|
for i=1,#biome_list do
|
|
|
|
local biome = biome_list[i]
|
|
|
|
|
2019-12-07 21:30:41 +00:00
|
|
|
-- add the biome's name N times to the biome metadata 'hat'
|
2019-12-09 21:51:15 +00:00
|
|
|
for i=1,biome_data[biome].biome_frequency do
|
2019-12-09 02:40:00 +00:00
|
|
|
add(biome_metadata, biome)
|
2019-12-07 21:30:41 +00:00
|
|
|
end
|
|
|
|
|
2019-12-09 02:40:00 +00:00
|
|
|
build_biome(biome, biome_data[biome])
|
2019-12-04 23:48:04 +00:00
|
|
|
end
|
2019-12-07 21:30:41 +00:00
|
|
|
end
|
2019-12-04 23:48:04 +00:00
|
|
|
|
2019-12-07 21:30:41 +00:00
|
|
|
-- build the lookup table for a given biome, based on the biome_meta data for
|
|
|
|
-- that string.
|
|
|
|
function build_biome(biome_name, data)
|
2019-12-09 21:51:15 +00:00
|
|
|
local meta_frequencies = data.tile_frequencies
|
2019-12-07 21:30:41 +00:00
|
|
|
local tile_lookup = {}
|
|
|
|
|
|
|
|
for i=1,#meta_frequencies do
|
|
|
|
local tuple = meta_frequencies[i]
|
2019-12-04 23:48:04 +00:00
|
|
|
for j=1,tuple[1] do
|
2019-12-07 21:30:41 +00:00
|
|
|
add(tile_lookup, tuple[2])
|
2019-12-04 23:48:04 +00:00
|
|
|
end
|
|
|
|
end
|
2019-12-07 21:30:41 +00:00
|
|
|
|
2019-12-09 21:51:15 +00:00
|
|
|
data.tile_lookup = tile_lookup
|
2019-12-04 23:48:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- generates a unique identifier for a position
|
|
|
|
-- uses srand() and rand() to get an unpredictable value (is this too slow?)
|
2019-12-09 21:35:45 +00:00
|
|
|
-- the two seed values are randomly chosen. Change them and change the world.
|
|
|
|
function generate_uid(pos_x, pos_y)
|
|
|
|
srand((pos_x + 2229) * (pos_y + 12295))
|
|
|
|
return flr(rnd(0xffff))
|
2019-12-04 23:48:04 +00:00
|
|
|
end
|
|
|
|
|
2019-12-09 02:40:00 +00:00
|
|
|
-- given an {x,y} position, calculates the aligned starting position for the
|
|
|
|
-- biome that position is in.
|
2019-12-09 21:35:45 +00:00
|
|
|
-- biomes are currently defined to be 128x128
|
|
|
|
function calculate_biome_pos(pos_x, pos_y)
|
|
|
|
return flr(pos_x / 128), flr(pos_y / 128)
|
2019-12-09 02:40:00 +00:00
|
|
|
end
|
|
|
|
|
2019-12-07 21:30:41 +00:00
|
|
|
-- determines which biome a given world map position should be,
|
|
|
|
-- returns the object out of the biome_data table
|
2019-12-09 21:35:45 +00:00
|
|
|
function get_biome_name(pos_x, pos_y)
|
|
|
|
local biome_pos_x, biome_pos_y = calculate_biome_pos(pos_x, pos_y)
|
|
|
|
local uid = generate_uid(biome_pos_x, biome_pos_y)
|
2019-12-09 21:12:48 +00:00
|
|
|
return biome_metadata[(uid % #biome_metadata) + 1]
|
2019-12-07 21:30:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- determine what sprite to render for a given position.
|
2019-12-10 02:50:06 +00:00
|
|
|
-- pos_x and pos_y are global coordinates.
|
2019-12-09 21:35:45 +00:00
|
|
|
function get_tile(pos_x, pos_y)
|
2019-12-10 02:50:06 +00:00
|
|
|
-- lookup changes in the change buffer
|
2019-12-11 05:29:02 +00:00
|
|
|
local modded_sprite = mod_buffer[get_mod_key(pos_x, pos_y)]
|
2019-12-10 02:50:06 +00:00
|
|
|
if (modded_sprite) return modded_sprite
|
|
|
|
|
2019-12-09 21:35:45 +00:00
|
|
|
local biome_name = get_biome_name(pos_x, pos_y)
|
2019-12-09 21:12:48 +00:00
|
|
|
local biome = biome_data[biome_name]
|
2019-12-09 21:35:45 +00:00
|
|
|
local uid = generate_uid(pos_x, pos_y)
|
2019-12-07 21:30:41 +00:00
|
|
|
|
2019-12-09 21:51:15 +00:00
|
|
|
return biome.tile_lookup[(uid % #biome.tile_lookup) + 1]
|
2019-12-04 23:48:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- generate the map and writes to the map area from 0 - block_size,
|
|
|
|
-- assuming 'start' as the top-left corner of the map area to generate.
|
|
|
|
-- writes block_size x block_size tiles
|
|
|
|
-- after a call to generate_map you should always center the camera/player over the map, i.e.
|
|
|
|
-- camera at { (block_size / 2) - 8, (block_size / 2) - 8 }
|
2019-12-09 21:35:45 +00:00
|
|
|
function generate_map(start_x, start_y)
|
|
|
|
for x=0,63 do
|
|
|
|
for y=0,63 do
|
|
|
|
mset(x, y, get_tile(start_x+x, start_y+y))
|
2019-12-04 23:48:04 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|