Browse Source

hack

master
Nicholas Hayashi 4 years ago
parent
commit
9b0b7df866
  1. 2
      color.lua
  2. 5
      src/entity.lua
  3. 11
      src/game.lua
  4. 2
      src/grid.lua
  5. 42
      src/mob.lua
  6. 108
      src/projectile.lua
  7. 117
      src/tower.lua

2
color.lua

@ -12,7 +12,7 @@ COLORS = {
-- non-standard hues
WATER = vec4(0.12, 0.25, 0.3, 1),
GRASS = vec4(0.10, 0.25, 0.10, 1),
GRASS = vec4(0.05, 0.22, 0.11, 1),
DIRT = vec4(0.22, 0.20, 0.10, 1),
MOUNTAIN = vec4(0.95, 0.30, 0.20, 1),

5
src/entity.lua

@ -9,6 +9,9 @@ entity structure:
update - function - runs every frame with itself and its index in some array as an argument
node - node - scene graph node
type - enum - sub type - unset if 'basic' entity
props - table - table of properties specific to this entity subtype
... - any - a bunch of other shit depending on what entity type it is
}
--]]
@ -31,6 +34,8 @@ function make_basic_entity(hex, node, update, position)
entity.update = update
entity.node = am.translate(entity.position) ^ node
entity.type = false
entity.props = {}
return entity
end

11
src/game.lua

@ -84,7 +84,7 @@ function select_toolbelt_button(i)
end
function do_day_night_cycle()
local tstep = (math.sin(state.time / 100) + 1) / state.perf.avg_fps
local tstep = (math.sin(state.time / 100) + 1) * am.delta_time
state.world"negative_mask".color = vec4(tstep){a=1}
end
@ -92,7 +92,10 @@ local function game_pause()
WIN.scene"game".paused = true
WIN.scene"game":append(am.group{
am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRANSPARENT),
am.scale(3) ^ am.text("Paused.\nEscape to Resume\nf4 to start a new game", COLORS.BLACK)
am.scale(3)
^ am.text(string.format(
"Paused.\nSeed: %d\nEscape to Resume\nf4 to start a new game", state.map.seed
), COLORS.BLACK)
}
:tag"pause_menu")
WIN.scene:action(function()
@ -286,6 +289,7 @@ local function make_game_toolbelt()
toolbelt:append(tower_select_square)
local keys = { '1', '2', '3', '4', 'q', 'w', 'e', 'r', 'a', 's', 'd', 'f' }
--local keys = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=' }
-- order of this array is the order of towers on the toolbelt.
local tower_type_values = {
TOWER_TYPE.WALL,
@ -392,6 +396,9 @@ function game_init()
state = get_initial_game_state()
build_tower(HEX_GRID_CENTER, TOWER_TYPE.RADAR)
-- hack to make the center tile passable even though there's a tower on it
state.map.get(HEX_GRID_CENTER.x, HEX_GRID_CENTER.y).elevation = 0
WIN.scene:remove("game")
WIN.scene:append(game_scene())
end

2
src/grid.lua

@ -174,7 +174,7 @@ function random_map(seed)
noise = noise * d^0.125 -- arbitrary, seems to work good
end
-- light shading on edge cells @TODO replace this with a skylight, that can move
-- 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))
local color = color_at(noise) - mask

42
src/mob.lua

