diff --git a/lib/texture.lua b/lib/texture.lua index 67a497c..81340f6 100644 --- a/lib/texture.lua +++ b/lib/texture.lua @@ -61,6 +61,8 @@ TEXTURES = { TOWER_RADAR_ICON = load_texture("tower_radar_icon.png"), TOWER_LIGHTHOUSE = load_texture("tower_lighthouse.png"), TOWER_LIGHTHOUSE_ICON = load_texture("tower_lighthouse_icon.png"), + TOWER_FARM = load_texture("farm2.png"), + TOWER_FARM_ICON = load_texture("farm2.png"), -- mob stuff MOB_BEEPER = load_texture("mob_beeper.png"), diff --git a/res/img/farm2.jpeg b/res/img/farm2.jpeg new file mode 100644 index 0000000..d0ca969 Binary files /dev/null and b/res/img/farm2.jpeg differ diff --git a/res/img/farm2.png b/res/img/farm2.png new file mode 100644 index 0000000..7d1eed5 Binary files /dev/null and b/res/img/farm2.png differ diff --git a/src/entity.lua b/src/entity.lua index d8c5dd9..5fd8efc 100644 --- a/src/entity.lua +++ b/src/entity.lua @@ -8,11 +8,16 @@ entity structure: update - function - runs every frame with itself and its index in some array as an argument node - node - scene graph node - should be initialized by caller after, though all entities have a node + z - number - z-index of the scene node, what layer should this node be rendered at? + we currently reserve z index 0 for just the 'floor', no towers or mobs or anything. + most things will set this to 1 (or leave it unset, 1 is the default) + we might use index -1 for underwater shit at some point + type - enum - sub type props - table - table of properties specific to this entity subtype } --]] -function make_basic_entity(hex, update_f, position) +function make_basic_entity(hex, update_f, position, z) local entity = {} entity.TOB = game_state.time @@ -30,6 +35,7 @@ function make_basic_entity(hex, update_f, position) end entity.update = update_f + entity.z = z or 1 entity.props = {} return entity @@ -37,7 +43,8 @@ end function register_entity(t, entity) table.insert(t, entity) - game_state.world:append(entity.node) + + game_state.world(world_layer_tag(entity.z)):append(entity.node) end -- |t| is the source table, probably game_state.mobs, game_state.towers, or game_state.projectiles diff --git a/src/game.lua b/src/game.lua index 6f361ef..2677a69 100644 --- a/src/game.lua +++ b/src/game.lua @@ -67,6 +67,7 @@ local game_scene_menu_options = { local function get_initial_game_state(seed) local STARTING_MONEY = 75 + --local STARTING_MONEY = 10000 local map = random_map(seed) local world = make_hex_grid_scene(map, true) @@ -122,7 +123,8 @@ local function get_top_right_display_text(hex, evenq, centered_evenq, display_ty str = table.tostring(hex_map_get(game_state.map, hex)) elseif display_type == TRDTS.MOUSE then - str = win:mouse_position() + local mouse = win:mouse_position() + str = mouse.x .. "," .. mouse.y .. " (mouse)" end return str end diff --git a/src/grid.lua b/src/grid.lua index 15fc750..e01d4e8 100644 --- a/src/grid.lua +++ b/src/grid.lua @@ -188,108 +188,116 @@ function map_elevation_to_color(elevation) end end -function make_hex_node(hex, tile, color) - if not color then - local evenq = hex_to_evenq(vec2(hex.x, hex.y)) - - -- light shading on edge cells - local mask = vec4(0, 0, 0, math.max(((evenq.x - HEX_GRID_WIDTH/2) / HEX_GRID_WIDTH) ^ 2 - , ((-evenq.y - HEX_GRID_HEIGHT/2) / HEX_GRID_HEIGHT) ^ 2)) - - color = map_elevation_to_color(tile.elevation) - mask +do + local s60 = math.sin(math.rad(60)) + local c60 = math.cos(math.rad(60)) + local radius = HEX_SIZE + + -- adds a pair of quads constructed to quads via quads:add_quad that draws a hexagon + function make_hex_quads_node(quads, position, color, uvs) + local p = position or vec2(0) + + quads:add_quad{ + vert = { + p.x - c60 * radius, p.y + s60 * radius, + p.x - radius, p.y, + p.x + radius, p.y, + p.x + c60 * radius, p.y + s60 * radius + }, + uv = am.vec2_array{ + vec2(0, 0), + vec2(0, 0.5), + vec2(1, 0.5), + vec2(1, 0) + }, + color = color or vec4(1), + } + quads:add_quad{ + vert = { + p.x - radius, p.y, + p.x - c60 * radius, p.y - s60 * radius, + p.x + c60 * radius, p.y - s60 * radius, + p.x + radius, p.y + }, + uv = am.vec2_array{ + vec2(0, 0.5), + vec2(0, 1), + vec2(1, 1), + vec2(1, 0.5) + }, + color = color or vec4(1), + } end - - return am.translate(hex_to_pixel(vec2(hex.x, hex.y), vec2(HEX_SIZE))) - ^ am.circle(vec2(0), HEX_SIZE, color, 6) end -function make_hex_grid_scene(map, do_generate_flow_field) - local world = am.group():tag"world" - local texture = TEXTURES.WHITE +local HEX_VSHADER_PROGRAM = [[ + precision highp float; - local quads = am.quads(map.size * 2, {"vert", "vec2", "uv", "vec2", "color", "vec4"}) - quads.usage = "static" -- see am.buffer documentation, hint to gpu - local prog = am.program([[ - precision highp float; + attribute vec2 uv; + attribute vec2 vert; + attribute vec4 color; - attribute vec2 uv; - attribute vec2 vert; - attribute vec4 color; + uniform mat4 MV; + uniform mat4 P; - uniform mat4 MV; - uniform mat4 P; + varying vec2 v_uv; + varying vec4 v_color; - varying vec2 v_uv; - varying vec4 v_color; + void main() { + v_uv = uv; + v_color = color; + gl_Position = P * MV * vec4(vert, 0.0, 1.0); + } +]] +local HEX_FSHADER_PROGRAM = [[ + precision mediump float; - void main() { - v_uv = uv; - v_color = color; - gl_Position = P * MV * vec4(vert, 0.0, 1.0); - } - ]], [[ - precision mediump float; + uniform sampler2D texture; - uniform sampler2D texture; + varying vec2 v_uv; + varying vec4 v_color; - varying vec2 v_uv; - varying vec4 v_color; + void main() { + gl_FragColor = texture2D(texture, v_uv) * v_color; + } +]] +function make_hex_shader_program_node() + return am.program(HEX_VSHADER_PROGRAM, HEX_FSHADER_PROGRAM) +end +function world_layer_tag(i) + return string.format("layer-%d", i) +end +function make_hex_grid_scene(map, do_generate_flow_field) + local world = am.group():tag"world" - void main() { - gl_FragColor = texture2D(texture, v_uv) * v_color; - } - ]]) + for i = 0, 10 do + world:append(am.group():tag(world_layer_tag(i))) + end + + local floor = world(world_layer_tag(0)) + local quads = am.quads(map.size * 2, {"vert", "vec2", "uv", "vec2", "color", "vec4"}) + quads.usage = "static" -- see am.buffer documentation, hint to gpu + local prog = make_hex_shader_program_node() - local s60 = math.sin(math.rad(60)) - local c60 = math.cos(math.rad(60)) for i,_ in pairs(map) do for j,tile in pairs(map[i]) do local v = vec2(i, j) local p = hex_to_pixel(v) - local d = math.distance(p, vec2(0)) -- distance to center + local d = math.distance(p, hex_to_pixel(HEX_GRID_CENTER)) -- distance to center -- light shading on edge cells, scaled by distance to center - local mask = vec4(0, 0, 0, 1/d) + local mask = vec4(d/(HEX_GRID_PIXEL_WIDTH * 6)) local color = map_elevation_to_color(tile.elevation) - mask - local radius = HEX_SIZE - quads:add_quad{ - vert = { - p.x - c60 * radius, p.y + s60 * radius, - p.x - radius, p.y, - p.x + radius, p.y, - p.x + c60 * radius, p.y + s60 * radius - }, - uv = am.vec2_array{ - vec2(0, 0), - vec2(1, 0), - vec2(1, 1), - vec2(0, 1) - }, - color = color, - } - quads:add_quad{ - vert = { - p.x - radius, p.y, - p.x - c60 * radius, p.y - s60 * radius, - p.x + c60 * radius, p.y - s60 * radius, - p.x + radius, p.y - }, - uv = am.vec2_array{ - vec2(0, 0), - vec2(1, 0), - vec2(1, 1), - vec2(0, 1) - }, - color = color, - } + make_hex_quads_node(quads, p, color) end end - world:append(am.blend("alpha") ^ am.use_program(prog) ^ am.bind{ texture = texture } ^ quads) + local texture = TEXTURES.WHITE + floor:append((am.blend("alpha") ^ am.use_program(prog) ^ am.bind{ texture = texture } ^ quads)) -- add the magenta diamond that represents 'home' - world:append( + floor:append( am.translate(hex_to_pixel(HEX_GRID_CENTER, vec2(HEX_SIZE))) ^ pack_texture_into_sprite(TEXTURES.GEM1, HEX_SIZE, HEX_SIZE*1.1) ) diff --git a/src/tower.lua b/src/tower.lua index de9af62..291a5a5 100644 --- a/src/tower.lua +++ b/src/tower.lua @@ -84,13 +84,16 @@ function init_tower_specs() local lines = am.rotate(math.rad(-30)) ^ am.group() for i,n in pairs(hex_neighbours(hex)) do - local no_towers_adjacent = true + local no_walls_adjacent = true for _,t in pairs(towers_on_hex(n)) do - no_towers_adjacent = false + if t.type == TOWER_TYPE.WALL then + no_walls_adjacent = false + break + end end - if no_towers_adjacent then + if no_walls_adjacent then local p1 = hex_corner_offset(vec2(0), i) local j = i == 6 and 1 or i + 1 local p2 = hex_corner_offset(vec2(0), j) @@ -112,6 +115,7 @@ function init_tower_specs() texture = TEXTURES.TOWER_GATTLER, icon_texture = TEXTURES.TOWER_GATTLER_ICON, cost = 20, + height = 2, weapons = { { projectile_type = PROJECTILE_TYPE.BULLET, @@ -161,6 +165,7 @@ function init_tower_specs() texture = TEXTURES.TOWER_HOWITZER, icon_texture = TEXTURES.TOWER_HOWITZER_ICON, cost = 50, + height = 2, weapons = { { projectile_type = PROJECTILE_TYPE.SHELL, @@ -242,6 +247,7 @@ function init_tower_specs() texture = TEXTURES.TOWER_REDEYE, icon_texture = TEXTURES.TOWER_REDEYE_ICON, cost = 75, + height = 2, weapons = { { projectile_type = PROJECTILE_TYPE.LASER, @@ -299,6 +305,7 @@ function init_tower_specs() cost = 150, range = 7, fire_rate = 1, + height = 2, make_node_f = function(self) return am.group( make_tower_sprite(self), @@ -362,6 +369,27 @@ function init_tower_specs() end end end + }, + { + id = "FARM", + name = "Farm", + placement_rules_text = "Place on Ground", + short_description = "Increases income gained over time. Mobs can trample farms, reducing their income (never completely nullifying it).", + texture = TEXTURES.TOWER_FARM, + icon_texture = TEXTURES.TOWER_FARM_ICON, + cost = 50, + size = 2, + height = 0, + make_node_f = function(self) + local quads = am.quads(2*7, {"vert", "vec2", "uv", "vec2", "color", "vec4"}) + + local map = hex_spiral_map(vec2(0), 1) + for _,h in pairs(map) do + make_hex_quads_node(quads, hex_to_pixel(h)) + end + + return am.blend("alpha") ^ am.use_program(make_hex_shader_program_node()) ^ am.bind{ texture = TEXTURES.TOWER_FARM } ^ quads + end } } @@ -516,6 +544,8 @@ function tower_type_is_buildable_on(hex, tile, tower_type) local tower_spec = get_tower_spec(tower_type) for _,h in pairs(hex_spiral_map(hex, get_tower_size(tower_type) - 1)) do + if h == HEX_GRID_CENTER then return false end + table.merge(blocking_towers, towers_on_hex(h)) table.merge(blocking_mobs, mobs_on_hex(h)) @@ -551,7 +581,7 @@ function make_and_register_tower(hex, tower_type) table.merge(tower, spec) tower.type = tower_type - tower.node = am.translate(tower.position) ^ tower.make_node_f(tower, hex, true) + tower.node = am.translate(tower.position) ^ tower.make_node_f(tower, hex) -- initialize each weapons' last shot time to the negation of the fire rate - -- this lets the tower fire immediately upon being placed @@ -577,7 +607,6 @@ function build_tower(hex, tower_type) -- check for that now for _,t in pairs(game_state.towers) do if t ~= tower and t.type == TOWER_TYPE.WALL then - log('replacin') t.node:replace("group", t.make_node_f(t, t.hex)) end end