a_pleasant_stroll/mapgen.lua

124 lines
3.6 KiB
Lua
Raw Normal View History

2019-12-04 23:48:04 +00:00
--- Procedural generation methods
function init_mapgen()
uid_seed = 2229 -- arbitrarily chosen number
block_size = 64
2019-12-07 21:30:41 +00:00
biome_size = 128
2019-12-04 23:48:04 +00:00
2019-12-07 21:30:41 +00:00
-- Metadata for different biomes
2019-12-04 23:48:04 +00:00
-- 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
2019-12-07 21:30:41 +00:00
-- * 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} },
}
}
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.
biome_list = {"grassland", "forest", "desert"}
2019-12-07 21:30:41 +00:00
init_biomes()
2019-12-04 23:48:04 +00:00
end
2019-12-07 21:30:41 +00:00
function init_biomes()
-- 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 02:40:00 +00:00
for i=1,biome_data[biome]["biome_frequency"] do
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)
local meta_frequencies = data["tile_frequencies"]
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
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?)
function generate_uid(pos)
srand((pos[1] + uid_seed) * (pos[2] + (uid_seed^2)))
return flr(rnd(-1))
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.
function calculate_biome_pos(pos)
return {flr(pos[1] / biome_size), flr(pos[2] / biome_size)}
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
function get_biome(pos)
2019-12-09 02:40:00 +00:00
local biome_pos = calculate_biome_pos(pos)
2019-12-07 21:30:41 +00:00
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.
2019-12-04 23:48:04 +00:00
function get_tile(pos)
2019-12-07 21:30:41 +00:00
local biome = get_biome(pos)
local uid = generate_uid(pos)
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 }
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