Browse Source

state -> gamestate

master
Nicholas Hayashi 3 years ago
parent
commit
79f8daf04b
  1. 8
      src/entity.lua
  2. 154
      src/game.lua
  3. 10
      src/grid.lua
  4. 58
      src/mob.lua
  5. 14
      src/projectile.lua
  6. 56
      src/tower.lua

8
src/entity.lua

@ -17,7 +17,7 @@ entity structure:
function make_basic_entity(hex, update, position)
local entity = {}
entity.TOB = state.time
entity.TOB = game_state.time
-- usually you'll provide a hex and not a position, and the entity will spawn in the center
-- of the hex. if you want an entity to exist not at the center of a hex, you can provide a
@ -41,14 +41,14 @@ end
function register_entity(t, entity)
table.insert(t, entity)
state.world:append(entity.node)
game_state.world:append(entity.node)
end
-- |t| is the source table, probably state.mobs, state.towers, or state.projectiles
-- |t| is the source table, probably game_state.mobs, game_state.towers, or game_state.projectiles
function delete_entity(t, index)
if not t then error("splat!") end
state.world:remove(t[index].node)
game_state.world:remove(t[index].node)
t[index] = false -- leave empty indexes so other entities can learn that this entity was deleted
end

154
src/game.lua

@ -1,6 +1,6 @@
game = false -- flag to tell if there is a game running
state = {}
game_state = {}
-- top right display types
-- f1 toggles what is displayed in the top right of the screen
@ -48,10 +48,10 @@ local function get_initial_game_state(seed)
end
local function get_wave_timer_text()
if state.spawning then
return string.format("WAVE (%d) OVER: %.2f", state.current_wave, state.time_until_next_break)
if game_state.spawning then
return string.format("WAVE (%d) OVER: %.2f", game_state.current_wave, game_state.time_until_next_break)
else
return string.format("NEXT WAVE (%d): %.2f", state.current_wave, state.time_until_next_wave)
return string.format("NEXT WAVE (%d): %.2f", game_state.current_wave, game_state.time_until_next_wave)
end
end
@ -73,10 +73,10 @@ local function get_top_right_display_text(hex, evenq, centered_evenq, display_ty
str = table.tostring(am.perf_stats())
elseif display_type == TRDTS.SEED then
str = "SEED: " .. state.map.seed
str = "SEED: " .. game_state.map.seed
elseif display_type == TRDTS.TILE then
str = table.tostring(hex_map_get(state.map, hex))
str = table.tostring(hex_map_get(game_state.map, hex))
end
return str
end
@ -91,14 +91,14 @@ end
local BASE_BREAK_TIME = 20
local function get_break_time(current_wave)
return BASE_BREAK_TIME - math.min(BASE_BREAK_TIME, BASE_BREAK_TIME / (1 / math.log(state.current_wave + 1)))
return BASE_BREAK_TIME - math.min(BASE_BREAK_TIME, BASE_BREAK_TIME / (1 / math.log(game_state.current_wave + 1)))
end
local function do_day_night_cycle()
-- this is a bad idea, atleast with the current bad rendering strategy of not using a single draw call
-- i get flickering as the light level increases
--local tstep = (math.sin(state.time * am.delta_time) + 1) / 100
--state.world"negative_mask".color = vec4(tstep){a=1}
--local tstep = (math.sin(game_state.time * am.delta_time) + 1) / 100
--game_state.world"negative_mask".color = vec4(tstep){a=1}
end
local function game_pause()
@ -110,48 +110,48 @@ end
local function game_deserialize(json_string)
local new_state = am.parse_json(json_string)
if new_state.version ~= version then
if new_game_state.version ~= version then
log("loading incompatible old save data. starting a fresh game instead.")
return get_initial_game_state()
end
new_state.map = random_map(new_state.seed)
new_state.world = make_hex_grid_scene(new_state.map)
new_state.seed = nil
new_game_state.map = random_map(new_game_state.seed)
new_game_state.world = make_hex_grid_scene(new_game_state.map)
new_game_state.seed = nil
for i,t in pairs(new_state.towers) do
for i,t in pairs(new_game_state.towers) do
if t then
new_state.towers[i] = tower_deserialize(t)
new_game_state.towers[i] = tower_deserialize(t)
for _,h in pairs(new_state.towers[i].hexes) do
local tile = hex_map_get(new_state.map, h.x, h.y)
tile.elevation = tile.elevation + new_state.towers[i].height
for _,h in pairs(new_game_state.towers[i].hexes) do
local tile = hex_map_get(new_game_state.map, h.x, h.y)
tile.elevation = tile.elevation + new_game_state.towers[i].height
end
-- @STATEFUL, shouldn't be done here
new_state.world:append(new_state.towers[i].node)
new_game_state.world:append(new_game_state.towers[i].node)
end
end
-- after we have re-constituted all of the towers and modified the map's elevations accordingly,
-- we should re-calc the flow-field
apply_flow_field(new_state.map, generate_flow_field(new_state.map, HEX_GRID_CENTER), new_state.world)
apply_flow_field(new_game_state.map, generate_flow_field(new_game_state.map, HEX_GRID_CENTER), new_game_state.world)
for i,m in pairs(new_state.mobs) do
for i,m in pairs(new_game_state.mobs) do
if m then
new_state.mobs[i] = mob_deserialize(m)
new_game_state.mobs[i] = mob_deserialize(m)
-- @STATEFUL, shouldn't be done here
new_state.world:append(new_state.mobs[i].node)
new_game_state.world:append(new_game_state.mobs[i].node)
end
end
for i,p in pairs(new_state.projectiles) do
for i,p in pairs(new_game_state.projectiles) do
if p then
new_state.projectiles[i] = projectile_deserialize(p)
new_game_state.projectiles[i] = projectile_deserialize(p)
-- @STATEFUL, shouldn't be done here
new_state.world:append(new_state.projectiles[i].node)
new_game_state.world:append(new_game_state.projectiles[i].node)
end
end
@ -162,7 +162,7 @@ local function game_serialize()
local serialized = table.shallow_copy(state)
serialized.version = version
serialized.seed = state.map.seed
serialized.seed = game_state.map.seed
serialized.map = nil -- we re-generate the entire map from the seed on de-serialize
-- in order to serialize the game state, we have to convert all relevant userdata into
@ -174,21 +174,21 @@ local function game_serialize()
-- this is dumb and if i forsaw this i would have probably used float arrays instead of vectors
serialized.towers = {}
for i,t in pairs(state.towers) do
for i,t in pairs(game_state.towers) do
if t then
serialized.towers[i] = tower_serialize(t)
end
end
serialized.mobs = {}
for i,m in pairs(state.mobs) do
for i,m in pairs(game_state.mobs) do
if m then
serialized.mobs[i] = mob_serialize(m)
end
end
serialized.projectiles = {}
for i,p in pairs(state.projectiles) do
for i,p in pairs(game_state.projectiles) do
if p then
serialized.projectiles[i] = projectile_serialize(p)
end
@ -202,35 +202,35 @@ local function deselect_tile()
end
local function game_action(scene)
if state.score < 0 then game_end() return true end
if game_state.score < 0 then game_end() return true end
local perf = am.perf_stats()
state.time = state.time + am.delta_time
state.score = state.score + am.delta_time
game_state.time = game_state.time + am.delta_time
game_state.score = game_state.score + am.delta_time
if state.spawning then
state.time_until_next_break = state.time_until_next_break - am.delta_time
if game_state.spawning then
game_state.time_until_next_break = game_state.time_until_next_break - am.delta_time
if state.time_until_next_break <= 0 then
state.time_until_next_break = 0
state.current_wave = state.current_wave + 1
if game_state.time_until_next_break <= 0 then
game_state.time_until_next_break = 0
game_state.current_wave = game_state.current_wave + 1
state.spawning = false
game_state.spawning = false
state.time_until_next_wave = get_break_time(state.current_wave)
game_state.time_until_next_wave = get_break_time(game_state.current_wave)
end
else
state.time_until_next_wave = state.time_until_next_wave - am.delta_time
game_state.time_until_next_wave = game_state.time_until_next_wave - am.delta_time
if state.time_until_next_wave <= 0 then
state.time_until_next_wave = 0
if game_state.time_until_next_wave <= 0 then
game_state.time_until_next_wave = 0
state.spawning = true
game_state.spawning = true
-- calculate spawn chance for next wave
state.spawn_chance = math.log(state.current_wave)/80 + 0.002
game_state.spawn_chance = math.log(game_state.current_wave)/80 + 0.002
state.time_until_next_break = get_wave_time(state.current_wave)
game_state.time_until_next_break = get_wave_time(game_state.current_wave)
end
end
@ -240,18 +240,18 @@ local function game_action(scene)
local evenq = hex_to_evenq(hex)
local centered_evenq = evenq{ y = -evenq.y } - vec2(math.floor(HEX_GRID_WIDTH/2)
, math.floor(HEX_GRID_HEIGHT/2))
local tile = hex_map_get(state.map, hex)
local tile = hex_map_get(game_state.map, hex)
local interactable = evenq_is_in_interactable_region(evenq{ y = -evenq.y })
local buildable = tower_type_is_buildable_on(hex, tile, state.selected_tower_type)
local buildable = tower_type_is_buildable_on(hex, tile, game_state.selected_tower_type)
if win:mouse_pressed"left" then
deselect_tile()
if interactable then
if buildable then
local broken, flow_field = building_tower_breaks_flow_field(state.selected_tower_type, hex)
local cost = get_tower_cost(state.selected_tower_type)
local broken, flow_field = building_tower_breaks_flow_field(game_state.selected_tower_type, hex)
local cost = get_tower_cost(game_state.selected_tower_type)
if broken then
local node = win.scene("cursor"):child(2)
@ -260,7 +260,7 @@ local function game_action(scene)
play_sfx(SOUNDS.BIRD2)
alert("closes the circle")
elseif cost > state.money then
elseif cost > game_state.money then
local node = win.scene("cursor"):child(2)
node.color = COLORS.CLARET
node:action(am.tween(0.1, { color = COLORS.TRANSPARENT }))
@ -269,10 +269,10 @@ local function game_action(scene)
else
update_money(-cost)
build_tower(hex, state.selected_tower_type, flow_field)
build_tower(hex, game_state.selected_tower_type, flow_field)
if flow_field then
apply_flow_field(state.map, flow_field, state.world)
apply_flow_field(game_state.map, flow_field, game_state.world)
end
end
else
@ -307,19 +307,19 @@ local function game_action(scene)
game_pause()
elseif win:key_pressed"f1" then
state.selected_top_right_display_type = (state.selected_top_right_display_type + 1) % #table.keys(TRDTS)
game_state.selected_top_right_display_type = (game_state.selected_top_right_display_type + 1) % #table.keys(TRDTS)
elseif win:key_pressed"f2" then
state.world"flow_field".hidden = not state.world"flow_field".hidden
game_state.world"flow_field".hidden = not game_state.world"flow_field".hidden
elseif win:key_pressed"f3" then
game_save()
elseif win:key_pressed"tab" then
if win:key_down"lshift" then
select_toolbelt_button((state.selected_toolbelt_button + table.count(TOWER_TYPE) - 2) % table.count(TOWER_TYPE) + 1)
select_toolbelt_button((game_state.selected_toolbelt_button + table.count(TOWER_TYPE) - 2) % table.count(TOWER_TYPE) + 1)
else
select_toolbelt_button((state.selected_toolbelt_button) % table.count(TOWER_TYPE) + 1)
select_toolbelt_button((game_state.selected_toolbelt_button) % table.count(TOWER_TYPE) + 1)
end
elseif win:key_pressed"1" then select_toolbelt_button( 1)
elseif win:key_pressed"2" then select_toolbelt_button( 2)
@ -336,7 +336,7 @@ local function game_action(scene)
end
do_entity_updates()
do_mob_spawning(state.spawn_chance)
do_mob_spawning(game_state.spawn_chance)
do_day_night_cycle()
-- update the cursor
@ -344,7 +344,7 @@ local function game_action(scene)
win.scene("cursor").hidden = true
else
if state.selected_tower_type then
if game_state.selected_tower_type then
if buildable then
win.scene("cursor").hidden = false
@ -358,10 +358,10 @@ local function game_action(scene)
win.scene("cursor_translate").position2d = rounded_mouse
end
win.scene("score").text = string.format("SCORE: %.2f", state.score)
win.scene("money").text = string.format("MONEY: $%d", state.money)
win.scene("score").text = string.format("SCORE: %.2f", game_state.score)
win.scene("money").text = string.format("MONEY: $%d", game_state.money)
win.scene("wave_timer").text = get_wave_timer_text()
win.scene("top_right_display").text = get_top_right_display_text(hex, evenq, centered_evenq, state.selected_top_right_display_type)
win.scene("top_right_display").text = get_top_right_display_text(hex, evenq, centered_evenq, game_state.selected_top_right_display_type)
end
local function make_game_toolbelt()
@ -474,8 +474,8 @@ local function make_game_toolbelt()
end
end
else
if state.selected_tower_type then
win.scene:replace("tower_tooltip_text", get_tower_tooltip_text_node(state.selected_tower_type))
if game_state.selected_tower_type then
win.scene:replace("tower_tooltip_text", get_tower_tooltip_text_node(game_state.selected_tower_type))
else
win.scene:replace("tower_tooltip_text", am.group():tag"tower_tooltip_text")
end
@ -506,7 +506,7 @@ local function make_game_toolbelt()
)
select_tower_type = function(tower_type)
state.selected_tower_type = tower_type
game_state.selected_tower_type = tower_type
if get_tower_spec(tower_type) then
win.scene:replace(
@ -537,7 +537,7 @@ local function make_game_toolbelt()
end
select_toolbelt_button = function(i)
state.selected_toolbelt_button = i
game_state.selected_toolbelt_button = i
if get_tower_spec(i) then
select_tower_type(i)
@ -581,20 +581,20 @@ local function game_scene()
self.color = COLORS.SUNRAY
if win:mouse_pressed("left") then
if state.spawning then
if game_state.spawning then
-- in this case, we don't exactly just send the next wave, we turn the current wave into the next
-- wave, and add the amount of time it would have lasted to the amount of remaining time in the
-- current wave
state.current_wave = state.current_wave + 1
game_state.current_wave = game_state.current_wave + 1
-- calculate spawn chance for next wave
state.spawn_chance = math.log(state.current_wave)/100 + 0.002
game_state.spawn_chance = math.log(game_state.current_wave)/100 + 0.002
state.time_until_next_break = state.time_until_next_break + get_break_time(state.current_wave)
game_state.time_until_next_break = game_state.time_until_next_break + get_break_time(game_state.current_wave)
play_sfx(SOUNDS.EXPLOSION4)
else
state.time_until_next_wave = 0
game_state.time_until_next_wave = 0
play_sfx(SOUNDS.EXPLOSION4)
end
@ -620,7 +620,7 @@ local function game_scene()
end))
local scene = am.group(
am.scale(1):tag"world_scale" ^ state.world,
am.scale(1):tag"world_scale" ^ game_state.world,
am.translate(HEX_GRID_CENTER):tag"cursor_translate" ^ make_hex_cursor(0, COLORS.TRANSPARENT):tag"cursor",
score,
money,
@ -638,11 +638,11 @@ local function game_scene()
return scene
end
function update_score(diff) state.score = state.score + diff end
function update_money(diff) state.money = state.money + diff end
function update_score(diff) game_state.score = game_state.score + diff end
function update_money(diff) game_state.money = game_state.money + diff end
function game_end()
state = {}
game_state = {}
game = false
end
@ -653,7 +653,7 @@ end
function game_init(saved_state)
if saved_state then
state = game_deserialize(saved_state)
game_state = game_deserialize(saved_state)
if not state then
-- failed to load a save
@ -665,7 +665,7 @@ function game_init(saved_state)
-- but you don't have a built tower cursor node, so hovering a buildable tile throws an error
select_tower_type(nil)
else
state = get_initial_game_state()
game_state = get_initial_game_state()
end
game = true

10
src/grid.lua

@ -122,7 +122,7 @@ function building_tower_breaks_flow_field(tower_type, hex)
local all_impassable = true
local hexes = hex_spiral_map(hex, get_tower_size(tower_type))
for _,h in pairs(hexes) do
local tile = hex_map_get(state.map, h)
local tile = hex_map_get(game_state.map, h)
if all_impassable and mob_can_pass_through(nil, h) then
all_impassable = false
@ -136,19 +136,19 @@ function building_tower_breaks_flow_field(tower_type, hex)
-- if no mobs can pass over any of the tiles we're building on
-- there is no need to regenerate the flow field, or do anything more
-- (besides return all the tile's elevations back to their original state)
-- (besides return all the tile's elevations back to their original game_state)
if all_impassable then
for i,h in pairs(hexes) do
hex_map_get(state.map, h).elevation = original_elevations[i]
hex_map_get(game_state.map, h).elevation = original_elevations[i]
end
return false
end
local flow_field = generate_flow_field(state.map, HEX_GRID_CENTER)
local flow_field = generate_flow_field(game_state.map, HEX_GRID_CENTER)
local result = not hex_map_get(flow_field, 0, 0)
for i,h in pairs(hexes) do
hex_map_get(state.map, h).elevation = original_elevations[i]
hex_map_get(game_state.map, h).elevation = original_elevations[i]
end
return result, flow_field

58
src/mob.lua

@ -37,18 +37,18 @@ function get_mob_spec(mob_type)
end
local function grow_mob_health(mob_type, spec_health, time)
return spec_health + math.pow(state.current_wave - 1, 2)
return spec_health + math.pow(game_state.current_wave - 1, 2)
end
local function grow_mob_speed(mob_type, spec_speed, time)
return spec_speed + math.log(state.current_wave + 1)
return spec_speed + math.log(game_state.current_wave + 1)
end
local function grow_mob_bounty(mob_type, spec_bounty, time)
return spec_bounty + (state.current_wave - 1) * 2
return spec_bounty + (game_state.current_wave - 1) * 2
end
function mobs_on_hex(hex)
local t = {}
for mob_index,mob in pairs(state.mobs) do
for mob_index,mob in pairs(game_state.mobs) do
if mob and mob.hex == hex then
table.insert(t, mob_index, mob)
end
@ -58,25 +58,25 @@ end
function mob_on_hex(hex)
-- table.find returns i,v in the table
return table.find(state.mobs, function(mob)
return table.find(game_state.mobs, function(mob)
return mob and mob.hex == hex
end)
end
-- check if a the tile at |hex| is passable by |mob|
function mob_can_pass_through(mob, hex)
local tile = hex_map_get(state.map, hex)
local tile = hex_map_get(game_state.map, hex)
return tile_is_medium_elevation(tile)
end
function mob_die(mob, mob_index)
vplay_sfx(SOUNDS.EXPLOSION1)
delete_entity(state.mobs, mob_index)
delete_entity(game_state.mobs, mob_index)
end
function mob_reach_center(mob, mob_index)
update_score(-(mob.health + mob.bounty))
delete_entity(state.mobs, mob_index)
delete_entity(game_state.mobs, mob_index)
end
local HEALTHBAR_WIDTH = HEX_PIXEL_WIDTH/2
@ -89,7 +89,7 @@ function do_hit_mob(mob, damage, mob_index)
mob_die(mob, mob_index)
else
mob.healthbar:action(coroutine.create(function(self)
local x2 = -HEALTHBAR_WIDTH/2 + mob.health/grow_mob_health(mob.type, get_mob_health(mob.type), state.time) * HEALTHBAR_WIDTH/2
local x2 = -HEALTHBAR_WIDTH/2 + mob.health/grow_mob_health(mob.type, get_mob_health(mob.type), game_state.time) * HEALTHBAR_WIDTH/2
self:child(2).x2 = x2
self.hidden = false
am.wait(am.delay(0.8))
@ -185,16 +185,16 @@ local function resolve_frame_target_for_mob(mob, mob_index)
end
else
-- use the map's flow field - gotta find the the best neighbour
local neighbours = grid_neighbours(state.map, mob.hex)
local neighbours = grid_neighbours(game_state.map, mob.hex)
if #neighbours > 0 then
local first_neighbour = neighbours[1]
tile = hex_map_get(state.map, first_neighbour)
tile = hex_map_get(game_state.map, first_neighbour)
local lowest_cost_hex = first_neighbour
local lowest_cost = tile.priority or 0
for _,n in pairs(neighbours) do
tile = hex_map_get(state.map, n)
tile = hex_map_get(game_state.map, n)
if not tile.priority then
-- if there's no stored priority, that should mean it's the center tile
@ -224,8 +224,8 @@ local function update_mob_velkooz(mob, mob_index)
if mob.frame_target then
if mob_can_pass_through(mob, mob.frame_target) then
local from = hex_map_get(state.map, mob.hex)
local to = hex_map_get(state.map, mob.frame_target)
local from = hex_map_get(game_state.map, mob.hex)
local to = hex_map_get(game_state.map, mob.frame_target)
local rate = mob.speed * am.delta_time
mob.position = mob.position + math.normalize(hex_to_pixel(mob.frame_target, vec2(HEX_SIZE)) - mob.position) * rate
@ -243,7 +243,7 @@ local function update_mob_velkooz(mob, mob_index)
mob.node("rotate").angle = -theta + math.pi/2
local roll = math.floor((state.time - mob.TOB) * 10) % 4
local roll = math.floor((game_state.time - mob.TOB) * 10) % 4
if roll == 0 then
mob.node"velk_sprite".source = "res/mob_velkooz0.png"
@ -267,8 +267,8 @@ local function update_mob_spooder(mob, mob_index)
-- or between when we last calculated this target and now
-- check for that now
if mob_can_pass_through(mob, mob.frame_target) then
local from = hex_map_get(state.map, mob.hex)
local to = hex_map_get(state.map, mob.frame_target)
local from = hex_map_get(game_state.map, mob.hex)
local to = hex_map_get(game_state.map, mob.frame_target)
local spider_speed = ((math.simplex(mob.hex) + 1.5) * 1.5) ^ 2
local rate = (spider_speed * mob.speed - math.abs(to.elevation - from.elevation)) * am.delta_time
@ -296,8 +296,8 @@ local function update_mob_beeper(mob, mob_index)
-- or between when we last calculated this target and now
-- check for that now
if mob_can_pass_through(mob, mob.frame_target) then
local from = hex_map_get(state.map, mob.hex)
local to = hex_map_get(state.map, mob.frame_target)
local from = hex_map_get(game_state.map, mob.hex)
local to = hex_map_get(game_state.map, mob.frame_target)
local rate = (4 * mob.speed - math.abs(to.elevation - from.elevation)) * am.delta_time
mob.position = mob.position + math.normalize(hex_to_pixel(mob.frame_target, vec2(HEX_SIZE)) - mob.position) * rate
@ -339,14 +339,14 @@ local function make_and_register_mob(mob_type)
mob.node = am.translate(mob.position) ^ make_mob_node(mob_type, mob)
local spec = get_mob_spec(mob_type)
mob.health = grow_mob_health(mob_type, spec.health, state.time)
mob.speed = grow_mob_speed(mob_type, spec.speed, state.time)
mob.bounty = grow_mob_bounty(mob_type, spec.bounty, state.time)
mob.health = grow_mob_health(mob_type, spec.health, game_state.time)
mob.speed = grow_mob_speed(mob_type, spec.speed, game_state.time)
mob.bounty = grow_mob_bounty(mob_type, spec.bounty, game_state.time)
mob.hurtbox_radius = spec.hurtbox_radius
mob.healthbar = mob.node:child(1):child(2):child(1) -- lmao
if mob.type == MOB_TYPE.VELKOOZ then
mob.states = {
mob.game_states = {
pack_texture_into_sprite(TEXTURES.VELKOOZ, MOB_SIZE, MOB_SIZE):tag"velk_sprite",
pack_texture_into_sprite(TEXTURES.VELKOOZ1, MOB_SIZE, MOB_SIZE):tag"velk_sprite",
pack_texture_into_sprite(TEXTURES.VELKOOZ2, MOB_SIZE, MOB_SIZE):tag"velk_sprite",
@ -354,7 +354,7 @@ local function make_and_register_mob(mob_type)
}
end
register_entity(state.mobs, mob)
register_entity(game_state.mobs, mob)
return mob
end
@ -376,12 +376,12 @@ end
local function can_spawn_mob()
local MAX_SPAWN_RATE = 0.1
if not state.spawning or (state.time - state.last_mob_spawn_time) < MAX_SPAWN_RATE then
if not game_state.spawning or (game_state.time - game_state.last_mob_spawn_time) < MAX_SPAWN_RATE then
return false
end
if math.random() <= state.spawn_chance then
state.last_mob_spawn_time = state.time
if math.random() <= game_state.spawn_chance then
game_state.last_mob_spawn_time = game_state.time
return true
else
return false
@ -390,7 +390,7 @@ end
function do_mob_spawning()
if can_spawn_mob() then
if state.current_wave % 2 == 0 then
if game_state.current_wave % 2 == 0 then
make_and_register_mob(MOB_TYPE.SPOODER)
else
make_and_register_mob(MOB_TYPE.BEEPER)
@ -399,7 +399,7 @@ function do_mob_spawning()
end
function do_mob_updates()
for mob_index,mob in pairs(state.mobs) do
for mob_index,mob in pairs(game_state.mobs) do
if mob and mob.update then
mob.update(mob, mob_index)
end

14
src/projectile.lua

@ -75,7 +75,7 @@ local function update_projectile_shell(projectile, projectile_index)
x2 = win.right,
y2 = win.top
}) then
delete_entity(state.projectiles, projectile_index)
delete_entity(game_state.projectiles, projectile_index)
return true
end
@ -106,7 +106,7 @@ local function update_projectile_shell(projectile, projectile_index)
end
end
local tile = hex_map_get(state.map, projectile.hex)
local tile = hex_map_get(game_state.map, projectile.hex)
if tile and tile.elevation >= projectile.props.z then
--do_explode = true
@ -120,7 +120,7 @@ local function update_projectile_shell(projectile, projectile_index)
do_hit_mob(mob, damage, index)
end
win.scene:append(make_shell_explosion_node(projectile.position))
delete_entity(state.projectiles, projectile_index)
delete_entity(game_state.projectiles, projectile_index)
return true
end
end
@ -135,7 +135,7 @@ local function update_projectile_laser(projectile, projectile_index)
x2 = win.right,
y2 = win.top
}) then
delete_entity(state.projectiles, projectile_index)
delete_entity(game_state.projectiles, projectile_index)
return true
end
@ -192,7 +192,7 @@ local function update_projectile_bullet(projectile, projectile_index)
x2 = win.right,
y2 = win.top
}) then
delete_entity(state.projectiles, projectile_index)
delete_entity(game_state.projectiles, projectile_index)
return true
end
@ -275,7 +275,7 @@ function make_and_register_projectile(hex, projectile_type, vector)
projectile.damage = spec.damage
projectile.hitbox_radius = spec.hitbox_radius
register_entity(state.projectiles, projectile)
register_entity(game_state.projectiles, projectile)
return projectile
end
@ -298,7 +298,7 @@ function projectile_deserialize(json_string)
end
function do_projectile_updates()
for projectile_index,projectile in pairs(state.projectiles) do
for projectile_index,projectile in pairs(game_state.projectiles) do
if projectile and projectile.update then
projectile.update(projectile, projectile_index)
end

56
src/tower.lua

@ -141,14 +141,14 @@ function make_tower_node(tower_type)
elseif tower_type == TOWER_TYPE.GATTLER then
return am.group{
am.circle(vec2(0), HEX_SIZE - 4, COLORS.VERY_DARK_GRAY, 5),
am.rotate(state.time or 0)
am.rotate(game_state.time or 0)
^ pack_texture_into_sprite(TEXTURES.TOWER_HOWITZER, HEX_PIXEL_HEIGHT*1.5, HEX_PIXEL_WIDTH*2, COLORS.GREEN_YELLOW)
}
elseif tower_type == TOWER_TYPE.HOWITZER then
return am.group{
am.circle(vec2(0), HEX_SIZE - 4, COLORS.VERY_DARK_GRAY, 6),
am.rotate(state.time or 0) ^ am.group{
am.rotate(game_state.time or 0) ^ am.group{
pack_texture_into_sprite(TEXTURES.TOWER_HOWITZER, HEX_PIXEL_HEIGHT*1.5, HEX_PIXEL_WIDTH*2) -- CHONK
}
}
@ -223,7 +223,7 @@ end
local function update_tower_redeye(tower, tower_index)
if not tower.target_index then
for index,mob in pairs(state.mobs) do
for index,mob in pairs(game_state.mobs) do
if mob then
local d = math.distance(mob.hex, tower.hex)
if d <= tower.range then
@ -233,11 +233,11 @@ local function update_tower_redeye(tower, tower_index)
end
end
else
if not state.mobs[tower.target_index] then
if not game_state.mobs[tower.target_index] then
tower.target_index = false
elseif (state.time - tower.last_shot_time) > tower.fire_rate then
local mob = state.mobs[tower.target_index]
elseif (game_state.time - tower.last_shot_time) > tower.fire_rate then
local mob = game_state.mobs[tower.target_index]
make_and_register_projectile(
tower.hex,
@ -245,7 +245,7 @@ local function update_tower_redeye(tower, tower_index)
math.normalize(mob.position - tower.position)
)
tower.last_shot_time = state.time
tower.last_shot_time = game_state.time
vplay_sfx(SOUNDS.LASER2)
end
end
@ -254,7 +254,7 @@ end
local function update_tower_gattler(tower, tower_index)
if not tower.target_index then
-- we should try and acquire a target
for index,mob in pairs(state.mobs) do
for index,mob in pairs(game_state.mobs) do
if mob then
local d = math.distance(mob.hex, tower.hex)
if d <= tower.range then
@ -268,23 +268,23 @@ local function update_tower_gattler(tower, tower_index)
tower.node("rotate").angle = math.wrapf(tower.node("rotate").angle + 0.1 * am.delta_time, math.pi*2)
else
-- should have a target, so we should try and shoot it
if not state.mobs[tower.target_index] then
if not game_state.mobs[tower.target_index] then
-- the target we have was invalidated
tower.target_index = false
else
-- the target we have is valid
local mob = state.mobs[tower.target_index]
local mob = game_state.mobs[tower.target_index]
local vector = math.normalize(mob.position - tower.position)
if (state.time - tower.last_shot_time) > tower.fire_rate then
if (game_state.time - tower.last_shot_time) > tower.fire_rate then
local projectile = make_and_register_projectile(
tower.hex,
PROJECTILE_TYPE.BULLET,
vector
)
tower.last_shot_time = state.time
tower.last_shot_time = game_state.time
play_sfx(SOUNDS.HIT1)
end
@ -300,7 +300,7 @@ end
local function update_tower_howitzer(tower, tower_index)
if not tower.target_index then
-- we don't have a target
for index,mob in pairs(state.mobs) do
for index,mob in pairs(game_state.mobs) do
if mob then
local d = math.distance(mob.hex, tower.hex)
if d <= tower.range then
@ -315,16 +315,16 @@ local function update_tower_howitzer(tower, tower_index)
else
-- we should have a target
-- @NOTE don't compare to false, empty indexes appear on game reload
if not state.mobs[tower.target_index] then
if not game_state.mobs[tower.target_index] then
-- the target we have was invalidated
tower.target_index = false
else
-- the target we have is valid
local mob = state.mobs[tower.target_index]
local mob = game_state.mobs[tower.target_index]
local vector = math.normalize(mob.position - tower.position)
if (state.time - tower.last_shot_time) > tower.fire_rate then
if (game_state.time - tower.last_shot_time) > tower.fire_rate then
local projectile = make_and_register_projectile(
tower.hex,
PROJECTILE_TYPE.SHELL,
@ -336,7 +336,7 @@ local function update_tower_howitzer(tower, tower_index)
-- if it's not enough the shell explodes before it leaves its spawning hex
projectile.props.z = tower.props.z + 0.1
tower.last_shot_time = state.time
tower.last_shot_time = game_state.time
play_sfx(SOUNDS.EXPLOSION2)
end
@ -360,7 +360,7 @@ local function update_tower_lighthouse(tower, tower_index)
-- is within some angle range...? if the mob is heading directly away from the tower, then
-- the lighthouse shouldn't do much
local path, made_it = hex_Astar(state.map, tower.hex, m.hex, grid_neighbours, grid_cost, grid_heuristic)
local path, made_it = hex_Astar(game_state.map, tower.hex, m.hex, grid_neighbours, grid_cost, grid_heuristic)
if made_it then
m.path = path
@ -369,7 +369,7 @@ local function update_tower_lighthouse(tower, tower_index)
--[[
local area = spiral_map(tower.hex, tower.range)
for _,h in pairs(area) do
local node = state.map[h.x][h.y].node"circle"
local node = game_state.map[h.x][h.y].node"circle"
local initial_color = node.color
local d = math.distance(h, tower.hex)
@ -426,7 +426,7 @@ end
function towers_on_hex(hex)
local t = {}
for tower_index,tower in pairs(state.towers) do
for tower_index,tower in pairs(game_state.towers) do
if tower then
for _,h in pairs(tower.hexes) do
if h == hex then
@ -440,7 +440,7 @@ function towers_on_hex(hex)
end
function tower_on_hex(hex)
return table.find(state.towers, function(tower)
return table.find(game_state.towers, function(tower)
for _,h in pairs(tower.hexes) do
if h == hex then return true end
end
@ -464,7 +464,7 @@ function tower_type_is_buildable_on(hex, tile, tower_type)
table.merge(blocking_towers, towers_on_hex(h))
table.merge(blocking_mobs, mobs_on_hex(h))
local tile = hex_map_get(state.map, h)
local tile = hex_map_get(game_state.map, h)
-- this should always be true, unless it is possible to place a tower
-- where part of the tower overflows the edge of the map
if tile then
@ -488,7 +488,7 @@ function tower_type_is_buildable_on(hex, tile, tower_type)
local has_mountain_neighbour = false
local has_non_wall_non_moat_tower_neighbour = false
for _,h in pairs(hex_neighbours(hex)) do
local tile = hex_map_get(state.map, h)
local tile = hex_map_get(game_state.map, h)
if tile and tile.elevation >= 0.5 then
has_mountain_neighbour = true
@ -518,7 +518,7 @@ function tower_type_is_buildable_on(hex, tile, tower_type)
break
end
local tile = hex_map_get(state.map, h)
local tile = hex_map_get(game_state.map, h)
if not wall_on_hex and tile and tile.elevation >= 0.5 then
has_mountain_neighbour = true
break
@ -533,7 +533,7 @@ function tower_type_is_buildable_on(hex, tile, tower_type)
elseif tower_type == TOWER_TYPE.LIGHTHOUSE then
local has_water_neighbour = false
for _,h in pairs(hex_neighbours(hex)) do
local tile = hex_map_get(state.map, h)
local tile = hex_map_get(game_state.map, h)
if tile and tile.elevation < -0.5 then
has_water_neighbour = true
@ -577,7 +577,7 @@ function make_and_register_tower(hex, tower_type)
tower.height = spec.height
for _,h in pairs(tower.hexes) do
local tile = hex_map_get(state.map, h.x, h.y)
local tile = hex_map_get(game_state.map, h.x, h.y)
tile.elevation = tile.elevation + tower.height
end
@ -591,7 +591,7 @@ function make_and_register_tower(hex, tower_type)
tower.perimeter = hex_ring_map(tower.hex, tower.range)
end
register_entity(state.towers, tower)
register_entity(game_state.towers, tower)
return tower
end
@ -603,7 +603,7 @@ function build_tower(hex, tower_type)
end
function do_tower_updates()
for tower_index,tower in pairs(state.towers) do
for tower_index,tower in pairs(game_state.towers) do
if tower and tower.update then
tower.update(tower, tower_index)
end

Loading…
Cancel
Save