diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 1572c51..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index fc5f9c0..6e886fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ bin/ +.DS_Store log.txt diff --git a/color.lua b/color.lua index b1c1072..1646edb 100644 --- a/color.lua +++ b/color.lua @@ -6,7 +6,7 @@ COLORS = { -- tones WHITE = vec4(0.8, 0.8, 0.7, 1), BLACK = vec4(0, 0, 0.02, 1), - VERY_DARK_GRAY = vec4(45/255, 45/255, 35/255, 1), + VERY_DARK_GRAY = vec4(35/255, 35/255, 25/255, 1), TRUE_BLACK = vec4(0, 0, 0, 1), -- non-standard hues diff --git a/main.lua b/main.lua index 018ff0f..9fea7ce 100644 --- a/main.lua +++ b/main.lua @@ -5,6 +5,7 @@ math.random() math.random() math.random() + -- Globals WIN = am.window{ width = 1920, @@ -14,7 +15,9 @@ WIN = am.window{ letterbox = true } --- assets/non-or-trivial code +STATE = {} -- @TODO move state in here + +-- assets and/or trivial code require "color" require "sound" require "texture" @@ -24,7 +27,7 @@ require "src/extra" require "src/geometry" require "src/hexyz" require "src/grid" -WIN.clear_color = color_at(0) +require "src/gui" require "src/mob" require "src/projectile" require "src/tower" @@ -36,6 +39,8 @@ PERF_STATS = false -- result of am.perf_stats() -- should be calle WORLD = false -- root scene node of everything considered to be in the game world -- aka non gui stuff +HEX_CURSOR = false + TIME = 0 -- runtime of the current game in seconds (not whole program runtime) SCORE = 0 -- score of the player STARTING_MONEY = 50 @@ -89,6 +94,7 @@ local function game_action(scene) do_entity_updates() do_mob_spawning() + do_gui_updates() if WIN:mouse_pressed"left" then if hot and can_do_build(hex, tile, SELECTED_TOWER_TYPE) then @@ -96,23 +102,29 @@ local function game_action(scene) end end + --[[ if WIN:mouse_pressed"middle" then - WIN.scene"scale".scale2d = vec2(1) + WORLD"scale".scale2d = vec2(1) else - local mwd = vec2(WIN:mouse_wheel_delta().y / 1000) - WIN.scene"scale".scale2d = WIN.scene"scale".scale2d + mwd - WIN.scene"scale".scale2d = WIN.scene"scale".scale2d + mwd + local mwd = vec2(WIN:mouse_wheel_delta().y / 500) + WORLD"scale".scale2d = WORLD"scale".scale2d + mwd + WORLD"scale".scale2d = WORLD"scale".scale2d + mwd end + ]] if WIN:key_pressed"escape" then WIN.scene"game".paused = true + WIN.scene:append(am.group{ + am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRANSPARENT), + am.scale(3) ^ am.text("Paused.\nEscape to Resume", COLORS.BLACK) + }:tag"pause_menu") WIN.scene:action(function() if WIN:key_pressed"escape" then + WIN.scene:remove"pause_menu" WIN.scene"game".paused = false return true end end) - --game_end() elseif WIN:key_pressed"f1" then TRDT = (TRDT + 1) % #table.keys(TRDTS) @@ -143,9 +155,9 @@ local function game_action(scene) end if tile and hot then - WIN.scene"hex_cursor".center = rounded_mouse + HEX_CURSOR.center = rounded_mouse else - WIN.scene"hex_cursor".center = OFF_SCREEN + HEX_CURSOR.center = OFF_SCREEN end WIN.scene"score".text = string.format("SCORE: %.2f", SCORE) @@ -197,113 +209,22 @@ function game_end() WIN.scene = am.group(am.scale(1) ^ game_scene()) end -function update_score(diff) - SCORE = SCORE + diff -end - -function update_money(diff) - MONEY = MONEY + diff -end - -function get_tower_tooltip_text(tower_type) - return string.format( - "%s\n%s\n%s\ncost: %d" - , get_tower_name(tower_type) - , get_tower_placement_rules_text(tower_type) - , get_tower_short_description(tower_type) - , get_tower_base_cost(tower_type) - ) -end +function update_score(diff) SCORE = SCORE + diff end +function update_money(diff) MONEY = MONEY + diff end -local function toolbelt() - -- init the toolbelt - local toolbelt_height = hex_height(HEX_SIZE) * 2 - local toolbelt = am.group{ - am.translate(WIN.left + 10, WIN.bottom + toolbelt_height + 20) - ^ am.text(get_tower_tooltip_text(SELECTED_TOWER_TYPE), "left", "bottom"):tag"tower_tooltip", - am.rect(WIN.left, WIN.bottom, WIN.right, WIN.bottom + toolbelt_height, COLORS.TRANSPARENT) - }:tag"toolbelt" - - local padding = 15 - local size = toolbelt_height - padding - local half_size = size/2 - local offset = vec2(WIN.left + padding*3, WIN.bottom + padding/3) - local tab_button = am.translate(vec2(0, half_size) + offset) ^ am.group{ - pack_texture_into_sprite(TEXTURES.WIDER_BUTTON1, 54, 32), - pack_texture_into_sprite(TEXTURES.TAB_ICON, 25, 25) - } - toolbelt:append(tab_button) - local tower_select_square = ( - am.translate(vec2(size + padding, half_size) + offset) - ^ am.rect(-size/2-3, -size/2-3, size/2+3, size/2+3, COLORS.SUNRAY) - ):tag"tower_select_square" - toolbelt:append(tower_select_square) - - -- fill in the other tower options - local tower_type_values = { - TOWER_TYPE.REDEYE, - TOWER_TYPE.LIGHTHOUSE, - TOWER_TYPE.WALL, - TOWER_TYPE.MOAT - } - local keys = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=' } - for i = 1, #keys do - if tower_type_values[i] then - toolbelt:append( - am.translate(vec2(size + padding, 0) * i + offset) - ^ am.group{ - am.translate(0, half_size) - ^ pack_texture_into_sprite(TEXTURES.BUTTON1, size, size), - - am.translate(0, half_size) - ^ pack_texture_into_sprite(get_tower_texture(tower_type_values[i]), size, size), - - am.translate(vec2(half_size)) - ^ am.group{ - pack_texture_into_sprite(TEXTURES.BUTTON1, half_size, half_size), - am.scale(2) - ^ am.text(keys[i], COLORS.BLACK) - } - } - ) - else - toolbelt:append( - am.translate(vec2(size + padding, 0) * i + offset) - ^ am.group{ - am.translate(0, half_size) - ^ pack_texture_into_sprite(TEXTURES.BUTTON1, size, size), - - am.translate(vec2(half_size)) - ^ am.group{ - pack_texture_into_sprite(TEXTURES.BUTTON1, half_size, half_size), - am.scale(2) - ^ am.text(keys[i], COLORS.BLACK) - } - } - ) - end +function draw_hex_cursor(map, color) + local group = am.group() + for _,h in pairs(map) do + group:append(am.circle(hex_to_pixel(h), HEX_SIZE, color, 6)) end - - select_tower_type = function(tower_type) - SELECTED_TOWER_TYPE = tower_type - if TOWER_SPECS[SELECTED_TOWER_TYPE] then - WIN.scene"tower_tooltip".text = get_tower_tooltip_text(tower_type) - local new_position = vec2((size + padding) * tower_type, size/2) + offset - WIN.scene"tower_select_square":action(am.tween(0.1, { position2d = new_position })) - - WIN.scene:action(am.play(am.sfxr_synth(SOUNDS.SELECT1), false, 1, SFX_VOLUME)) - end - end - - return toolbelt + return group end --- @NOTE must be global to allow the game_action to reference it function game_scene() local score = am.translate(WIN.left + 10, WIN.top - 20) ^ am.text("", "left"):tag"score" local money = am.translate(WIN.left + 10, WIN.top - 40) ^ am.text("", "left"):tag"money" local coords = am.translate(WIN.right - 10, WIN.top - 20) ^ am.text("", "right", "top"):tag"coords" - local hex_cursor = am.circle(OFF_SCREEN, HEX_SIZE, COLORS.TRANSPARENT, 6):tag"hex_cursor" + HEX_CURSOR = am.circle(OFF_SCREEN, HEX_SIZE, COLORS.TRANSPARENT, 6):tag"hex_cursor" local curtain = am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRUE_BLACK) curtain:action(coroutine.create(function() @@ -317,7 +238,7 @@ function game_scene() local scene = am.group{ WORLD, curtain, - hex_cursor, + HEX_CURSOR, toolbelt(), score, money, @@ -330,6 +251,6 @@ function game_scene() return scene end -WIN.scene = am.group(am.scale(vec2(1)) ^ game_scene()) +WIN.scene = am.group(game_scene()) noglobals() diff --git a/res/.DS_Store b/res/.DS_Store deleted file mode 100644 index a777cea..0000000 Binary files a/res/.DS_Store and /dev/null differ diff --git a/res/tower_lighthouse.png b/res/tower_lighthouse.png index 42ea3d4..225eccb 100644 Binary files a/res/tower_lighthouse.png and b/res/tower_lighthouse.png differ diff --git a/res/tower_moat.png b/res/tower_moat.png index 7a9701c..5f08535 100644 Binary files a/res/tower_moat.png and b/res/tower_moat.png differ diff --git a/res/tower_redeye.png b/res/tower_redeye.png index 255337e..f0021cb 100644 Binary files a/res/tower_redeye.png and b/res/tower_redeye.png differ diff --git a/res/tower_wall.png b/res/tower_wall.png index e43af90..982d765 100644 Binary files a/res/tower_wall.png and b/res/tower_wall.png differ diff --git a/src/entity.lua b/src/entity.lua index 16b8aa2..c39f234 100644 --- a/src/entity.lua +++ b/src/entity.lua @@ -1,9 +1,5 @@ -MOBS = {} -TOWERS = {} -PROJECTILES = {} - --[[ entity structure: { @@ -12,6 +8,8 @@ entity structure: position - vec2 - current pixel position of it's translate (forced parent) node update - function - runs every frame with itself and its index as an argument node - node - scene graph node + + ... - any - a bunch of other shit depending on what entity type it is } --]] function make_basic_entity(hex, node, update, position) @@ -51,34 +49,14 @@ function delete_entity(t, index) end function delete_all_entities() - for mob_index,mob in pairs(MOBS) do - if mob then delete_entity(MOBS, mob_index) end - end - for tower_index,tower in pairs(TOWERS) do - if tower then delete_entity(TOWERS, tower_index) end - end - for projectile_index,projectile in pairs(PROJECTILES) do - if projectile then delete_entity(PROJECTILES, projectile_index) end - end + delete_all_mobs() + delete_all_towers() + delete_all_projetiles() end function do_entity_updates() - --if WIN:key_down"space" then - for mob_index,mob in pairs(MOBS) do - if mob and mob.update then - mob.update(mob, mob_index) - end - end - for tower_index,tower in pairs(TOWERS) do - if tower and tower.update then - tower.update(tower, tower_index) - end - end - for projectile_index,projectile in pairs(PROJECTILES) do - if projectile and projectile.update then - projectile.update(projectile, projectile_index) - end - end - --end + do_mob_updates() + do_tower_updates() + do_projectile_updates() end diff --git a/src/grid.lua b/src/grid.lua index 40481e6..4fec704 100644 --- a/src/grid.lua +++ b/src/grid.lua @@ -7,8 +7,8 @@ HEX_PIXEL_WIDTH = hex_width(HEX_SIZE, ORIENTATION.FLAT) HEX_PIXEL_HEIGHT = hex_height(HEX_SIZE, ORIENTATION.FLAT) HEX_PIXEL_DIMENSIONS = vec2(HEX_PIXEL_WIDTH, HEX_PIXEL_HEIGHT) --- with 1920x1080, this is the minimal dimensions to cover the screen (65x33) --- @NOTE added 2 cell padding, because we terraform the very outer edge and it looks ugly +-- with 1920x1080, the minimal dimensions to cover the screen is 65x33 +-- added 2 cell padding, because we terraform the very outer edge and it looks ugly, so hide it -- odd numbers are important because we want a 'true' center HEX_GRID_WIDTH = 67 HEX_GRID_HEIGHT = 35 @@ -91,14 +91,9 @@ function grid_cost(map, from, to) end function generate_and_apply_flow_field(map, start, world) - local flow - if false then - flow = flow_field(map, start, world) - else - flow = dijkstra(map, start, nil, grid_cost) - end + local flow = dijkstra(map, start, nil, grid_cost) - local flow_field_hidden = world and world"flow_field" and world"flow_field".hidden + local flow_field_hidden = world and world"flow_field" and world"flow_field".hidden or true if world and world"flow_field" then world:remove"flow_field" end @@ -112,8 +107,7 @@ function generate_and_apply_flow_field(map, start, world) overlay_group:append(am.translate(hex_to_pixel(vec2(i, j))) ^ am.text(string.format("%.1f", f.priority * 10))) else - -- should fire exactly once per goal hex - -- log('no priority') + -- should fire exactly once end end end @@ -134,6 +128,7 @@ function random_map(seed) -- the world's appearance relies largely on a backdrop which can be scaled in -- tone to give the appearance of light or darkness + -- @NOTE replace this with a shader program local neg_mask = am.rect(0, 0, HEX_GRID_PIXEL_WIDTH, HEX_GRID_PIXEL_HEIGHT, COLORS.TRUE_BLACK):tag"negative_mask" local world = am.group(neg_mask):tag"world" @@ -180,7 +175,7 @@ function random_map(seed) getmetatable(map).__index.neighbours = function(hex) return table.filter(hex_neighbours(hex), function(_hex) local tile = map.get(_hex.x, _hex.y) - return tile and tile.elevation > -0.5 and tile.elevation <= 0.5 + return tile and tile_is_medium_elevation(tile) end) end diff --git a/src/gui.lua b/src/gui.lua index 99f2b9d..580ead5 100644 --- a/src/gui.lua +++ b/src/gui.lua @@ -12,8 +12,8 @@ function set_hot(id) if not active then hot = { id = id } end end -function register_button_widget(id, rect) - register_widget(id, function() +function register_button_widget(id, rect, onclick) + register_widget(id, function(i) local click = false if active and active.id == id then @@ -27,23 +27,107 @@ function register_button_widget(id, rect) if point_in_rect(WIN:mouse_position(), rect) then set_hot(id) end - return click + if click then onclick() end end) end -function make_button_widget(id, position, dimensions, text) - local rect = am.rect( - -dimensions.x/2, - dimensions.y/2, - dimensions.x/2, - -dimensions.y/2, - vec4(1, 0, 0, 1) - ) +function do_gui_updates() + for i,w in pairs(widgets) do + w.poll(i) + end +end - register_button_widget(id, rect) - return am.group{ - rect, - am.text(text) - }:tag(id) +local function get_tower_tooltip_text(tower_type) + return string.format( + "%s\n%s\n%s\ncost: %d" + , get_tower_name(tower_type) + , get_tower_placement_rules_text(tower_type) + , get_tower_short_description(tower_type) + , get_tower_base_cost(tower_type) + ) end +function toolbelt() + local function button(size, half_size, tower_texture, padding, i, offset, key_name) + local x1 = (size + padding) * i + offset.x + local y1 = offset.y + local x2 = (size + padding) * i + offset.x + size + local y2 = offset.y + size + + register_button_widget("toolbelt_tower_button" .. i, am.rect(x1, y1, x2, y2), function() select_tower_type(i) end) + + return am.translate(vec2(size + padding, 0) * i + offset) + ^ am.group{ + am.translate(0, half_size) + ^ pack_texture_into_sprite(TEXTURES.BUTTON1, size, size), + + am.translate(0, half_size) + ^ pack_texture_into_sprite(tower_texture, size, size), + + am.translate(vec2(half_size)) + ^ am.group{ + pack_texture_into_sprite(TEXTURES.BUTTON1, half_size, half_size), + am.scale(2) + ^ am.text(key_name, COLORS.BLACK) + } + } + end + + -- init the toolbelt + local toolbelt_height = hex_height(HEX_SIZE) * 2 + local toolbelt = am.group{ + am.translate(WIN.left + 10, WIN.bottom + toolbelt_height + 20) + ^ am.text(get_tower_tooltip_text(SELECTED_TOWER_TYPE), "left", "bottom"):tag"tower_tooltip", + am.rect(WIN.left, WIN.bottom, WIN.right, WIN.bottom + toolbelt_height, COLORS.TRANSPARENT) + }:tag"toolbelt" + + local padding = 15 + local size = toolbelt_height - padding + local half_size = size/2 + local offset = vec2(WIN.left + padding*3, WIN.bottom + padding/3) + local tab_button = am.translate(vec2(0, half_size) + offset) ^ am.group{ + pack_texture_into_sprite(TEXTURES.WIDER_BUTTON1, 54, 32), + pack_texture_into_sprite(TEXTURES.TAB_ICON, 25, 25) + } + toolbelt:append(tab_button) + local tower_select_square = ( + am.translate(vec2(size + padding, half_size) + offset) + ^ am.rect(-size/2-3, -size/2-3, size/2+3, size/2+3, COLORS.SUNRAY) + ):tag"tower_select_square" + toolbelt:append(tower_select_square) + + -- fill in the other tower options + local tower_type_values = { + TOWER_TYPE.REDEYE, + TOWER_TYPE.LIGHTHOUSE, + TOWER_TYPE.WALL, + TOWER_TYPE.MOAT + } + local keys = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=' } + for i = 1, #keys do + toolbelt:append( + button( + size, + half_size, + get_tower_texture(tower_type_values[i]), + padding, + i, + offset, + keys[i] + ) + ) + end + + select_tower_type = function(tower_type) + SELECTED_TOWER_TYPE = tower_type + if TOWER_SPECS[SELECTED_TOWER_TYPE] then + WIN.scene"tower_tooltip".text = get_tower_tooltip_text(tower_type) + local new_position = vec2((size + padding) * tower_type, size/2) + offset + WIN.scene"tower_select_square":action(am.tween(0.1, { position2d = new_position })) + + WIN.scene:action(am.play(am.sfxr_synth(SOUNDS.SELECT1), false, 1, SFX_VOLUME)) + end + end + + return toolbelt +end diff --git a/src/mob.lua b/src/mob.lua index 0294e92..013f423 100644 --- a/src/mob.lua +++ b/src/mob.lua @@ -1,14 +1,6 @@ ---[[ -mob(entity) structure: -{ - path - 2d table - map of hexes to other hexes, forms a path - speed - number - multiplier on distance travelled per frame, up to the update function to use correctly - bounty - number - score bonus you get when this mob is killed - hurtbox_radius - number - -} ---]] +MOBS = {} MAX_MOB_SIZE = hex_height(HEX_SIZE, ORIENTATION.FLAT) / 2 MOB_SIZE = MAX_MOB_SIZE @@ -33,7 +25,7 @@ end -- check if a the tile at |hex| is passable by |mob| function mob_can_pass_through(mob, hex) local tile = HEX_MAP.get(hex.x, hex.y) - return tile and tile.elevation <= 0.5 and tile.elevation > -0.5 + return tile and tile_is_medium_elevation(tile) end function mob_die(mob, mob_index) @@ -143,12 +135,6 @@ local function update_mob(mob, mob_index) if mob.frame_target and mob.frame_target == last_frame_hex then --log('backpedaling') - -- backpedaling or failing to find anywhere to go, run Astar and hope it works - --local made_it - --mob.path, made_it = Astar(HEX_MAP, mob.hex, HEX_GRID_CENTER, grid_heuristic, grid_cost) - --if not made_it then - -- log('stuck!') - --end end -- do movement @@ -187,7 +173,7 @@ local function make_and_register_mob(mob_type) register_entity(MOBS, mob) end -local SPAWN_CHANCE = 25 +local SPAWN_CHANCE = 45 function do_mob_spawning() --if WIN:key_pressed"space" then if math.random(SPAWN_CHANCE) == 1 then @@ -196,3 +182,17 @@ function do_mob_spawning() end end +function delete_all_mobs() + for mob_index,mob in pairs(MOBS) do + if mob then delete_entity(MOBS, mob_index) end + end +end + +function do_mob_updates() + for mob_index,mob in pairs(MOBS) do + if mob and mob.update then + mob.update(mob, mob_index) + end + end +end + diff --git a/src/projectile.lua b/src/projectile.lua index 19b8187..2a823e3 100644 --- a/src/projectile.lua +++ b/src/projectile.lua @@ -1,16 +1,8 @@ ---[[ -bullet/projectile(entity) structure -{ - vector - vec2 - normalized vector of the current direction of this projectile - velocity - number - multplier on distance travelled per frame - damage - number - guess - hitbox_radius - number - hitboxes are circles -} ---]] +PROJECTILES = {} -function update_projectile(projectile, projectile_index) +local function update_projectile(projectile, projectile_index) projectile.position = projectile.position + projectile.vector * projectile.velocity projectile.node.position2d = projectile.position projectile.hex = pixel_to_hex(projectile.position) @@ -80,3 +72,17 @@ function make_and_register_projectile(hex, vector, velocity, damage, hitbox_radi register_entity(PROJECTILES, projectile) end +function delete_all_projectiles() + for projectile_index,projectile in pairs(PROJECTILES) do + if projectile then delete_entity(PROJECTILES, projectile_index) end + end +end + +function do_projectile_updates() + for projectile_index,projectile in pairs(PROJECTILES) do + if projectile and projectile.update then + projectile.update(projectile, projectile_index) + end + end +end + diff --git a/src/tower.lua b/src/tower.lua index 26fd029..f1bf01e 100644 --- a/src/tower.lua +++ b/src/tower.lua @@ -1,5 +1,7 @@ +TOWERS = {} + TOWER_TYPE = { REDEYE = 1, LIGHTHOUSE = 2, @@ -72,6 +74,34 @@ local function make_tower_sprite(tower_type) return pack_texture_into_sprite(get_tower_texture(tower_type), HEX_PIXEL_WIDTH, HEX_PIXEL_HEIGHT) end +local function make_tower_node(tower_type) + if tower_type == TOWER_TYPE.REDEYE then + return make_tower_sprite(tower_type) + + elseif tower_type == TOWER_TYPE.LIGHTHOUSE then + return am.group( + make_tower_sprite(tower_type) + ) + elseif tower_type == TOWER_TYPE.WALL then + return am.circle(vec2(0), HEX_SIZE, COLORS.VERY_DARK_GRAY, 6) + + elseif tower_type == TOWER_TYPE.MOAT then + return am.circle(vec2(0), HEX_SIZE, (COLORS.WATER){a=1}, 6) + + end +end + +function towers_on_hex(hex) + local t = {} + for tower_index,tower in pairs(TOWERS) do + if tower and tower.hex == hex then + table.insert(t, tower_index, tower) + end + end + return t +end + + function tower_on_hex(hex) return table.find(TOWERS, function(tower) return tower.hex == hex @@ -81,9 +111,24 @@ end function tower_is_buildable_on(hex, tile, tower_type) if hex == HEX_GRID_CENTER then return false end - local blocked = tower_on_hex(hex) or #mobs_on_hex(hex) ~= 0 + local blocking_towers = towers_on_hex(hex) + local blocking_mobs = mobs_on_hex(hex) + + local towers_blocking = #blocking_towers ~= 0 + local mobs_blocking = #blocking_mobs ~= 0 + + local blocked = mobs_blocking or towers_blocking if tower_type == TOWER_TYPE.REDEYE then + if not mobs_blocking and towers_blocking then + blocked = false + for _,tower in pairs(TOWERS) do + if tower.type ~= TOWER_TYPE.WALL then + blocked = true + break + end + end + end return not blocked and tile.elevation > 0.5 elseif tower_type == TOWER_TYPE.LIGHTHOUSE then @@ -96,13 +141,13 @@ function tower_is_buildable_on(hex, tile, tower_type) break end end - return not blocked and tile.elevation <= 0.5 and tile.elevation > -0.5 and has_water_neighbour + return not blocked and tile_is_medium_elevation(tile) and has_water_neighbour elseif tower_type == TOWER_TYPE.WALL then - return not blocked and tile.elevation <= 0.5 and tile.elevation > -0.5 + return not blocked and tile_is_medium_elevation(tile) elseif tower_type == TOWER_TYPE.MOAT then - return not blocked and tile.elevation <= 0.5 and tile.elevation > -0.5 + return not blocked and tile_is_medium_elevation(tile) end end @@ -158,10 +203,11 @@ end function make_and_register_tower(hex, tower_type) local tower = make_basic_entity( hex, - make_tower_sprite(tower_type), + make_tower_node(tower_type), get_tower_update_function(tower_type) ) + local need_to_regen_flow_field = true tower.type = tower_type if tower_type == TOWER_TYPE.REDEYE then tower.range = 7 @@ -171,18 +217,46 @@ function make_and_register_tower(hex, tower_type) HEX_MAP[hex.x][hex.y].elevation = 2 elseif tower_type == TOWER_TYPE.LIGHTHOUSE then - tower.range = 4 + tower.range = 5 tower.perimeter = ring_map(tower.hex, tower.range) + --[[ + tower.node:append( + am.particles2d{ + source_pos = vec2(0, 12), + source_pos_var = vec2(2), + start_size = 1, + start_size_var = 1, + end_size = 1, + end_size_var = 1, + angle = 0, + angle_var = math.pi, + speed = 1, + speed_var = 2, + life = 10, + life_var = 1, + start_color = COLORS.WHITE, + start_color_var = vec4(0.1, 0.1, 0.1, 1), + end_color = COLORS.SUNRAY, + end_color_var = vec4(0.1), + emission_rate = 4, + start_particles = 4, + max_particles = 200 + } + ) + ]] + -- @HACK + need_to_regen_flow_field = false elseif tower_type == TOWER_TYPE.WALL then HEX_MAP[hex.x][hex.y].elevation = 1 elseif tower_type == TOWER_TYPE.MOAT then - HEX_MAP[hex.x][hex.y].elevation = 0 - + HEX_MAP[hex.x][hex.y].elevation = -1 end - generate_and_apply_flow_field(HEX_MAP, HEX_GRID_CENTER, WORLD) + if need_to_regen_flow_field then + generate_and_apply_flow_field(HEX_MAP, HEX_GRID_CENTER, WORLD) + end register_entity(TOWERS, tower) end @@ -193,3 +267,17 @@ function build_tower(hex, tower_type) vplay_sfx(SOUNDS.EXPLOSION4) end +function delete_all_towers() + for tower_index,tower in pairs(TOWERS) do + if tower then delete_entity(TOWERS, tower_index) end + end +end + +function do_tower_updates() + for tower_index,tower in pairs(TOWERS) do + if tower and tower.update then + tower.update(tower, tower_index) + end + end +end +