--- Procedural generation methods function init_mapgen() uid_seed = 2229 -- arbitrarily chosen number block_size = 64 biome_size = 128 -- Metadata for different biomes -- frequencies don't have to add up to 100, but they should by convention -- -- Sprites are: -- * 2 - grass -- * 3 - bush -- * 4 - tree -- * 5 - red flowers -- * 6 - pink flowers -- * 7 - mushrooms -- * 8 - big mushroom -- * 9 - sand -- * 10 - cactus with flower -- * 11 - pebbles -- * 12 - rock -- * 13 - cactus biome_data = { grassland = { biome_frequency = 75, tile_frequencies = { {40, 2}, {28, 5}, {28, 6}, {3, 3}, {1, 4} } }, forest = { biome_frequency = 20, tile_frequencies = { {60, 2}, {20, 4}, {5, 3}, {5, 5}, {4, 7}, {5, 6}, {1, 8} } }, desert = { biome_frequency = 5, tile_frequencies = { {80, 9}, {10, 11}, {6, 13}, {3, 12}, {1, 10} }, } } -- 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. biome_list = {"grassland", "forest", "desert"} init_biomes() end function init_biomes() -- this is the frequency list for the biomes themselves biome_metadata = {} for i=1,#biome_list do local biome = biome_list[i] -- add the biome's name N times to the biome metadata 'hat' for i=1,biome_data[biome]["biome_frequency"] do add(biome_metadata, biome) end build_biome(biome, biome_data[biome]) end end -- build the lookup table for a given biome, based on the biome_meta data for -- that string. function build_biome(biome_name, data) local meta_frequencies = data["tile_frequencies"] local tile_lookup = {} for i=1,#meta_frequencies do local tuple = meta_frequencies[i] for j=1,tuple[1] do add(tile_lookup, tuple[2]) end end data["tile_lookup"] = tile_lookup end -- generates a unique identifier for a position -- uses srand() and rand() to get an unpredictable value (is this too slow?) function generate_uid(pos) srand((pos[1] + uid_seed) * (pos[2] + (uid_seed^2))) return flr(rnd(-1)) end -- given an {x,y} position, calculates the aligned starting position for the -- biome that position is in. function calculate_biome_pos(pos) return {flr(pos[1] / biome_size), flr(pos[2] / biome_size)} end -- determines which biome a given world map position should be, -- returns the object out of the biome_data table function get_biome(pos) local biome_pos = calculate_biome_pos(pos) local uid = generate_uid(biome_pos) local biome_name = biome_metadata[(uid % #biome_metadata) + 1] return biome_data[biome_name] end -- determine what sprite to render for a given position. -- todo: this needs the ability to have a list of 'changed' tiles to check against. function get_tile(pos) local biome = get_biome(pos) local uid = generate_uid(pos) return biome["tile_lookup"][(uid % #biome["tile_lookup"]) + 1] 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 } function generate_map(start) for x=0,block_size-1 do for y=0,block_size-1 do mset(x, y, get_tile({start[1]+x, start[2]+y})) end end end