@ -2,9 +2,26 @@
MOBS = {}
MOB_TYPE = {
BEEPER = 1,
}
MAX_MOB_SIZE = hex_height(HEX_SIZE, ORIENTATION.FLAT) / 2
MOB_SIZE = MAX_MOB_SIZE
MOB_SPECS = {
[MOB_TYPE.BEEPER] = {
health = 10,
speed = 10,
bounty = 5,
hurtbox_radius = MOB_SIZE/2
}
}
function get_mob_spec(mob_type)
return MOB_SPECS[mob_type]
end
function mobs_on_hex(hex)
local t = {}
for mob_index,mob in pairs(MOBS) do
@ -15,8 +32,8 @@ function mobs_on_hex(hex)
return t
end
-- @NOTE returns i,v in the table
function mob_on_hex(hex)
-- table.find returns i,v in the table
return table.find(MOBS, function(mob)
return mob and mob.hex == hex
end)
@ -134,7 +151,7 @@ local function update_mob(mob, mob_index)
end
if mob.frame_target and mob.frame_target == last_frame_hex then
--log('backpedaling')
log('backpedaling')
end
-- do movement
@ -143,9 +160,7 @@ local function update_mob(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
-- this is supposed to achieve frame rate independence, but i have no idea if it actually does
-- the constant multiplier at the beginning is how many pixels we want a mob with speed 1 to move in one frame
local rate = 4 * mob.speed / state.perf.avg_fps
local rate = 4 * mob.speed * am.delta_time
mob.position = mob.position + math.normalize(hex_to_pixel(mob.frame_target) - mob.position) * rate
mob.node.position2d = mob.position
@ -171,21 +186,24 @@ local function make_and_register_mob(mob_type)
update_mob
)
--mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER)
mob.health = 10
mob.speed = 10
mob.bounty = 5
mob.hurtbox_radius = MOB_SIZE/2
mob.type = mob_type
local spec = get_mob_spec(mob_type)
mob.health = spec.health
mob.speed = spec.speed
mob.bounty = spec.bounty
mob.hurtbox_radius = spec.hurtbox_radius
register_entity(MOBS, mob)
return mob
end
local SPAWN_CHANCE = 45
local SPAWN_CHANCE = 25
function do_mob_spawning()
--if WIN:key_pressed"space" then
if math.random(SPAWN_CHANCE) == 1 then
--if #MOBS < 1 then
make_and_register_mob()
make_and_register_mob(MOB_TYPE.BEEPER)
end
end

108
src/projectile.lua

@ -2,7 +2,77 @@
PROJECTILES = {}
local function update_projectile(projectile, projectile_index)
PROJECTILE_TYPE = {
SHELL = 1,
LASER = 2,
}
PROJECTILE_SPECS = {
[PROJECTILE_TYPE.SHELL] = {
velocity = 13,
damage = 20,
hitbox_radius = 3
},
[PROJECTILE_TYPE.LASER] = {
velocity = 25,
damage = 5,
hitbox_radius = 10
},
}
function get_projectile_velocity(projectile_type)
return PROJECTILE_SPECS[projectile_type].velocity
end
function get_projectile_damage(projectile_type)
return PROJECTILE_SPECS[projectile_type].damage
end
function get_projectile_hitbox_radius(projectile_type)
return PROJECTILE_SPECS[projectile_type].hitbox_radius
end
function get_projectile_spec(projectile_type)
return PROJECTILE_SPECS[projectile_type]
end
local function update_projectile_shell(projectile, projectile_index)
projectile.position = projectile.position + projectile.vector * projectile.velocity
projectile.node.position2d = projectile.position
projectile.hex = pixel_to_hex(projectile.position)
projectile.props.z = projectile.props.z - 0.6 * am.delta_time
if projectile.props.z <= 0 then
log('exploded cuz we hit da grund')
delete_entity(PROJECTILES, projectile_index)
return true
end
-- check if we hit something
-- get a list of hexes that could have something we could hit on them
-- right now, it's just the hex we're on and all of its neighbours.
-- this is done to avoid having to check every mob on screen, though maybe it's not necessary.
local do_explode = false
local search_hexes = spiral_map(projectile.hex, 1)
for _,hex in pairs(search_hexes) do
for mob_index,mob in pairs(mobs_on_hex(hex)) do
if mob and circles_intersect(mob.position
, projectile.position
, mob.hurtbox_radius
, projectile.hitbox_radius) then
do_explode = true
break
end
end
end
if do_explode then
log('exploded cuz we hit a boi')
delete_entity(PROJECTILES, projectile_index)
return true
end
end
local function update_projectile_laser(projectile, projectile_index)
projectile.position = projectile.position + projectile.vector * projectile.velocity
projectile.node.position2d = projectile.position
projectile.hex = pixel_to_hex(projectile.position)
@ -60,16 +130,38 @@ local function update_projectile(projectile, projectile_index)
vplay_sfx(SOUNDS.HIT1, 0.5)
end
function make_and_register_projectile(hex, vector, velocity, damage, hitbox_radius)
function make_projectile_node(projectile_type, vector)
if projectile_type == PROJECTILE_TYPE.LASER then
return am.line(vector, vector*get_projectile_hitbox_radius(projectile_type), 3, COLORS.CLARET)
elseif projectile_type == PROJECTILE_TYPE.SHELL then
return am.circle(vec2(0), 3, COLORS.VERY_DARK_GRAY)
end
end
function get_projectile_update_function(projectile_type)
if projectile_type == PROJECTILE_TYPE.LASER then
return update_projectile_laser
elseif projectile_type == PROJECTILE_TYPE.SHELL then
return update_projectile_shell
end
end
function make_and_register_projectile(hex, projectile_type, vector)
local projectile = make_basic_entity(hex
, am.line(vector, vector*hitbox_radius, 3, COLORS.CLARET)
, update_projectile)
projectile.vector = vector
projectile.velocity = velocity
projectile.damage = damage
projectile.hitbox_radius = hitbox_radius
, make_projectile_node(projectile_type, vector)
, get_projectile_update_function(projectile_type))
projectile.type = projectile_type
projectile.vector = vector
local spec = get_projectile_spec(projectile_type)
projectile.velocity = spec.velocity
projectile.damage = spec.damage
projectile.hitbox_radius = spec.hitbox_radius
register_entity(PROJECTILES, projectile)
return projectile
end
function delete_all_projectiles()

