gmtk-2024/game.lua

456 lines
17 KiB
Lua

local LevelData = require "leveldata"
local Game = {}
Game.__index = Game
MAX_POWER = 999999999999
local player_spr = love.graphics.newImage("res/sprite/player.png")
local ent_spr = {
enemy = love.graphics.newImage("res/sprite/enemy.png"),
enemy_neg = love.graphics.newImage("res/sprite/enemy_neg.png"),
elixir = love.graphics.newImage("res/sprite/elixir.png"),
gate = love.graphics.newImage("res/sprite/gate.png"),
vorpal = love.graphics.newImage("res/sprite/vorpal_sword.png"),
pickaxe = love.graphics.newImage("res/sprite/pickaxe.png"),
stairs_up = love.graphics.newImage("res/sprite/stairs_up.png"),
stairs_down = love.graphics.newImage("res/sprite/stairs_down.png"),
crown = love.graphics.newImage("res/sprite/crown.png"),
}
local held_spr = {
vorpal = love.graphics.newImage("res/sprite/vorpal_held.png"),
pickaxe = love.graphics.newImage("res/sprite/pickaxe_held.png"),
}
function Game.new()
local self = {
player_power = 5,
player_x = 1,
player_y = 8,
player_item = nil,
floor = 1,
level_data = LevelData:new(),
undo_history = {},
}
setmetatable(self, Game)
return self
end
function Game:keypressed(key,scancode,isrepeat)
if self.player_item ~= "crown" then
if scancode=="up" or scancode=="k" or scancode=="w" or scancode=="kp8" then
self:step(0,-1)
elseif scancode=="down" or scancode=="j" or scancode=="s" or scancode=="kp2" then
self:step(0,1)
elseif scancode=="left" or scancode=="h" or scancode=="a" or scancode=="kp4" then
self:step(-1,0)
elseif scancode=="right" or scancode=="l" or scancode=="d" or scancode=="kp6" then
self:step(1,0)
end
end
if scancode=="z" then
self:undo()
end
end
function Game:step(ox,oy)
tx = self.player_x + ox
ty = self.player_y + oy
--check if border
if tx < 1 or ty < 1 or tx > 15 or ty > 15 then
return
end
-- check if reinforced wall
if self.level_data[self.floor].walls[ty][tx]==2 then
return
end
-- check if normal wall
if self.level_data[self.floor].walls[ty][tx]==1 then
if self.player_item == "pickaxe" then
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"dig",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
wx = tx,
wy = ty,
}
}
--remove wall
self.level_data[self.floor].walls[ty][tx]=0
--remove item
self.player_item = nil
end
return
end
--check if entity
local move_legal = true
local entities = self.level_data[self.floor].entities
for i=1,#entities do
if entities[i].x == tx and entities[i].y == ty then
if entities[i].type == nil then --removed entity
break
elseif entities[i].type == "enemy" then
if self.player_item == "vorpal" then
self.undo_history[#self.undo_history+1] = {
"vorpal",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--remove item
self.player_item = nil
break
elseif entities[i].value >= self.player_power then
return
else
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"fight",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
power = self.player_power,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--absorb power
self.player_power = self.player_power + entities[i].value
break
end
elseif entities[i].type == "enemy_neg" then
if self.player_item == "vorpal" then
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"vorpal",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--remove item
self.player_item = nil
break
elseif entities[i].value >= self.player_power then
return
else
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"fight",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
power = self.player_power,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--absorb power
self.player_power = self.player_power - entities[i].value
break
end
elseif entities[i].type == "elixir" then
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"fight",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
power = self.player_power,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--double power
self.player_power = self.player_power * 2
break
elseif entities[i].type == "gate" then
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"fight",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
power = self.player_power,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--divide power by two
self.player_power = math.ceil(self.player_power / 2)
break
elseif entities[i].type == "pickaxe" then
--can't pick up if you have an item
if self.player_item then
return
end
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"item_get",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--equip item
self.player_item = "pickaxe"
break
elseif entities[i].type == "vorpal" then
--can't pick up if you have an item
if self.player_item then
return
end
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"item_get",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--equip item
self.player_item = "vorpal"
break
elseif entities[i].type == "crown" then
--can't pick up if you have an item
if self.player_item then
return
end
--push to undo memory
self.undo_history[#self.undo_history+1] = {
"item_get",
{
floor = self.floor,
px = self.player_x,
py = self.player_y,
ent_type = entities[i].type,
ent = entities[i],
}
}
--remove entity
entities[i].type = nil
--equip item
self.player_item = "crown"
break
elseif entities[i].type == "stairs_up" then
self.floor = self.floor + 1
break
elseif entities[i].type == "stairs_down" then
self.floor = self.floor - 1
break
else
return
end
end
end
--ensure the power cap is upheld to
self.player_power = math.min(self.player_power,MAX_POWER)
--move if possible
if move_legal then
self.player_x = tx
self.player_y = ty
end
end
function Game:undo()
if #self.undo_history == 0 then
return
end
undo_item = self.undo_history[#self.undo_history]
if undo_item[1] == "vorpal" then
self.floor = undo_item[2].floor
self.player_x = undo_item[2].px
self.player_y = undo_item[2].py
undo_item[2].ent.type = undo_item[2].ent_type
self.player_item = "vorpal"
elseif undo_item[1] == "dig" then
self.floor = undo_item[2].floor
self.player_x = undo_item[2].px
self.player_y = undo_item[2].py
self.level_data[self.floor].walls[undo_item[2].wy][undo_item[2].wx]=1
self.player_item = "pickaxe"
elseif undo_item[1] == "item_get" then
self.floor = undo_item[2].floor
self.player_x = undo_item[2].px
self.player_y = undo_item[2].py
undo_item[2].ent.type = undo_item[2].ent_type
self.player_item = nil
elseif undo_item[1] == "fight" then
--works for elixirs and gates too
self.floor = undo_item[2].floor
self.player_x = undo_item[2].px
self.player_y = undo_item[2].py
self.player_power = undo_item[2].power
undo_item[2].ent.type = undo_item[2].ent_type
else
assert(false)
end
--remove the item from stack
self.undo_history[#self.undo_history] = nil
end
function Game:update(dt)
end
function Game:draw()
love.graphics.setLineWidth(2)
love.graphics.push()
--win screen
if self.player_item == "crown" then
love.graphics.printf("YOU WIN!", 0,32,248,"center")
love.graphics.printf("YOU WIN!", 0,32,248,"center")
love.graphics.draw(ent_spr.crown, 116,52,0)
love.graphics.printf("You succeeded at scaling up the Tower of Scale, and displayed the mastery over the power scaling!", 8,80,232,"center")
love.graphics.printf("SCORE:"..player_power_to_string(self.player_power),0,128,248,"center")
if self.player_power >= 10000000000 then
love.graphics.printf("GRADE: S",0,144,248,"center")
elseif self.player_power >= 1000000000 then
love.graphics.printf("GRADE: A",0,144,248,"center")
elseif self.player_power >= 100000000 then
love.graphics.printf("GRADE: B",0,144,248,"center")
elseif self.player_power >= 10000000 then
love.graphics.printf("GRADE: C",0,144,248,"center")
else
love.graphics.printf("GRADE: D",0,144,248,"center")
end
love.graphics.printf("Want to do better?\nPress Z to undo!", 0,200,248,"center")
love.graphics.pop()
return
end
--floor and walls
love.graphics.setColor(1,1,1,1)
love.graphics.rectangle("fill",0,0,248,248)
local walls = self.level_data[self.floor].walls
for x=1,15 do
for y=1,15 do
if walls[y][x]==2 then
love.graphics.setColor(1,1,1,1)
elseif walls[y][x]==1 then
love.graphics.setColor(0.85,0.85,0.85,1)
else
love.graphics.setColor(0.05,0.05,0.05,1)
end
love.graphics.rectangle("fill",x*16-12,y*16-12,16,16)
if walls[y][x]==2 then
love.graphics.setColor(0,0,0,1)
love.graphics.rectangle("fill",x*16-10,y*16-10,2,2)
love.graphics.rectangle("fill",x*16-5,y*16-10,2,2)
love.graphics.rectangle("fill",x*16-10,y*16-5,2,2)
love.graphics.rectangle("fill",x*16-5,y*16,2,2)
love.graphics.rectangle("fill",x*16,y*16-5,2,2)
love.graphics.rectangle("fill",x*16-10,y*16,2,2)
love.graphics.rectangle("fill",x*16,y*16-10,2,2)
love.graphics.rectangle("fill",x*16,y*16,2,2)
end
end
end
--entity sprites
love.graphics.setFont(FONT_DIGITS)
local entities = self.level_data[self.floor].entities
for i=1,#entities do
if entities[i].type then
--sprite
love.graphics.setColor(1,1,1,1)
love.graphics.draw(ent_spr[entities[i].type],entities[i].x*16-12,entities[i].y*16-12)
end
end
--entity values
love.graphics.setFont(FONT_DIGITS)
local entities = self.level_data[self.floor].entities
for i=1,#entities do
if entities[i].type then
if entities[i].value_str then
love.graphics.setColor(0,0,0,1)
love.graphics.printf(entities[i].value_str,entities[i].x*16-10,entities[i].y*16-1,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-12,entities[i].y*16-1,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-11,entities[i].y*16,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-11,entities[i].y*16-2,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-10,entities[i].y*16,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-10,entities[i].y*16-2,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-12,entities[i].y*16,16,"right")
love.graphics.printf(entities[i].value_str,entities[i].x*16-12,entities[i].y*16-2,16,"right")
love.graphics.setColor(1,1,1,1)
love.graphics.printf(entities[i].value_str,entities[i].x*16-11,entities[i].y*16-1,16,"right")
end
end
end
--player
love.graphics.setColor(1,1,1,1)
love.graphics.draw(player_spr,self.player_x*16-12,self.player_y*16-12)
--player info
love.graphics.setColor(1,1,1,1)
love.graphics.setFont(FONT_STANDARD)
love.graphics.print("FLOOR "..(self.floor>9 and self.floor or " "..self.floor).." POWER:"..player_power_to_string(self.player_power),1,249)
--tutorial textboxes
local textboxes = self.level_data[self.floor].textboxes
for i=1,#textboxes do
love.graphics.setColor(0,0,0,1)
love.graphics.rectangle("fill",textboxes[i].x,textboxes[i].y,textboxes[i].w,textboxes[i].h)
love.graphics.setColor(1,1,1,1)
love.graphics.rectangle("line",textboxes[i].x-1,textboxes[i].y-1,textboxes[i].w+2,textboxes[i].h+2)
love.graphics.printf(
textboxes[i].str,
textboxes[i].x+1,textboxes[i].y+1,textboxes[i].w-2,
"center"
)
end
--held item
if self.player_item then
love.graphics.draw(held_spr[self.player_item],72,250)
end
love.graphics.pop()
love.graphics.setColor(1,1,1,1)
end
return Game