|
@@ -0,0 +1,1275 @@
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ores = {
|
|
|
+ [1] = {
|
|
|
+ name = 'Iron',
|
|
|
+ offset = 15000,
|
|
|
+ id = 3,
|
|
|
+ scale = 0.011,
|
|
|
+ min = 15,
|
|
|
+ max = 16,
|
|
|
+ bmin = 45,
|
|
|
+ bmax = 100,
|
|
|
+ color_keys = 4,
|
|
|
+ tile_id = 162,
|
|
|
+ sprite_id = 178,
|
|
|
+ biome_id = 2,
|
|
|
+ map_cols = {8,11,12,13,14,15},
|
|
|
+ },
|
|
|
+ [2] = {
|
|
|
+ name = 'Copper',
|
|
|
+ offset = 10000,
|
|
|
+ id = 4,
|
|
|
+ scale = 0.013,
|
|
|
+ min = 15,
|
|
|
+ max = 16,
|
|
|
+ bmin = 33,
|
|
|
+ bmax = 40,
|
|
|
+ color_keys = 1,
|
|
|
+ tile_id = 161,
|
|
|
+ sprite_id = 177,
|
|
|
+ biome_id = 2,
|
|
|
+ map_cols = {2,3,4,15},
|
|
|
+ },
|
|
|
+ [3] = {
|
|
|
+ name = 'Coal',
|
|
|
+ offset = 50000,
|
|
|
+ id = 6,
|
|
|
+ scale = 0.020,
|
|
|
+ min = 14,
|
|
|
+ max = 17,
|
|
|
+ bmin = 35,
|
|
|
+ bmax = 75,
|
|
|
+ color_keys = 4,
|
|
|
+ tile_id = 163,
|
|
|
+ sprite_id = 179,
|
|
|
+ biome_id = 3,
|
|
|
+ map_cols = {0,14,15},
|
|
|
+ },
|
|
|
+ [4] = {
|
|
|
+ name = 'Stone',
|
|
|
+ offset = 22500,
|
|
|
+ id = 5,
|
|
|
+ scale = 0.018,
|
|
|
+ min = 15,
|
|
|
+ max = 16,
|
|
|
+ bmin = 20,
|
|
|
+ bmax = 70,
|
|
|
+ color_keys = 4,
|
|
|
+ tile_id = 160,
|
|
|
+ sprite_id = 176,
|
|
|
+ biome_id = 1,
|
|
|
+ map_cols = {12,13,14,15},
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+biomes = {
|
|
|
+ [1] = {
|
|
|
+ name = 'Desert',
|
|
|
+ tile_id_offset = 0,
|
|
|
+ min = 20,
|
|
|
+ max = 30,
|
|
|
+ t_min = 21,
|
|
|
+ t_max = 25,
|
|
|
+ tree_id = 193,
|
|
|
+ tree_density = 0.05,
|
|
|
+ color_key = 0,
|
|
|
+ map_col = 4,
|
|
|
+ clutter = 0.02
|
|
|
+ },
|
|
|
+ [2] = {
|
|
|
+ name = 'Prairie',
|
|
|
+ tile_id_offset = 16,
|
|
|
+ min = 30,
|
|
|
+ max = 45,
|
|
|
+ t_min = 33,
|
|
|
+ t_max = 40,
|
|
|
+ tree_id = 196,
|
|
|
+ tree_density = 0.05,
|
|
|
+ color_key = 1,
|
|
|
+ map_col = 6,
|
|
|
+ clutter = 0.08
|
|
|
+ },
|
|
|
+ [3] = {
|
|
|
+ name = 'Forest',
|
|
|
+ tile_id_offset = 32,
|
|
|
+ min = 45,
|
|
|
+ max = 101,
|
|
|
+ t_min = 47,
|
|
|
+ t_max = 99,
|
|
|
+ tree_id = 199,
|
|
|
+ tree_density = 0.05,
|
|
|
+ color_key = 1,
|
|
|
+ map_col = 7,
|
|
|
+ clutter = 0.05
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
+TileManager = {}
|
|
|
+TileManager.__index = TileManager
|
|
|
+
|
|
|
+auto_map = {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ['1000'] = {sprite_id = 1, rot = 0},
|
|
|
+ ['0100'] = {sprite_id = 1, rot = 1},
|
|
|
+ ['0010'] = {sprite_id = 1, rot = 2},
|
|
|
+ ['0001'] = {sprite_id = 1, rot = 3},
|
|
|
+
|
|
|
+ ['1100'] = {sprite_id = 2, rot = 1},
|
|
|
+ ['0110'] = {sprite_id = 2, rot = 2},
|
|
|
+ ['0011'] = {sprite_id = 2, rot = 3},
|
|
|
+ ['1001'] = {sprite_id = 2, rot = 0},
|
|
|
+
|
|
|
+ ['1101'] = {sprite_id = 3, rot = 0},
|
|
|
+ ['1110'] = {sprite_id = 3, rot = 1},
|
|
|
+ ['0111'] = {sprite_id = 3, rot = 2},
|
|
|
+ ['1011'] = {sprite_id = 3, rot = 3},
|
|
|
+ ['0101'] = {sprite_id = 4, rot = 0},
|
|
|
+ ['1010'] = {sprite_id = 4, rot = 1},
|
|
|
+ ['1111'] = {sprite_id = 0, rot = 0},
|
|
|
+}
|
|
|
+
|
|
|
+function ore_sample(x, y, tile)
|
|
|
+ local biome = tile.biome
|
|
|
+ for i = 1, #ores do
|
|
|
+ local scale = ores[i].scale
|
|
|
+ local noise = (simplex.Noise2D(x * scale + ((ores[i].offset * biome) * scale) + offset * scale, (y * scale) + ((ores[i].offset * biome) * scale) + (offset * scale)) / 2 + 0.5) * 16
|
|
|
+ if noise >= ores[i].min and noise <= ores[i].max and tile.noise >= ores[i].bmin and tile.noise <= ores[i].bmax then return i end
|
|
|
+ end
|
|
|
+ return false
|
|
|
+end
|
|
|
+
|
|
|
+function AutoMap(x, y)
|
|
|
+ local tile = TileMan.tiles[y][x]
|
|
|
+ TileMan.tiles[y][x].visited = true
|
|
|
+
|
|
|
+ local adj = {
|
|
|
+ [1] = {x = 0, y = -1},
|
|
|
+ [2] = {x = 1, y = 0},
|
|
|
+ [3] = {x = 0, y = 1},
|
|
|
+ [4] = {x = -1, y = 0},
|
|
|
+ }
|
|
|
+ local key = ''
|
|
|
+ for i = 1, 4 do
|
|
|
+
|
|
|
+ local near = TileMan.tiles[y + adj[i].y][x + adj[i].x]
|
|
|
+
|
|
|
+
|
|
|
+ if not near.is_land or near.biome < tile.biome then
|
|
|
+ key = key .. '1'
|
|
|
+ TileMan.tiles[y][x].border_col = biomes[near.biome].map_col
|
|
|
+ else
|
|
|
+ key = key .. '0'
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+ local new_tile = auto_map[key]
|
|
|
+
|
|
|
+
|
|
|
+ if not new_tile then return end
|
|
|
+
|
|
|
+ TileMan.tiles[y][x].sprite_id = new_tile.sprite_id + 11 + biomes[tile.biome].tile_id_offset
|
|
|
+ TileMan.tiles[y][x].is_border = true
|
|
|
+
|
|
|
+ TileMan.tiles[y][x].ore = false
|
|
|
+ TileMan.tiles[y][x].flip = 0
|
|
|
+ TileMan.tiles[y][x].rot = new_tile.rot
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager.new()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ local self = setmetatable({}, TileManager)
|
|
|
+ local tile_mt = {
|
|
|
+ __index = function(row, x)
|
|
|
+
|
|
|
+ local tile = TileManager.create_tile(x, row.y)
|
|
|
+ row[x] = tile
|
|
|
+ return tile
|
|
|
+ end
|
|
|
+ }
|
|
|
+ local tiles_mt = {
|
|
|
+ __index = function(tiles, y)
|
|
|
+ local row = setmetatable({y = y}, tile_mt)
|
|
|
+ tiles[y] = row
|
|
|
+ return row
|
|
|
+ end
|
|
|
+ }
|
|
|
+ self.tiles = setmetatable({}, tiles_mt)
|
|
|
+ return self
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager.create_tile(x, y)
|
|
|
+
|
|
|
+
|
|
|
+ local scale = 0.0005
|
|
|
+ local scale2 = 0.025
|
|
|
+
|
|
|
+ local base_noise = (simplex.Noise2D(x * scale + offset * scale, (y * scale) + (offset * scale)) / 2 + 0.5) * 100
|
|
|
+ local addl_noise = (simplex.Noise2D(x * scale2 + offset * scale2, (y * scale2) + (offset * scale2))) * 100
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ base_noise = lerp(base_noise, addl_noise, 0.05)
|
|
|
+
|
|
|
+ local tile = {
|
|
|
+ noise = base_noise,
|
|
|
+ is_land = base_noise >= 20 and true or false,
|
|
|
+ biome = 1,
|
|
|
+ is_border = false,
|
|
|
+ is_tree = false,
|
|
|
+ visited = false,
|
|
|
+ b_visited = false,
|
|
|
+ rot = 0,
|
|
|
+ offset = {x = math.random(1, 2), y = math.random(1, 4)},
|
|
|
+ }
|
|
|
+ for i = 1, #biomes do
|
|
|
+ if base_noise > biomes[i].min and base_noise < biomes[i].max then
|
|
|
+ tile.biome = i
|
|
|
+ break
|
|
|
+ end
|
|
|
+ end
|
|
|
+ tile.flip = math.random() > 0.5 and 1 or 0
|
|
|
+
|
|
|
+ tile.ore = tile.is_land and base_noise > 21 and ore_sample(x, y, tile) or false
|
|
|
+
|
|
|
+ if not tile.is_land then
|
|
|
+
|
|
|
+ tile.color = floor(math.random(2)) + 8
|
|
|
+ tile.sprite_id = WATER_SPRITE
|
|
|
+ tile.rot = floor(math.random(0,3))
|
|
|
+ else
|
|
|
+ tile.sprite_id = biomes[tile.biome].tile_id_offset
|
|
|
+ tile.color = biomes[tile.biome].map_col
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+ if tile.ore then
|
|
|
+ tile.color = ores[tile.ore].map_cols[floor(math.random(#ores[tile.ore].map_cols))]
|
|
|
+ tile.rot = math.random(4) % 4
|
|
|
+ end
|
|
|
+
|
|
|
+ if tile.is_land and not tile.ore then
|
|
|
+
|
|
|
+ scale = 0.001
|
|
|
+ local tree = base_noise
|
|
|
+
|
|
|
+ local tmin = biomes[tile.biome].t_min
|
|
|
+ local tmax = biomes[tile.biome].t_max
|
|
|
+
|
|
|
+
|
|
|
+ if tree >= biomes[tile.biome].t_min and tree <= biomes[tile.biome].t_max and math.random(0, 100) < (biomes[tile.biome].tree_density * 100) then
|
|
|
+
|
|
|
+ tile.is_tree = true
|
|
|
+
|
|
|
+ elseif math.random(100) <= (biomes[tile.biome].clutter * 100) then
|
|
|
+ local rand = floor(math.random(10))
|
|
|
+ tile.sprite_id = biomes[tile.biome].tile_id_offset + rand
|
|
|
+
|
|
|
+ if rand == 1 then
|
|
|
+ tile.rot = math.random(4) % 4
|
|
|
+ end
|
|
|
+ else
|
|
|
+ tile.rot = math.random(4) % 4
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ return tile
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager:set_tile(x, y, tile_id)
|
|
|
+ local tile = self.tiles[y][x]
|
|
|
+ tile_id = tile_id or biomes[tile.biome].tile_id_offset
|
|
|
+ if tile.is_land and not tile.ore and not tile.is_border then
|
|
|
+ self.tiles[y][x].sprite_id = tile_id
|
|
|
+ self.tiles[y][x].is_tree = false
|
|
|
+ end
|
|
|
+ if tile.ore then
|
|
|
+ self.tiles[y][x].ore = false
|
|
|
+ self.tiles[y][x].is_tree = false
|
|
|
+ self.tiles[y][x].sprite_id = biomes[tile.biome].tile_id_offset
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager:draw_terrain(player, screenWidth, screenHeight)
|
|
|
+ local cameraTopLeftX = player.x - 116
|
|
|
+ local cameraTopLeftY = player.y - 64
|
|
|
+ local subTileX = cameraTopLeftX % 8
|
|
|
+ local subTileY = cameraTopLeftY % 8
|
|
|
+ local startX = floor(cameraTopLeftX / 8)
|
|
|
+ local startY = floor(cameraTopLeftY / 8)
|
|
|
+ for screenY = 1, screenHeight do
|
|
|
+ for screenX = 1, screenWidth do
|
|
|
+ local worldX = startX + screenX
|
|
|
+ local worldY = startY + screenY
|
|
|
+ local tile = self.tiles[worldY][worldX]
|
|
|
+ local sx = (screenX - 1) * 8 - subTileX
|
|
|
+ local sy = (screenY - 1) * 8 - subTileY
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if not tile.visited and tile.is_land then AutoMap(worldX, worldY) end
|
|
|
+
|
|
|
+ if tile.ore then
|
|
|
+ rect(sx, sy, 8, 8, biomes[tile.biome].map_col)
|
|
|
+ sspr(ores[tile.ore].tile_id, sx, sy, ores[tile.ore].color_keys, 1, 0, tile.rot)
|
|
|
+ elseif not tile.is_border then
|
|
|
+ local id, rot, flip = tile.sprite_id, tile.rot, tile.flip
|
|
|
+ if not tile.is_land then
|
|
|
+
|
|
|
+ if worldX % 2 == 1 and worldY % 2 == 1 then
|
|
|
+ flip = 3
|
|
|
+ elseif worldX % 2 == 1 then
|
|
|
+ flip = 1
|
|
|
+ elseif worldY % 2 == 1 then
|
|
|
+ flip = 2
|
|
|
+ end
|
|
|
+
|
|
|
+ sspr(224, sx, sy, 0, 1, flip, rot)
|
|
|
+ else
|
|
|
+
|
|
|
+ rect(sx, sy, 8, 8, biomes[tile.biome].map_col)
|
|
|
+ sspr(biomes[tile.biome].tile_id_offset, sx, sy, biomes[tile.biome].map_col, 1, 0, tile.rot)
|
|
|
+ if id ~= biomes[tile.biome].tile_id_offset then
|
|
|
+ sspr(id, sx, sy, biomes[tile.biome].map_col, 1, flip)
|
|
|
+ end
|
|
|
+ end
|
|
|
+ else
|
|
|
+ if tile.biome == 1 then
|
|
|
+ local flip = 0
|
|
|
+ if worldX % 2 == 1 and worldY % 2 == 1 then
|
|
|
+ flip = 3
|
|
|
+ elseif worldX % 2 == 1 then
|
|
|
+ flip = 1
|
|
|
+ elseif worldY % 2 == 1 then
|
|
|
+ flip = 2
|
|
|
+ end
|
|
|
+ sspr(224, sx, sy, -1, 1, flip)
|
|
|
+ sspr(tile.sprite_id, sx, sy, 0, 1, 0, tile.rot)
|
|
|
+ else
|
|
|
+ sspr(tile.sprite_id, sx, sy, -1, 1, 0, tile.rot)
|
|
|
+ end
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager:draw_clutter(player, screenWidth, screenHeight)
|
|
|
+ local cameraTopLeftX = player.x - 116
|
|
|
+ local cameraTopLeftY = player.y - 64
|
|
|
+ local subTileX = cameraTopLeftX % 8
|
|
|
+ local subTileY = cameraTopLeftY % 8
|
|
|
+ local startX = floor(cameraTopLeftX / 8)
|
|
|
+ local startY = floor(cameraTopLeftY / 8)
|
|
|
+
|
|
|
+ for screenY = 1, screenHeight do
|
|
|
+ for screenX = 1, screenWidth do
|
|
|
+ local worldX = startX + screenX
|
|
|
+ local worldY = startY + screenY
|
|
|
+ local tile = self.tiles[worldY][worldX]
|
|
|
+ local sx = (screenX - 1) * 8 - subTileX
|
|
|
+ local sy = (screenY - 1) * 8 - subTileY
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if tile.is_tree then
|
|
|
+
|
|
|
+ sspr(biomes[tile.biome].tree_id, sx - 9 + tile.offset.x, sy - 27 + tile.offset.y, biomes[tile.biome].color_key, 1, tile.flip, 0, 3, 4)
|
|
|
+
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager:draw_worldmap(player, x, y, width, height, center)
|
|
|
+
|
|
|
+ width, height = width or 240, height or 136
|
|
|
+ x, y = x or 120 - (width/2), y or 68 - (height/2)
|
|
|
+ if center then
|
|
|
+ x = (240/2) - (width/2)
|
|
|
+ y = (136/2) - (height/2)
|
|
|
+ end
|
|
|
+ local map_x, map_y = x or 120 - (width/2) + 1, y or 68 - (height/2) + 2
|
|
|
+ local startX, startY = floor(player.x/8 - (width/2) + 1), floor(player.y/8 - (height/2) + 2)
|
|
|
+ local biome_col = biomes[self.tiles[startY][startX].biome].map_col
|
|
|
+ local skipped = 0
|
|
|
+ rectb(map_x - 1, map_y - 1, width + 2, height + 2, 9)
|
|
|
+ rect(map_x, map_y, width, height, biome_col)
|
|
|
+
|
|
|
+ local biome = self.tiles[startY][startX].biome
|
|
|
+ start_col = biomes[biome].map_col
|
|
|
+ for y = 0, height - 1 do
|
|
|
+ if y == 0 then
|
|
|
+ end
|
|
|
+ for x = 0, width - 1 do
|
|
|
+ local tile = self.tiles[startY + y - 1][startX + x - 1]
|
|
|
+ if tile.color ~= start_col or tile.ore or tile.is_tree or not tile.is_land or not tile.biome == biome then
|
|
|
+
|
|
|
+ if rawget(self.tiles, startY + y - 1) and rawget(self.tiles[startY + y - 1], startX + x - 1) then
|
|
|
+
|
|
|
+
|
|
|
+ pix(x + map_x, y + map_y, tile.is_tree and 6 or tile.color)
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+
|
|
|
+end
|
|
|
+
|
|
|
+function TileManager:save_worldmap(player, width, height)
|
|
|
+
|
|
|
+ width, height = width or 240, height or 136
|
|
|
+ x, y = 0, 0
|
|
|
+ local map_x, map_y = x or 120 - (width/2) + 1, y or 68 - (height/2) + 2
|
|
|
+ local startX, startY = floor(player.x/8 - (width/2) + 1), floor(player.y/8 - (height/2) + 2)
|
|
|
+ local biome_col = biomes[self.tiles[startY][startX].biome].map_col
|
|
|
+ local skipped = 0
|
|
|
+ rectb(map_x - 1, map_y - 1, width + 2, height + 2, 9)
|
|
|
+ rect(map_x, map_y, width, height, biome_col)
|
|
|
+
|
|
|
+ for y = 0, height - 1 do
|
|
|
+ if y == 0 then
|
|
|
+ local biome = self.tiles[startY + y - 1][startX + x - 1].biome
|
|
|
+ start_col = biomes[biome].map_col
|
|
|
+ end
|
|
|
+ for x = 0, width - 1 do
|
|
|
+ local tile = self.tiles[startY + y - 1][startX + x - 1]
|
|
|
+ pix(x + map_x, y + map_y, tile.is_tree and 6 or tile.color)
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+local math = math
|
|
|
+local table = table
|
|
|
+local tonumber = tonumber
|
|
|
+local ipairs = ipairs
|
|
|
+local error = error
|
|
|
+
|
|
|
+simplex = {}
|
|
|
+simplex.DIR_X = 0
|
|
|
+simplex.DIR_Y = 1
|
|
|
+simplex.DIR_Z = 2
|
|
|
+simplex.DIR_W = 3
|
|
|
+simplex.internalCache = false
|
|
|
+
|
|
|
+local Gradients3D = {{1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0},
|
|
|
+{1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1},
|
|
|
+{0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1}}
|
|
|
+local Gradients4D = {{0,1,1,1}, {0,1,1,-1}, {0,1,-1,1}, {0,1,-1,-1},
|
|
|
+{0,-1,1,1}, {0,-1,1,-1}, {0,-1,-1,1}, {0,-1,-1,-1},
|
|
|
+{1,0,1,1}, {1,0,1,-1}, {1,0,-1,1}, {1,0,-1,-1},
|
|
|
+{-1,0,1,1}, {-1,0,1,-1}, {-1,0,-1,1}, {-1,0,-1,-1},
|
|
|
+{1,1,0,1}, {1,1,0,-1}, {1,-1,0,1}, {1,-1,0,-1},
|
|
|
+{-1,1,0,1}, {-1,1,0,-1}, {-1,-1,0,1}, {-1,-1,0,-1},
|
|
|
+{1,1,1,0}, {1,1,-1,0}, {1,-1,1,0}, {1,-1,-1,0},
|
|
|
+{-1,1,1,0}, {-1,1,-1,0}, {-1,-1,1,0}, {-1,-1,-1,0}}
|
|
|
+local p = {151,160,137,91,90,15,
|
|
|
+131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
|
|
+190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
|
|
+88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
|
|
+77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
|
|
+102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
|
|
+135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
|
|
+5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
|
|
+223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
|
|
+129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
|
|
+251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
|
|
+49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
|
|
+138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180}
|
|
|
+
|
|
|
+
|
|
|
+for i=1,#p do
|
|
|
+ p[i-1] = p[i]
|
|
|
+ p[i] = nil
|
|
|
+end
|
|
|
+
|
|
|
+for i=1,#Gradients3D do
|
|
|
+ Gradients3D[i-1] = Gradients3D[i]
|
|
|
+ Gradients3D[i] = nil
|
|
|
+end
|
|
|
+
|
|
|
+for i=1,#Gradients4D do
|
|
|
+ Gradients4D[i-1] = Gradients4D[i]
|
|
|
+ Gradients4D[i] = nil
|
|
|
+end
|
|
|
+
|
|
|
+local perm = {}
|
|
|
+
|
|
|
+for i=0,255 do
|
|
|
+ perm[i] = p[i]
|
|
|
+ perm[i+256] = p[i]
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+local sim = {
|
|
|
+{0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0},
|
|
|
+{0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0},
|
|
|
+{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
|
|
|
+{1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0},
|
|
|
+{1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0},
|
|
|
+{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
|
|
|
+{2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0},
|
|
|
+{2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0}}
|
|
|
+
|
|
|
+local function Dot2D(tbl, x, y)
|
|
|
+ return tbl[1]*x + tbl[2]*y;
|
|
|
+end
|
|
|
+local function Dot3D(tbl, x, y, z)
|
|
|
+ return tbl[1]*x + tbl[2]*y + tbl[3]*z
|
|
|
+end
|
|
|
+local function Dot4D( tbl, x,y,z,w)
|
|
|
+ return tbl[1]*x + tbl[2]*y + tbl[3]*z + tbl[3]*w;
|
|
|
+end
|
|
|
+
|
|
|
+local Prev2D = {}
|
|
|
+
|
|
|
+function simplex.seed(seed)
|
|
|
+ seed = seed or tstamp()
|
|
|
+ math.randomseed(seed * seed)
|
|
|
+ for i = 1, 256 do
|
|
|
+ p[i] = math.floor(math.random()*256)
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+function simplex.Noise2D(xin, yin)
|
|
|
+ if simplex.internalCache and Prev2D[xin] and Prev2D[xin][yin] then return Prev2D[xin][yin] end
|
|
|
+
|
|
|
+ local n0, n1, n2;
|
|
|
+
|
|
|
+ local F2 = 0.5*(math.sqrt(3.0)-1.0);
|
|
|
+ local s = (xin+yin)*F2;
|
|
|
+ local i = math.floor(xin+s);
|
|
|
+ local j = math.floor(yin+s);
|
|
|
+ local G2 = (3.0-math.sqrt(3.0))/6.0;
|
|
|
+
|
|
|
+ local t = (i+j)*G2;
|
|
|
+ local X0 = i-t;
|
|
|
+ local Y0 = j-t;
|
|
|
+ local x0 = xin-X0;
|
|
|
+ local y0 = yin-Y0;
|
|
|
+
|
|
|
+ local i1, j1;
|
|
|
+ if(x0>y0) then
|
|
|
+ i1=1
|
|
|
+ j1=0
|
|
|
+ else
|
|
|
+ i1=0
|
|
|
+ j1=1
|
|
|
+ end
|
|
|
+
|
|
|
+ local x1 = x0 - i1 + G2;
|
|
|
+ local y1 = y0 - j1 + G2;
|
|
|
+ local x2 = x0 - 1.0 + 2.0 * G2;
|
|
|
+ local y2 = y0 - 1.0 + 2.0 * G2;
|
|
|
+
|
|
|
+
|
|
|
+ local ii = i & 255
|
|
|
+ local jj = j & 255
|
|
|
+ local gi0 = perm[ii+perm[jj]] % 12;
|
|
|
+ local gi1 = perm[ii+i1+perm[jj+j1]] % 12;
|
|
|
+ local gi2 = perm[ii+1+perm[jj+1]] % 12;
|
|
|
+
|
|
|
+
|
|
|
+ local t0 = 0.5 - x0*x0-y0*y0;
|
|
|
+ if t0<0 then
|
|
|
+ n0 = 0.0;
|
|
|
+ else
|
|
|
+ t0 = t0 * t0
|
|
|
+ n0 = t0 * t0 * Dot2D(Gradients3D[gi0], x0, y0);
|
|
|
+ end
|
|
|
+
|
|
|
+ local t1 = 0.5 - x1*x1-y1*y1;
|
|
|
+ if (t1<0) then
|
|
|
+ n1 = 0.0;
|
|
|
+ else
|
|
|
+ t1 = t1*t1
|
|
|
+ n1 = t1 * t1 * Dot2D(Gradients3D[gi1], x1, y1);
|
|
|
+ end
|
|
|
+
|
|
|
+ local t2 = 0.5 - x2*x2-y2*y2;
|
|
|
+ if (t2<0) then
|
|
|
+ n2 = 0.0;
|
|
|
+ else
|
|
|
+ t2 = t2*t2
|
|
|
+ n2 = t2 * t2 * Dot2D(Gradients3D[gi2], x2, y2);
|
|
|
+ end
|
|
|
+
|
|
|
+ local retval = 70.0 * (n0 + n1 + n2)
|
|
|
+
|
|
|
+ if simplex.internalCache then
|
|
|
+ if not Prev2D[xin] then Prev2D[xin] = {} end
|
|
|
+ Prev2D[xin][yin] = retval
|
|
|
+ end
|
|
|
+
|
|
|
+ return retval;
|
|
|
+end
|
|
|
+
|
|
|
+TileMan = TileManager.new()
|
|
|
+t = 0
|
|
|
+m = {x = 0, y = 0, l = false}
|
|
|
+last_time = 0
|
|
|
+fps = 60
|
|
|
+player = {x = -1000, y = 0}
|
|
|
+sspr = spr
|
|
|
+floor = math.floor
|
|
|
+
|
|
|
+show_map = false
|
|
|
+
|
|
|
+debug = true
|
|
|
+
|
|
|
+show_help = true
|
|
|
+help = {
|
|
|
+ [1] = 'SHIFT - Inspect tile (debug mode only)',
|
|
|
+ [2] = 'TAB - Toggle debug mode',
|
|
|
+ [3] = 'M - Toggle world map view',
|
|
|
+ [4] = 'H - Toggle this menu',
|
|
|
+}
|
|
|
+water_anim = 0
|
|
|
+dir = 1
|
|
|
+
|
|
|
+
|
|
|
+math.randomseed(666)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+offset = math.random(100000, 500000)
|
|
|
+simplex.seed()
|
|
|
+
|
|
|
+function get_sprite_pixel(sprite_id, x, y)
|
|
|
+ local byte = peek(0x04000 + sprite_id * 32 + y * 4 + math.floor(x / 2))
|
|
|
+ return x % 2 == 0 and byte % 16 or byte // 16
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+function set_sprite_pixel(sprite_id, x, y, color)
|
|
|
+ local addr = 0x04000 + sprite_id * 32 + y * 4 + math.floor(x / 2)
|
|
|
+ local byte = peek(addr)
|
|
|
+ if x % 2 == 0 then poke(addr, (byte - byte % 16) + color) else poke(addr, (color * 16) + byte % 16) end
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+function lerp(a,b,mu)
|
|
|
+ return a*(1-mu)+b*mu
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+local num_colors = 3
|
|
|
+local start_color = 8
|
|
|
+local tileSize = 8
|
|
|
+local tileCount = 1
|
|
|
+
|
|
|
+
|
|
|
+local amplitude = num_colors
|
|
|
+local frequency = 0.22
|
|
|
+local speed = 0.002
|
|
|
+
|
|
|
+
|
|
|
+function update_water_effect(time)
|
|
|
+ for sprite_id = 0, (tileCount * tileCount) - 1 do
|
|
|
+ for y = 0, tileSize - 1 do
|
|
|
+ for x = 0, tileSize - 1 do
|
|
|
+
|
|
|
+ local worldX = (sprite_id % tileCount) * tileSize + x
|
|
|
+ local worldY = math.floor(sprite_id / tileCount) * tileSize + y
|
|
|
+
|
|
|
+ local tileX = worldX % (tileSize * tileCount)
|
|
|
+ local tileY = worldY % (tileSize * tileCount)
|
|
|
+
|
|
|
+ local noiseValue = simplex.Noise2D(tileX * frequency, (tileY + time * speed) * frequency)
|
|
|
+
|
|
|
+ local color = math.floor(((noiseValue + 1) / 2) * amplitude) + start_color
|
|
|
+
|
|
|
+ set_sprite_pixel(224, x, y, color)
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function get_screen_cell(mouse_x, mouse_y)
|
|
|
+ local cam_x, cam_y = 116 - player.x, 64 - player.y
|
|
|
+ local mx = floor(cam_x) % 8
|
|
|
+ local my = floor(cam_y) % 8
|
|
|
+ return mouse_x - ((mouse_x - mx) % 8), mouse_y - ((mouse_y - my) % 8)
|
|
|
+end
|
|
|
+
|
|
|
+function get_world_cell(mouse_x, mouse_y)
|
|
|
+ local cam_x = player.x - 116
|
|
|
+ local cam_y = player.y - 64
|
|
|
+ local sub_tile_x = cam_x % 8
|
|
|
+ local sub_tile_y = cam_y % 8
|
|
|
+ local sx = floor((mouse_x + sub_tile_x) / 8)
|
|
|
+ local sy = floor((mouse_y + sub_tile_y) / 8)
|
|
|
+ local wx = floor(cam_x / 8) + sx + 1
|
|
|
+ local wy = floor(cam_y / 8) + sy + 1
|
|
|
+ return TileMan.tiles[wy][wx], wx, wy
|
|
|
+end
|
|
|
+
|
|
|
+function clamp(value, min, max)
|
|
|
+ return math.min(math.max(min, value), max)
|
|
|
+end
|
|
|
+
|
|
|
+function draw_debug(data, x, y)
|
|
|
+ if debug then
|
|
|
+ local width = 4
|
|
|
+ local height = #data * 7
|
|
|
+ for i = 1, #data do
|
|
|
+ local length = print(data[i], 2, -10, 2, false, 1, true)
|
|
|
+ if length > width then width = length + 4 end
|
|
|
+ end
|
|
|
+ x, y = clamp(x, 0, 240 - width), clamp(y, 0, 136 - height)
|
|
|
+ rectb(x, y, width, height, 10)
|
|
|
+ rect(x + 1, y + 1, width -2, height - 2, 8)
|
|
|
+ for i = 1, #data do
|
|
|
+ print(data[i], x + 2, i*6 - 4 + y, 11, false, 1, true)
|
|
|
+ end
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function draw_tile_widget(x, y)
|
|
|
+ local mx, my = mouse()
|
|
|
+ local tile, wx, wy = get_world_cell(mx, my)
|
|
|
+ local sx, sy = get_screen_cell(x, y)
|
|
|
+ local type = tile.ore and ores[tile.ore].name or tile.is_land and 'Land' or 'Water'
|
|
|
+ local biome = tile.is_land and biomes[tile.biome].name or 'Ocean'
|
|
|
+ if tile.is_tree then
|
|
|
+ rectb(sx + tile.offset.x - 9, sy + tile.offset.y - 26, 24, 32, 4)
|
|
|
+ end
|
|
|
+ local info = {
|
|
|
+ 'Sprite: ' .. (tile.ore and tostring(ores[tile.ore].tile_id) or tile.is_land and tostring(tile.sprite_id) or 224),
|
|
|
+ 'Type: ' .. type,
|
|
|
+ 'Biome: ' .. biome,
|
|
|
+ 'Coords: ' .. tostring(wx) .. ',' .. tostring(wy),
|
|
|
+ }
|
|
|
+ if tile.is_tree then info[4] = 'Tree' end
|
|
|
+ draw_text_window(info, x, y)
|
|
|
+end
|
|
|
+
|
|
|
+function draw_text_window(data, x, y, fg, bg, text_color)
|
|
|
+ fg, bg, text = fg or 9, bg or 8, text_color or 4
|
|
|
+ local width = 0
|
|
|
+ local height = #data * 7 + 3
|
|
|
+ for i = 1, #data do
|
|
|
+ local string_width = print(data[i], 0, -10, 0, false, 1, true)
|
|
|
+ if string_width > width then width = string_width end
|
|
|
+ end
|
|
|
+ width = width + 4
|
|
|
+ x, y = clamp(x, 1, 240 - width - 1), clamp(y, 1, 136 - height - 1)
|
|
|
+ rectb(x, y, width, height, fg)
|
|
|
+ rect(x + 1, y + 1, width - 2, height - 2, bg)
|
|
|
+ for i = 1, #data do
|
|
|
+ print(data[i], x + 1, y - 5 + i*7, 0, false, 1, true)
|
|
|
+ print(data[i], x + 2, y - 5 + i*7, text, false, 1, true)
|
|
|
+ end
|
|
|
+end
|
|
|
+
|
|
|
+function save_map()
|
|
|
+ local tile1, wx, wy = get_world_cell(player.x, player.y)
|
|
|
+ local start_x, start_y = wx - 120, wy - 68
|
|
|
+ for y = 0, 135 do
|
|
|
+ for x = 0, 239 do
|
|
|
+ local tile = TileMan.tiles[start_y + y][start_x + x]
|
|
|
+ if not tile.visited and tile.is_land then AutoMap(start_x + x, start_y + y) end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ for y = 0, 135 do
|
|
|
+ for x = 0, 239 do
|
|
|
+ local tile = TileMan.tiles[start_y + y][start_x + x]
|
|
|
+ mset(x, y, tile.sprite_id)
|
|
|
+ end
|
|
|
+ end
|
|
|
+ sync(4, 0, true)
|
|
|
+end
|
|
|
+
|
|
|
+function TIC()
|
|
|
+ local start_time = time()
|
|
|
+ cls(0)
|
|
|
+ if t % 2 == 0 then
|
|
|
+ update_water_effect(time())
|
|
|
+ end
|
|
|
+ t = t + 1
|
|
|
+ if t % 6 == 0 then
|
|
|
+ water_anim = water_anim + 1
|
|
|
+ if water_anim > 3 then water_anim = 0 end
|
|
|
+ end
|
|
|
+
|
|
|
+ poke(0x3FFB, 341)
|
|
|
+
|
|
|
+ local x, y, left = mouse()
|
|
|
+
|
|
|
+ if key(23) or btn(0) then player.y = player.y - (show_map and 10 or 5) end
|
|
|
+ if key(19) or btn(1) then player.y = player.y + (show_map and 10 or 5) end
|
|
|
+ if key( 1) or btn(2) then player.x = player.x - (show_map and 10 or 5) end
|
|
|
+ if key( 4) or btn(3) then player.x = player.x + (show_map and 10 or 5) end
|
|
|
+ if keyp(49) then debug = not debug end
|
|
|
+ if keyp(13) then show_map = not show_map end
|
|
|
+ if keyp(37) then frequency = frequency - 0.01 end
|
|
|
+ if keyp(38) then frequency = frequency + 0.01 end
|
|
|
+ if keyp(8) then show_help = not show_help end
|
|
|
+
|
|
|
+ if show_map then
|
|
|
+ TileMan:draw_worldmap(player)
|
|
|
+ else
|
|
|
+
|
|
|
+ TileMan:draw_terrain(player, 31, 18)
|
|
|
+ TileMan:draw_clutter(player, 32, 21)
|
|
|
+ end
|
|
|
+
|
|
|
+ local tile, wx, wy = get_world_cell(x, y)
|
|
|
+ local sx, sy = get_screen_cell(x, y)
|
|
|
+ if not show_map then
|
|
|
+ sspr(288, sx, sy, 0)
|
|
|
+ end
|
|
|
+
|
|
|
+ if debug then
|
|
|
+ local frame_time = floor(time() - start_time)
|
|
|
+ local total_frame_time = floor(time() - last_time)
|
|
|
+ draw_text_window({'Frame Time: ' .. frame_time .. 'ms', 'FPS: ' .. floor(1.0/total_frame_time * 1000)}, 2, 2)
|
|
|
+ sspr(320, 116 - 8, 64, 0, 1, 0, 0, 2, 1)
|
|
|
+ end
|
|
|
+
|
|
|
+ if key(64) then draw_tile_widget(x + 5, y + 8) end
|
|
|
+ if key(63) and keyp(20) then sync(0, 0, true) end
|
|
|
+ if show_help then draw_text_window(help, 1, 25) end
|
|
|
+ m.x, m.y, m.l = x, y, left
|
|
|
+ if keyp(16) then
|
|
|
+ save_map()
|
|
|
+ end
|
|
|
+ last_time = time()
|
|
|
+end
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|