117
src/tower.lua

@ -15,7 +15,7 @@ TOWER_TYPE = {
LIGHTHOUSE = 6
}
local TOWER_SPECS = {
TOWER_SPECS = {
[TOWER_TYPE.WALL] = {
name = "Wall",
placement_rules_text = "Place on grass or dirt",
@ -24,17 +24,17 @@ local TOWER_SPECS = {
icon_texture = TEXTURES.TOWER_WALL_ICON,
cost = 10,
range = 0,
props = {}
fire_rate = 2,
},
[TOWER_TYPE.HOWITZER] = {
name = "HOWITZER",
placement_rules_text = "Place on non-Water",
short_description = "Fires artillery. Range and cost increase with elevation of terrain underneath.",
texture = TEXTURES.TOWER_SHELL,
icon_texture = TEXTURES.TOWER_SHELL_ICON,
texture = TEXTURES.TOWER_HOWITZER,
icon_texture = TEXTURES.TOWER_HOWITZER_ICON,
cost = 20,
range = 10,
props = {}
fire_rate = 4,
},
[TOWER_TYPE.REDEYE] = {
name = "Redeye",
@ -44,7 +44,7 @@ local TOWER_SPECS = {
icon_texture = TEXTURES.TOWER_REDEYE_ICON,
cost = 20,
range = 12,
props = {}
fire_rate = 1,
},
[TOWER_TYPE.MOAT] = {
name = "Moat",
@ -54,7 +54,7 @@ local TOWER_SPECS = {
icon_texture = TEXTURES.TOWER_MOAT_ICON,
cost = 10,
range = 0,
props = {}
fire_rate = 2,
},
[TOWER_TYPE.RADAR] = {
name = "Radar",
@ -64,7 +64,7 @@ local TOWER_SPECS = {
icon_texture = TEXTURES.TOWER_RADAR_ICON,
cost = 20,
range = 0,
props = {}
fire_rate = 1,
},
[TOWER_TYPE.LIGHTHOUSE] = {
name = "Lighthouse",
@ -74,7 +74,7 @@ local TOWER_SPECS = {
icon_texture = TEXTURES.TOWER_LIGHTHOUSE_ICON,
cost = 20,
range = 8,
props = {}
fire_rate = 1,
},
}
@ -102,6 +102,9 @@ end
function get_tower_range(tower_type)
return TOWER_SPECS[tower_type].range
end
function get_tower_fire_rate(tower_type)
return TOWER_SPECS[tower_type].fire_rate
end
local function make_tower_sprite(tower_type)
return pack_texture_into_sprite(get_tower_texture(tower_type), HEX_PIXEL_WIDTH, HEX_PIXEL_HEIGHT)
@ -143,6 +146,9 @@ 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.HOWITZER then
return make_tower_sprite(tower_type)
elseif tower_type == TOWER_TYPE.LIGHTHOUSE then
return am.group(
make_tower_sprite(tower_type),
@ -165,7 +171,8 @@ local function make_tower_node(tower_type)
end_color_var = vec4(0.1),
emission_rate = 4,
start_particles = 4,
max_particles = 200
max_particles = 200,
warmup_time = 5
}
)
elseif tower_type == TOWER_TYPE.WALL then
@ -183,6 +190,9 @@ local function get_tower_update_function(tower_type)
if tower_type == TOWER_TYPE.REDEYE then
return update_tower_redeye
elseif tower_type == TOWER_TYPE.HOWITZER then
return update_tower_howitzer
elseif tower_type == TOWER_TYPE.LIGHTHOUSE then
return update_tower_lighthouse
end
@ -213,7 +223,19 @@ function tower_type_is_buildable_on(hex, tile, tower_type)
local blocked = mobs_blocking or towers_blocking
if tower_type == TOWER_TYPE.REDEYE then
if tower_type == TOWER_TYPE.HOWITZER 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.REDEYE then
if not mobs_blocking and towers_blocking then
blocked = false
for _,tower in pairs(TOWERS) do
@ -249,7 +271,7 @@ function update_tower_redeye(tower, tower_index)
if not tower.target_index then
for index,mob in pairs(MOBS) do
if mob then
local d = math.distance(mob.position, tower.position) / (HEX_SIZE * 2)
local d = math.distance(mob.hex, tower.hex)
if d <= tower.range then
tower.target_index = index
break
@ -260,15 +282,13 @@ function update_tower_redeye(tower, tower_index)
if MOBS[tower.target_index] == false then
tower.target_index = false
elseif (state.time - tower.last_shot_time) > 1 then
elseif (state.time - tower.last_shot_time) > tower.fire_rate then
local mob = MOBS[tower.target_index]
make_and_register_projectile(
tower.hex,
math.normalize(hex_to_pixel(mob.hex) - tower.position),
15,
5,
10
PROJECTILE_TYPE.LASER,
math.normalize(mob.position - tower.position)
)
tower.last_shot_time = state.time
@ -277,6 +297,38 @@ function update_tower_redeye(tower, tower_index)
end
end
function update_tower_howitzer(tower, tower_index)
if not tower.target_index then
for index,mob in pairs(MOBS) do
if mob then
local d = math.distance(mob.hex, tower.hex)
if d <= tower.range then
tower.target_index = index
break
end
end
end
else
if MOBS[tower.target_index] == false then
tower.target_index = false
elseif (state.time - tower.last_shot_time) > tower.fire_rate then
local mob = MOBS[tower.target_index]
local projectile = make_and_register_projectile(
tower.hex,
PROJECTILE_TYPE.SHELL,
math.normalize(mob.position - tower.position)
)
projectile.props.z = tower.props.z
tower.last_shot_time = state.time
play_sfx(SOUNDS.EXPLOSION2)
end
end
end
function update_tower_lighthouse(tower, tower_index)
-- check if there's a mob on a hex in our perimeter
for _,h in pairs(tower.perimeter) do
@ -293,6 +345,7 @@ function update_tower_lighthouse(tower, tower_index)
if made_it then
m.path = path
--[[
local area = spiral_map(tower.hex, tower.range)
for _,h in pairs(area) do
local node = state.map[h.x][h.y].node"circle"
@ -305,6 +358,7 @@ function update_tower_lighthouse(tower, tower_index)
am.tween(node, 0.3, { color = initial_color })
})
end
]]
end
end
end
@ -319,30 +373,39 @@ function make_and_register_tower(hex, tower_type)
)
tower.type = tower_type
tower.cost = get_tower_cost(tower_type)
tower.range = get_tower_range(tower_type)
tower.last_shot_time = tower.TOB -- a tower has never shot if its TOB == its last_shot_time
for k,v in pairs(TOWER_SPECS[tower_type].props) do
tower[k] = v
end
local spec = get_tower_spec(tower_type)
tower.cost = spec.cost
tower.range = spec.range
tower.fire_rate = spec.fire_rate
tower.last_shot_time = -spec.fire_rate
if tower_type == TOWER_TYPE.REDEYE then
local tile = state.map.get(hex.x, hex.y)
tile.elevation = tile.elevation + 0.6
elseif tower_type == TOWER_TYPE.HOWITZER then
local tile = state.map.get(hex.x, hex.y)
tile.elevation = tile.elevation + 0.6
tower.props.z = tile.elevation
elseif tower_type == TOWER_TYPE.LIGHTHOUSE then
tower.perimeter = ring_map(tower.hex, tower.range)
local tile = state.map.get(hex.x, hex.y)
tile.elevation = tile.elevation + 0.5
tile.elevation = tile.elevation + 0.6
elseif tower_type == TOWER_TYPE.WALL then
state.map.get(hex.x, hex.y).elevation = 0.5
state.map.get(hex.x, hex.y).elevation = 0.6
elseif tower_type == TOWER_TYPE.MOAT then
state.map.get(hex.x, hex.y).elevation = -0.49
state.map.get(hex.x, hex.y).elevation = -0.6
elseif tower_type == TOWER_TYPE.RADAR then
local tile = state.map.get(hex.x, hex.y)
tile.elevation = tile.elevation + 0.6
end
register_entity(TOWERS, tower)
return register_entity(TOWERS, tower)
end
function build_tower(hex, tower_type)

Loading…
Cancel
Save