various fixes
This commit is contained in:
parent
a9af97925e
commit
3ceb07f4d1
61 changed files with 49695 additions and 25250 deletions
207
room.lua
207
room.lua
|
|
@ -14,30 +14,46 @@ require "dialogue_manager"
|
|||
require "generic_moveable"
|
||||
require "generic_unmoveable"
|
||||
|
||||
-- cache loaded images so repeated placing/loading doesn't re-decode PNGs
|
||||
local placeImageCache = {}
|
||||
local function loadPlaceImage(path)
|
||||
if not placeImageCache[path] then
|
||||
placeImageCache[path] = love.graphics.newImage(path)
|
||||
end
|
||||
return placeImageCache[path]
|
||||
end
|
||||
|
||||
function Room:initialize(t)
|
||||
self.player = {}
|
||||
self.switches = { red = {}, green = {}, blue = {} }
|
||||
self.doors = {}
|
||||
self.collideables = { red = {}, green = {}, blue = {} }
|
||||
self.npcs = {}
|
||||
self.activeColors = {red = false, green = false, blue = false}
|
||||
self.colorsPlayerHas = {}
|
||||
|
||||
if t.name then
|
||||
print("loaded!!")
|
||||
self:load(t.name)
|
||||
self:load(t.name) -- registers objects (and any saved players) from the .sav
|
||||
print(t.name)
|
||||
|
||||
if t.player then
|
||||
-- entering from another room: place the carried colors at the entry point
|
||||
for _, color in ipairs(t.player.activeColors) do
|
||||
self:registerPlayer(Player:new(t.player.x, t.player.y, color), color)
|
||||
self:setActiveColor(color, true)
|
||||
end
|
||||
else
|
||||
for color, active in pairs(self.activeColors) do
|
||||
self:registerPlayer(Player:new(1, 1, color), color)
|
||||
if self.player[color] then
|
||||
self.player[color].x, self.player[color].y = t.player.x, t.player.y
|
||||
else
|
||||
self:registerPlayer(Player:new(t.player.x, t.player.y, color), color)
|
||||
end
|
||||
self:setActiveColor(color, true)
|
||||
end
|
||||
elseif not next(self.player) then
|
||||
-- fresh load of a room with no saved player: default red spawn so it's
|
||||
-- playable (the player starts with only red)
|
||||
self:registerPlayer(Player:new(1, 1, "red"), "red")
|
||||
self:setActiveColor("red", true)
|
||||
end
|
||||
self.exits = t.exits
|
||||
|
||||
self.name = t.name
|
||||
else
|
||||
self.colorsPlayerHas = {"red", "green", "blue"}
|
||||
|
|
@ -108,19 +124,44 @@ end
|
|||
|
||||
function Room:draw()
|
||||
|
||||
-- you only perceive the color channels the player actually has: with only a
|
||||
-- red copy, only the red layer is drawn (a stacked r+g+b wall shows as red,
|
||||
-- not white). Doors span all channels, so dedupe and draw them once.
|
||||
local visible = {}
|
||||
for _, c in ipairs(self.colorsPlayerHas) do visible[c] = true end
|
||||
|
||||
for color, player in pairs(self.player) do
|
||||
player:draw()
|
||||
if visible[color] then player:draw() end
|
||||
end
|
||||
local drawnDoors = {}
|
||||
for color, entityArray in pairs(self.collideables) do
|
||||
for _, entity in pairs(entityArray) do
|
||||
entity:draw()
|
||||
if visible[color] then
|
||||
for _, entity in pairs(entityArray) do
|
||||
if entity:isInstanceOf(Door) then
|
||||
if not drawnDoors[entity] then
|
||||
drawnDoors[entity] = true
|
||||
entity:draw()
|
||||
end
|
||||
else
|
||||
entity:draw()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for color, switchArray in pairs(self.switches) do
|
||||
for _, switch in pairs(switchArray) do
|
||||
switch:draw()
|
||||
if visible[color] then
|
||||
for _, switch in pairs(switchArray) do
|
||||
switch:draw()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- npcs (old "sages") are just markers for now: draw a "?" in their cell,
|
||||
-- tinted to only the channels the player has (never a white pixel)
|
||||
local cellW, cellH = width / gridWidth, height / gridHeight
|
||||
love.graphics.setColor(visible.red and 255 or 0, visible.green and 255 or 0, visible.blue and 255 or 0)
|
||||
for _, npc in ipairs(self.npcs) do
|
||||
love.graphics.print("?", (npc.x - 1) * cellW + cellW * 0.3, (npc.y - 1) * cellH + cellH * 0.1, 0, 2, 2)
|
||||
end
|
||||
end
|
||||
|
||||
function Room:createCollideablesMatrix()
|
||||
|
|
@ -369,10 +410,13 @@ function Room:colorIsActive(color)
|
|||
end
|
||||
|
||||
function Room:getInactiveColors()
|
||||
-- only colors the player actually has a copy of but that aren't active right
|
||||
-- now (a left-behind copy). Colors the player hasn't acquired have no copy to
|
||||
-- merge with, so they must not appear here.
|
||||
local colors = {}
|
||||
|
||||
for color, active in pairs(self.activeColors) do
|
||||
if not active then
|
||||
for _, color in ipairs(self.colorsPlayerHas) do
|
||||
if not self.activeColors[color] then
|
||||
table.insert(colors, color)
|
||||
end
|
||||
end
|
||||
|
|
@ -501,31 +545,54 @@ end
|
|||
|
||||
function Room:nextRoomCheck()
|
||||
for _, color in ipairs(self:getActiveColors()) do
|
||||
if not self:isInBounds(self.player[color]:getGridPos()) then
|
||||
nextRoom(self.player[color]:getGridPos())
|
||||
local player = self.player[color]
|
||||
if player and not self:isInBounds(player:getGridPos()) then
|
||||
nextRoom(player:getGridPos())
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Instantiate one object from the flat {class,color,x,y} schema. `class` is a
|
||||
-- key: the built-in behaviour classes (door/switch/player) plus the two generic
|
||||
-- grid pieces (wall/static_wall), and finally any art asset resolved by name via
|
||||
-- the globalAssetProperties registry (this is what the level editor places).
|
||||
function Room:createEntity(class, color, x, y)
|
||||
if class == "Door" then
|
||||
self:registerDoor(Door:new(x, y))
|
||||
elseif class == "Wall" then
|
||||
self:registerCollidable(Wall:new(x, y, color), {color})
|
||||
elseif class == "Switch" then
|
||||
self.registerSwitch(Switch:new(x, y), color)
|
||||
local entity
|
||||
if class == "door" then
|
||||
entity = Door:new(x, y)
|
||||
self:registerDoor(entity)
|
||||
elseif class == "switch" then
|
||||
entity = Switch:new(x, y, color)
|
||||
self:registerSwitch(entity, color)
|
||||
elseif class == "player" then
|
||||
self:registerPlayer(Player:new(x, y, color), color)
|
||||
elseif class == "Box" then
|
||||
self:registerCollidable(Box:new(x, y, color), {color})
|
||||
entity = Player:new(x, y, color)
|
||||
self:registerPlayer(entity, color)
|
||||
self:setActiveColor(color, true)
|
||||
elseif class == "wall" then
|
||||
entity = GenericUnmoveable:new(x, y, color, sprites.box[color])
|
||||
self:registerCollidable(entity, {color})
|
||||
elseif class == "static_wall" then
|
||||
entity = GenericUnmoveable:new(x, y, color, sprites.wall)
|
||||
self:registerCollidable(entity, {color})
|
||||
elseif class == "npc" then
|
||||
-- do something soon
|
||||
elseif class == "Ass" then
|
||||
--do this later when we have a more definite schema
|
||||
-- self:registerAssorted(Ass:new(x, y, color, name))
|
||||
self:registerNpc(x, y)
|
||||
else
|
||||
-- generic art asset placed via the editor, resolved by name
|
||||
local props = globalAssetProperties and globalAssetProperties[class]
|
||||
if props and props.sprites and props.sprites[color] then
|
||||
local sprite = loadPlaceImage(props.sprites[color])
|
||||
if props.class == "moveable" then
|
||||
entity = GenericMoveable:new(x, y, color, sprite, class)
|
||||
else
|
||||
entity = GenericUnmoveable:new(x, y, color, sprite)
|
||||
end
|
||||
self:registerCollidable(entity, {color})
|
||||
end
|
||||
end
|
||||
if entity then entity.saveClass = class end
|
||||
return entity
|
||||
end
|
||||
|
||||
function Room:registerCollidable(entityPointer, colorArray)
|
||||
|
|
@ -549,6 +616,10 @@ function Room:registerPlayer(entityPointer, color)
|
|||
self.player[color] = entityPointer
|
||||
end
|
||||
|
||||
function Room:registerNpc(x, y)
|
||||
table.insert(self.npcs, { x = x, y = y })
|
||||
end
|
||||
|
||||
function Room:getCellFromMousePos(mouseX, mouseY)
|
||||
local cell = {}
|
||||
cell.x = math.ceil(mouseX * gridWidth / width)
|
||||
|
|
@ -571,7 +642,10 @@ function Room:attemptDelete(mouseX, mouseY, color)
|
|||
-- player
|
||||
if self.player[c] and self.player[c]:occupiesCell(cell) then
|
||||
self.player[c] = nil
|
||||
self.colorsPlayerHas[c] = false
|
||||
self:setActiveColor(c, false)
|
||||
for i = #self.colorsPlayerHas, 1, -1 do
|
||||
if self.colorsPlayerHas[i] == c then table.remove(self.colorsPlayerHas, i) end
|
||||
end
|
||||
end
|
||||
-- collidables (iterate backwards so table.remove is safe)
|
||||
local entityArray = self.collideables[c]
|
||||
|
|
@ -591,14 +665,6 @@ function Room:attemptDelete(mouseX, mouseY, color)
|
|||
self:tick()
|
||||
end
|
||||
|
||||
local placeImageCache = {}
|
||||
local function loadPlaceImage(path)
|
||||
if not placeImageCache[path] then
|
||||
placeImageCache[path] = love.graphics.newImage(path)
|
||||
end
|
||||
return placeImageCache[path]
|
||||
end
|
||||
|
||||
function Room:attemptPlace(name, props, mouseX, mouseY, color)
|
||||
if not props or not props.sprites then return end
|
||||
local cell = self:getCellFromMousePos(mouseX, mouseY)
|
||||
|
|
@ -611,19 +677,11 @@ function Room:attemptPlace(name, props, mouseX, mouseY, color)
|
|||
colors = {color}
|
||||
end
|
||||
|
||||
-- one generic entity per placed channel; each lives on its own collision
|
||||
-- layer and the additive blend combines them into full color
|
||||
-- one entity per placed channel, via the same path level-loading uses; the
|
||||
-- additive blend combines the channels into full color
|
||||
for _, c in ipairs(colors) do
|
||||
local path = props.sprites[c]
|
||||
if path then
|
||||
local sprite = loadPlaceImage(path)
|
||||
local entity
|
||||
if props.class == "moveable" then
|
||||
entity = GenericMoveable:new(cell.x, cell.y, c, sprite, name)
|
||||
else
|
||||
entity = GenericUnmoveable:new(cell.x, cell.y, c, sprite)
|
||||
end
|
||||
self:registerCollidable(entity, {c})
|
||||
if props.sprites[c] then
|
||||
self:createEntity(name, c, cell.x, cell.y)
|
||||
end
|
||||
end
|
||||
self:tick()
|
||||
|
|
@ -640,10 +698,8 @@ function Room:load(name)
|
|||
end
|
||||
|
||||
function Room:deserialize(saveTable)
|
||||
for entityClass, entities in pairs(saveTable) do
|
||||
for _, entity in pairs(entities) do
|
||||
self:createEntity(entityClass, entity.color, entity.x, entity.y)
|
||||
end
|
||||
for _, obj in ipairs(saveTable.objects or {}) do
|
||||
self:createEntity(obj.class, obj.color, obj.x, obj.y)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -656,37 +712,44 @@ function Room:save()
|
|||
end
|
||||
|
||||
function Room:serialize()
|
||||
local level = {}
|
||||
local objects = {}
|
||||
|
||||
level.player = {}
|
||||
for _, color in ipairs(self:getInactiveColors()) do
|
||||
level.player[color] = self:getPlayerObject(color):getSerializationTable()
|
||||
local function emit(class, color, entity)
|
||||
local pos = entity:getGridPos()
|
||||
table.insert(objects, { class = class, color = color, x = pos.x, y = pos.y })
|
||||
end
|
||||
|
||||
level.door = {}
|
||||
for _, door in pairs(self:getDoors()) do
|
||||
table.insert(level.door, doors:getSerializationTable())
|
||||
for color, player in pairs(self.player) do
|
||||
emit("player", color, player)
|
||||
end
|
||||
|
||||
|
||||
for color, collideableArray in pairs(self:getCollideables()) do
|
||||
-- collideables hold walls/static_walls/generics on one color each, plus
|
||||
-- doors registered across all three colors -> dedupe doors, emit once
|
||||
local seenDoor = {}
|
||||
for color, collideableArray in pairs(self.collideables) do
|
||||
for _, collideable in pairs(collideableArray) do
|
||||
if not collideable:isInstanceOf("Door") then --for now, we might change doors up some
|
||||
local entityClass = collideable:getClass()
|
||||
if not level[entityClass] then level[entityClass] = {} end
|
||||
table.insert(level[entityClass], collideable:getSerializationTable())
|
||||
if collideable:isInstanceOf(Door) then
|
||||
if not seenDoor[collideable] then
|
||||
seenDoor[collideable] = true
|
||||
emit("door", nil, collideable)
|
||||
end
|
||||
else
|
||||
emit(collideable.saveClass or "unmoveable", color, collideable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
level.switch = {}
|
||||
for color, switchArray in pairs(self:getSwitches()) do
|
||||
for color, switchArray in pairs(self.switches) do
|
||||
for _, switch in ipairs(switchArray) do
|
||||
table.insert(level.switch, switch:getSerializationTable())
|
||||
emit("switch", color, switch)
|
||||
end
|
||||
end
|
||||
|
||||
return level
|
||||
for _, npc in ipairs(self.npcs) do
|
||||
table.insert(objects, { class = "npc", x = npc.x, y = npc.y })
|
||||
end
|
||||
|
||||
return { objects = objects }
|
||||
end
|
||||
|
||||
function nextRoom(pos)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue