Database now handles entities
parent
a35d481b15
commit
240587344d
41
src/game.zig
41
src/game.zig
|
@ -207,6 +207,7 @@ fn loadLevel(lvl: usize) !void {
|
||||||
map.clear();
|
map.clear();
|
||||||
circuit.clearMap();
|
circuit.clearMap();
|
||||||
level = try db.levelLoad(alloc, lvl);
|
level = try db.levelLoad(alloc, lvl);
|
||||||
|
const levelc = world.Coordinate.fromWorld(level.world_x, level.world_y);
|
||||||
|
|
||||||
try extract.extractLevel(.{
|
try extract.extractLevel(.{
|
||||||
.alloc = frame_alloc,
|
.alloc = frame_alloc,
|
||||||
|
@ -225,9 +226,11 @@ fn loadLevel(lvl: usize) !void {
|
||||||
{
|
{
|
||||||
_ = try wires.resize(0);
|
_ = try wires.resize(0);
|
||||||
var a: usize = 0;
|
var a: usize = 0;
|
||||||
while (level.getWire(a)) |wire| : (a += 1) {
|
while (db.getWire(level, a)) |wire| : (a += 1) {
|
||||||
const p1 = util.vec2ToVec2f(Vec2{ wire[0].x, wire[0].y } * tile_size + Vec2{ 4, 4 });
|
const coord0 = wire[0].coord.subC(levelc);
|
||||||
const p2 = util.vec2ToVec2f(Vec2{ wire[1].x, wire[1].y } * tile_size + Vec2{ 4, 4 });
|
const coord1 = wire[1].coord.subC(levelc);
|
||||||
|
const p1 = util.vec2ToVec2f(coord0.toVec2() * tile_size + Vec2{ 4, 4 });
|
||||||
|
const p2 = util.vec2ToVec2f(coord1.toVec2() * tile_size + Vec2{ 4, 4 });
|
||||||
|
|
||||||
var w = try wires.addOne();
|
var w = try wires.addOne();
|
||||||
_ = try w.nodes.resize(0);
|
_ = try w.nodes.resize(0);
|
||||||
|
@ -249,15 +252,16 @@ fn loadLevel(lvl: usize) !void {
|
||||||
|
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (level.getDoor(i)) |door| : (i += 1) {
|
while (db.getDoor(level, i)) |door| : (i += 1) {
|
||||||
try circuit.addDoor(Vec2{ door.x, door.y });
|
const coord = door.coord.subC(levelc);
|
||||||
|
try circuit.addDoor(coord.toVec2());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (level.getJoin(i)) |join| : (i += 1) {
|
while (level.getJoin(i)) |join| : (i += 1) {
|
||||||
const globalc = Coord.fromWorld(level.world_x, level.world_y).addC(join);
|
const globalc = levelc.addC(join);
|
||||||
var e = false;
|
var e = false;
|
||||||
if (db.isEnergized(globalc)) {
|
if (db.isEnergized(globalc)) {
|
||||||
e = true;
|
e = true;
|
||||||
|
@ -270,9 +274,10 @@ fn loadLevel(lvl: usize) !void {
|
||||||
try coins.resize(0);
|
try coins.resize(0);
|
||||||
// if (!try Disk.load()) {
|
// if (!try Disk.load()) {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (level.getCoin(i)) |coin| : (i += 1) {
|
while (db.getCoin(level, i)) |coin| : (i += 1) {
|
||||||
|
const coord = coin.coord.subC(levelc);
|
||||||
try coins.append(.{
|
try coins.append(.{
|
||||||
.pos = Pos.init(util.vec2ToVec2f(Vec2{ coin.x, coin.y } * tile_size)),
|
.pos = Pos.init(util.vec2ToVec2f(coord.toVec2() * tile_size)),
|
||||||
.sprite = .{ .offset = .{ 0, 0 }, .size = .{ 8, 8 }, .index = 4, .flags = .{ .bpp = .b2 } },
|
.sprite = .{ .offset = .{ 0, 0 }, .size = .{ 8, 8 }, .index = 4, .flags = .{ .bpp = .b2 } },
|
||||||
.anim = Anim{ .anim = &anim_store.coin },
|
.anim = Anim{ .anim = &anim_store.coin },
|
||||||
.area = .{ .pos = .{ 0, 0 }, .size = .{ 8, 8 } },
|
.area = .{ .pos = .{ 0, 0 }, .size = .{ 8, 8 } },
|
||||||
|
@ -342,18 +347,20 @@ pub fn start() !void {
|
||||||
|
|
||||||
db = try world.Database.init(db_alloc);
|
db = try world.Database.init(db_alloc);
|
||||||
|
|
||||||
try loadLevel(0);
|
const spawn = db.getSpawn();
|
||||||
|
|
||||||
const spawnArr = level.getSpawn() orelse return error.NoPlayerSpawn;
|
const spawn_worldc = spawn.coord.toWorld();
|
||||||
const spawn = Vec2{ spawnArr[0], spawnArr[1] };
|
const first_level = db.findLevel(spawn_worldc[0], spawn_worldc[1]) orelse return error.SpawnOutOfBounds;
|
||||||
|
|
||||||
camera = @divTrunc(spawn, @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));
|
try loadLevel(first_level);
|
||||||
|
|
||||||
|
camera = @divTrunc(spawn.coord.toVec2(), @splat(2, @as(i32, 20))) * @splat(2, @as(i32, 20));
|
||||||
|
|
||||||
const tile_size = Vec2{ 8, 8 };
|
const tile_size = Vec2{ 8, 8 };
|
||||||
const offset = Vec2{ 4, 8 };
|
const offset = Vec2{ 4, 8 };
|
||||||
|
|
||||||
player = .{
|
player = .{
|
||||||
.pos = Pos.init(util.vec2ToVec2f(spawn * tile_size + offset)),
|
.pos = Pos.init(util.vec2ToVec2f(spawn.coord.toVec2() * tile_size + offset)),
|
||||||
.control = .{ .controller = .player, .state = .stand },
|
.control = .{ .controller = .player, .state = .stand },
|
||||||
.sprite = .{ .offset = .{ -4, -8 }, .size = .{ 8, 8 }, .index = 8, .flags = .{ .bpp = .b2 } },
|
.sprite = .{ .offset = .{ -4, -8 }, .size = .{ 8, 8 }, .index = 8, .flags = .{ .bpp = .b2 } },
|
||||||
.physics = .{ .friction = Vec2f{ 0.15, 0.1 }, .gravity = Vec2f{ 0, 0.25 } },
|
.physics = .{ .friction = Vec2f{ 0.15, 0.1 }, .gravity = Vec2f{ 0, 0.25 } },
|
||||||
|
@ -713,15 +720,19 @@ fn updateCircuit() !void {
|
||||||
|
|
||||||
// Add doors to map
|
// Add doors to map
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (level.getDoor(i)) |door| : (i += 1) {
|
while (db.getDoor(level, i)) |door| : (i += 1) {
|
||||||
const tile: u8 = if (door.kind == .Door) world.Tiles.Door else world.Tiles.Trapdoor;
|
const tile: u8 = if (door.kind == .Door) world.Tiles.Door else world.Tiles.Trapdoor;
|
||||||
try map.set_cell(.{ door.x, door.y }, tile);
|
const globalc = world.Coordinate.fromWorld(level.world_x, level.world_y);
|
||||||
|
const coord = door.coord.subC(globalc);
|
||||||
|
w4.tracef("[getDoor] (%d, %d)", coord.val[0], coord.val[1]);
|
||||||
|
try map.set_cell(coord.toVec2(), tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove doors that have been unlocked
|
// Remove doors that have been unlocked
|
||||||
const enabledDoors = try circuit.enabledDoors(frame_alloc);
|
const enabledDoors = try circuit.enabledDoors(frame_alloc);
|
||||||
defer frame_alloc.free(enabledDoors.items);
|
defer frame_alloc.free(enabledDoors.items);
|
||||||
for (enabledDoors.items) |door| {
|
for (enabledDoors.items) |door| {
|
||||||
|
w4.tracef("[enabledDoors] (%d, %d)", door[0], door[1]);
|
||||||
try map.set_cell(door, world.Tiles.Empty);
|
try map.set_cell(door, world.Tiles.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ export fn update() void {
|
||||||
error.EndOfStream => showErr(@errorName(e)),
|
error.EndOfStream => showErr(@errorName(e)),
|
||||||
error.OutOfMemory => showErr(@errorName(e)),
|
error.OutOfMemory => showErr(@errorName(e)),
|
||||||
error.NullTiles => showErr(@errorName(e)),
|
error.NullTiles => showErr(@errorName(e)),
|
||||||
error.NoPlayerSpawn => showErr(@errorName(e)),
|
error.SpawnOutOfBounds => showErr(@errorName(e)),
|
||||||
error.InvalidLevel => showErr(@errorName(e)),
|
error.InvalidLevel => showErr(@errorName(e)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
194
src/world.zig
194
src/world.zig
|
@ -178,20 +178,37 @@ pub const Coordinate = struct {
|
||||||
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
|
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sub(coord: Coordinate, val: [2]i16) Coordinate {
|
||||||
|
return .{ .val = .{ coord.val[0] - val[0], coord.val[1] - val[1] } };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addC(coord: Coordinate, other: Coordinate) Coordinate {
|
pub fn addC(coord: Coordinate, other: Coordinate) Coordinate {
|
||||||
return .{ .val = .{ coord.val[0] + other.val[0], coord.val[1] + other.val[1] } };
|
return .{ .val = .{ coord.val[0] + other.val[0], coord.val[1] + other.val[1] } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subC(coord: Coordinate, other: Coordinate) Coordinate {
|
||||||
|
return .{ .val = .{ coord.val[0] - other.val[0], coord.val[1] - other.val[1] } };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eq(coord: Coordinate, other: Coordinate) bool {
|
pub fn eq(coord: Coordinate, other: Coordinate) bool {
|
||||||
return coord.val[0] == other.val[0] and coord.val[1] == other.val[1];
|
return coord.val[0] == other.val[0] and coord.val[1] == other.val[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn within(coord: Coord, nw: Coord, se: Coord) bool {
|
||||||
|
return coord.val[0] >= nw.val[0] and coord.val[1] >= nw.val[1] and
|
||||||
|
coord.val[0] < se.val[0] and coord.val[1] < se.val[1];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toWorld(coord: Coordinate) [2]i8 {
|
pub fn toWorld(coord: Coordinate) [2]i8 {
|
||||||
const world_x = @intCast(i8, @divFloor(coord.val[0], LEVELSIZE));
|
const world_x = @intCast(i8, @divFloor(coord.val[0], LEVELSIZE));
|
||||||
const world_y = @intCast(i8, @divFloor(coord.val[1], LEVELSIZE));
|
const world_y = @intCast(i8, @divFloor(coord.val[1], LEVELSIZE));
|
||||||
return .{ world_x, world_y };
|
return .{ world_x, world_y };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toVec2(coord: Coordinate) @Vector(2, i32) {
|
||||||
|
return .{ coord.val[0], coord.val[1] };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fromWorld(x: i8, y: i8) Coordinate {
|
pub fn fromWorld(x: i8, y: i8) Coordinate {
|
||||||
return .{ .val = .{
|
return .{ .val = .{
|
||||||
@intCast(i16, x) * 20,
|
@intCast(i16, x) * 20,
|
||||||
|
@ -222,50 +239,37 @@ pub const Level = struct {
|
||||||
world_y: i8,
|
world_y: i8,
|
||||||
width: u16,
|
width: u16,
|
||||||
size: u16,
|
size: u16,
|
||||||
entity_count: u16,
|
|
||||||
tiles: ?[]TileData,
|
tiles: ?[]TileData,
|
||||||
entities: ?[]Entity = null,
|
|
||||||
|
|
||||||
pub fn init(x: u8, y: u8, width: u16, buf: []TileData, entities: []Entity) Level {
|
pub fn init(x: u8, y: u8, width: u16, buf: []TileData) Level {
|
||||||
return Level{
|
return Level{
|
||||||
.world_x = x,
|
.world_x = x,
|
||||||
.world_y = y,
|
.world_y = y,
|
||||||
.width = width,
|
.width = width,
|
||||||
.size = buf.len,
|
.size = buf.len,
|
||||||
.entity_count = entities.len,
|
|
||||||
.tiles = buf,
|
.tiles = buf,
|
||||||
.entities = entities,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculateSize(level: Level) !usize {
|
pub fn calculateSize(level: Level) !usize {
|
||||||
const tiles = level.tiles orelse return error.NullTiles;
|
const tiles = level.tiles orelse return error.NullTiles;
|
||||||
const entities = level.entities orelse return error.NullEntities;
|
|
||||||
return @sizeOf(i8) + // world_x
|
return @sizeOf(i8) + // world_x
|
||||||
@sizeOf(i8) + // world_y
|
@sizeOf(i8) + // world_y
|
||||||
@sizeOf(u16) + // width
|
@sizeOf(u16) + // width
|
||||||
@sizeOf(u16) + // size
|
@sizeOf(u16) + // size
|
||||||
@sizeOf(u16) + // entity_count
|
tiles.len;
|
||||||
tiles.len + //
|
|
||||||
entities.len * 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(level: Level, writer: anytype) !void {
|
pub fn write(level: Level, writer: anytype) !void {
|
||||||
var tiles = level.tiles orelse return error.NullTiles;
|
var tiles = level.tiles orelse return error.NullTiles;
|
||||||
var entities = level.entities orelse return error.NullEntities;
|
|
||||||
try writer.writeInt(i8, level.world_x, .Little);
|
try writer.writeInt(i8, level.world_x, .Little);
|
||||||
try writer.writeInt(i8, level.world_y, .Little);
|
try writer.writeInt(i8, level.world_y, .Little);
|
||||||
try writer.writeInt(u16, level.width, .Little);
|
try writer.writeInt(u16, level.width, .Little);
|
||||||
try writer.writeInt(u16, level.size, .Little);
|
try writer.writeInt(u16, level.size, .Little);
|
||||||
try writer.writeInt(u16, level.entity_count, .Little);
|
|
||||||
|
|
||||||
for (tiles) |tile| {
|
for (tiles) |tile| {
|
||||||
try writer.writeByte(tile.toByte());
|
try writer.writeByte(tile.toByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entities) |entity| {
|
|
||||||
try entity.write(writer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(reader: anytype) !Level {
|
pub fn read(reader: anytype) !Level {
|
||||||
|
@ -274,9 +278,7 @@ pub const Level = struct {
|
||||||
.world_y = try reader.readInt(i8, .Little),
|
.world_y = try reader.readInt(i8, .Little),
|
||||||
.width = try reader.readInt(u16, .Little),
|
.width = try reader.readInt(u16, .Little),
|
||||||
.size = try reader.readInt(u16, .Little),
|
.size = try reader.readInt(u16, .Little),
|
||||||
.entity_count = try reader.readInt(u16, .Little),
|
|
||||||
.tiles = null,
|
.tiles = null,
|
||||||
.entities = null,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,25 +291,6 @@ pub const Level = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readEntities(level: *Level, reader: anytype, buf: []Entity) !void {
|
|
||||||
std.debug.assert(buf.len >= level.entity_count);
|
|
||||||
level.entities = buf;
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < level.entity_count) : (i += 1) {
|
|
||||||
buf[i] = try Entity.read(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getSpawn(level: *Level) ?[2]i16 {
|
|
||||||
std.debug.assert(level.entities != null);
|
|
||||||
for (level.entities.?) |entity| {
|
|
||||||
if (entity.kind == .Player) {
|
|
||||||
return [2]i16{ entity.x, entity.y };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getTile(level: Level, globalc: Coord) ?TileData {
|
pub fn getTile(level: Level, globalc: Coord) ?TileData {
|
||||||
const tiles = level.tiles orelse return null;
|
const tiles = level.tiles orelse return null;
|
||||||
const worldc = globalc.toLevelTopLeft();
|
const worldc = globalc.toLevelTopLeft();
|
||||||
|
@ -338,47 +321,6 @@ pub const Level = struct {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getWire(level: *Level, num: usize) ?[2]Entity {
|
|
||||||
std.debug.assert(level.entities != null);
|
|
||||||
var node_begin: ?Entity = null;
|
|
||||||
var wire_count: usize = 0;
|
|
||||||
for (level.entities.?) |entity| {
|
|
||||||
if (entity.kind == .WireNode or entity.kind == .WireAnchor) {
|
|
||||||
node_begin = entity;
|
|
||||||
} else if (entity.kind == .WireEndNode or entity.kind == .WireEndAnchor) {
|
|
||||||
if (node_begin) |begin| {
|
|
||||||
if (wire_count == num) return [2]Entity{ begin, entity };
|
|
||||||
}
|
|
||||||
wire_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getDoor(level: *Level, num: usize) ?Entity {
|
|
||||||
std.debug.assert(level.entities != null);
|
|
||||||
var count: usize = 0;
|
|
||||||
for (level.entities.?) |entity| {
|
|
||||||
if (entity.kind == .Door or entity.kind == .Trapdoor) {
|
|
||||||
if (count == num) return entity;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getCoin(level: *Level, num: usize) ?Entity {
|
|
||||||
std.debug.assert(level.entities != null);
|
|
||||||
var count: usize = 0;
|
|
||||||
for (level.entities.?) |entity| {
|
|
||||||
if (entity.kind == .Coin) {
|
|
||||||
if (count == num) return entity;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// AutoTile algorithm datatypes
|
// AutoTile algorithm datatypes
|
||||||
|
@ -493,8 +435,7 @@ pub const EntityKind = enum(u8) {
|
||||||
|
|
||||||
pub const Entity = struct {
|
pub const Entity = struct {
|
||||||
kind: EntityKind,
|
kind: EntityKind,
|
||||||
x: i16,
|
coord: Coordinate,
|
||||||
y: i16,
|
|
||||||
|
|
||||||
pub fn calculateSize() usize {
|
pub fn calculateSize() usize {
|
||||||
return @sizeOf(u8) + // kind
|
return @sizeOf(u8) + // kind
|
||||||
|
@ -504,15 +445,13 @@ pub const Entity = struct {
|
||||||
|
|
||||||
pub fn write(entity: Entity, writer: anytype) !void {
|
pub fn write(entity: Entity, writer: anytype) !void {
|
||||||
try writer.writeInt(u8, @enumToInt(entity.kind), .Little);
|
try writer.writeInt(u8, @enumToInt(entity.kind), .Little);
|
||||||
try writer.writeInt(i16, entity.x, .Little);
|
try entity.coord.write(writer);
|
||||||
try writer.writeInt(i16, entity.y, .Little);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(reader: anytype) !Entity {
|
pub fn read(reader: anytype) !Entity {
|
||||||
return Entity{
|
return Entity{
|
||||||
.kind = @intToEnum(EntityKind, try reader.readInt(u8, .Little)),
|
.kind = @intToEnum(EntityKind, try reader.readInt(u8, .Little)),
|
||||||
.x = try reader.readInt(i16, .Little),
|
.coord = try Coordinate.read(reader),
|
||||||
.y = try reader.readInt(i16, .Little),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -546,11 +485,14 @@ pub const LevelHeader = struct {
|
||||||
pub fn write(
|
pub fn write(
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
level_headers: []LevelHeader,
|
level_headers: []LevelHeader,
|
||||||
|
entities: []Entity,
|
||||||
circuit_nodes: []CircuitNode,
|
circuit_nodes: []CircuitNode,
|
||||||
levels: []Level,
|
levels: []Level,
|
||||||
) !void {
|
) !void {
|
||||||
// Write number of levels
|
// Write number of levels
|
||||||
try writer.writeInt(u16, @intCast(u16, level_headers.len), .Little);
|
try writer.writeInt(u16, @intCast(u16, level_headers.len), .Little);
|
||||||
|
// Write number of entities
|
||||||
|
try writer.writeInt(u16, @intCast(u16, entities.len), .Little);
|
||||||
// Write number of circuit nodes
|
// Write number of circuit nodes
|
||||||
try writer.writeInt(u16, @intCast(u16, circuit_nodes.len), .Little);
|
try writer.writeInt(u16, @intCast(u16, circuit_nodes.len), .Little);
|
||||||
|
|
||||||
|
@ -559,6 +501,11 @@ pub fn write(
|
||||||
try lvl_header.write(writer);
|
try lvl_header.write(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write entity data
|
||||||
|
for (entities) |entity| {
|
||||||
|
try entity.write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
// Write node data
|
// Write node data
|
||||||
for (circuit_nodes) |node| {
|
for (circuit_nodes) |node| {
|
||||||
try node.write(writer);
|
try node.write(writer);
|
||||||
|
@ -574,6 +521,7 @@ const Cursor = std.io.FixedBufferStream([]const u8);
|
||||||
pub const Database = struct {
|
pub const Database = struct {
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
level_info: []LevelHeader,
|
level_info: []LevelHeader,
|
||||||
|
entities: []Entity,
|
||||||
circuit_info: []CircuitNode,
|
circuit_info: []CircuitNode,
|
||||||
level_data_begin: usize,
|
level_data_begin: usize,
|
||||||
|
|
||||||
|
@ -589,6 +537,8 @@ pub const Database = struct {
|
||||||
|
|
||||||
// read number of levels
|
// read number of levels
|
||||||
const level_count = try reader.readInt(u16, .Little);
|
const level_count = try reader.readInt(u16, .Little);
|
||||||
|
// read number of entities
|
||||||
|
const entity_count = try reader.readInt(u16, .Little);
|
||||||
// read number of nodes
|
// read number of nodes
|
||||||
const node_count = try reader.readInt(u16, .Little);
|
const node_count = try reader.readInt(u16, .Little);
|
||||||
|
|
||||||
|
@ -599,23 +549,34 @@ pub const Database = struct {
|
||||||
level_headers[i] = try LevelHeader.read(reader);
|
level_headers[i] = try LevelHeader.read(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read entities
|
||||||
|
var entities = try alloc.alloc(Entity, entity_count);
|
||||||
|
|
||||||
|
for (entities) |_, i| {
|
||||||
|
entities[i] = try Entity.read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read circuits
|
||||||
var circuit_nodes = try alloc.alloc(CircuitNode, node_count);
|
var circuit_nodes = try alloc.alloc(CircuitNode, node_count);
|
||||||
|
|
||||||
// read headers
|
|
||||||
for (circuit_nodes) |_, i| {
|
for (circuit_nodes) |_, i| {
|
||||||
circuit_nodes[i] = try CircuitNode.read(reader);
|
circuit_nodes[i] = try CircuitNode.read(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save where the rest of the data ended, and the level data begins
|
||||||
var level_data_begin = @intCast(usize, try cursor.getPos());
|
var level_data_begin = @intCast(usize, try cursor.getPos());
|
||||||
|
|
||||||
return Database{
|
return Database{
|
||||||
.cursor = cursor,
|
.cursor = cursor,
|
||||||
.level_info = level_headers,
|
.level_info = level_headers,
|
||||||
|
.entities = entities,
|
||||||
.circuit_info = circuit_nodes,
|
.circuit_info = circuit_nodes,
|
||||||
.level_data_begin = level_data_begin,
|
.level_data_begin = level_data_begin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Level functions
|
||||||
|
|
||||||
pub fn levelInfo(db: *Database, level: usize) !Level {
|
pub fn levelInfo(db: *Database, level: usize) !Level {
|
||||||
if (level > db.level_info.len) return error.InvalidLevel;
|
if (level > db.level_info.len) return error.InvalidLevel;
|
||||||
try db.cursor.seekTo(db.level_data_begin + db.level_info[level].offset);
|
try db.cursor.seekTo(db.level_data_begin + db.level_info[level].offset);
|
||||||
|
@ -632,9 +593,6 @@ pub const Database = struct {
|
||||||
var level_buf = try alloc.alloc(TileData, level_info.size);
|
var level_buf = try alloc.alloc(TileData, level_info.size);
|
||||||
try level_info.readTiles(reader, level_buf);
|
try level_info.readTiles(reader, level_buf);
|
||||||
|
|
||||||
var entity_buf = try alloc.alloc(Entity, level_info.entity_count);
|
|
||||||
try level_info.readEntities(reader, entity_buf);
|
|
||||||
|
|
||||||
return level_info;
|
return level_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,6 +605,8 @@ pub const Database = struct {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Circuit functions
|
||||||
|
|
||||||
fn getNodeID(db: *Database, coord: Coord) ?NodeID {
|
fn getNodeID(db: *Database, coord: Coord) ?NodeID {
|
||||||
for (db.circuit_info) |node, i| {
|
for (db.circuit_info) |node, i| {
|
||||||
if (!coord.eq(node.coord)) continue;
|
if (!coord.eq(node.coord)) continue;
|
||||||
|
@ -752,6 +712,66 @@ pub const Database = struct {
|
||||||
if (i == 0) break;
|
if (i == 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entity functions
|
||||||
|
|
||||||
|
pub fn getWire(database: *Database, level: Level, num: usize) ?[2]Entity {
|
||||||
|
const nw = Coord.fromWorld(level.world_x, level.world_y);
|
||||||
|
const se = nw.add(.{ 20, 20 });
|
||||||
|
var node_begin: ?Entity = null;
|
||||||
|
var wire_count: usize = 0;
|
||||||
|
for (database.entities) |entity| {
|
||||||
|
if (!entity.coord.within(nw, se)) continue;
|
||||||
|
if (entity.kind == .WireNode or entity.kind == .WireAnchor) {
|
||||||
|
node_begin = entity;
|
||||||
|
} else if (entity.kind == .WireEndNode or entity.kind == .WireEndAnchor) {
|
||||||
|
if (node_begin) |begin| {
|
||||||
|
if (wire_count == num) return [2]Entity{ begin, entity };
|
||||||
|
}
|
||||||
|
wire_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDoor(database: *Database, level: Level, num: usize) ?Entity {
|
||||||
|
const nw = Coord.fromWorld(level.world_x, level.world_y);
|
||||||
|
const se = nw.add(.{ 20, 20 });
|
||||||
|
var count: usize = 0;
|
||||||
|
for (database.entities) |entity| {
|
||||||
|
if (!entity.coord.within(nw, se)) continue;
|
||||||
|
if (entity.kind == .Door or entity.kind == .Trapdoor) {
|
||||||
|
if (count == num) return entity;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getCoin(database: *Database, level: Level, num: usize) ?Entity {
|
||||||
|
const nw = Coord.fromWorld(level.world_x, level.world_y);
|
||||||
|
const se = nw.add(.{ 20, 20 });
|
||||||
|
var count: usize = 0;
|
||||||
|
for (database.entities) |entity| {
|
||||||
|
if (!entity.coord.within(nw, se)) continue;
|
||||||
|
if (entity.kind == .Coin) {
|
||||||
|
if (count == num) return entity;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the players spawn location.
|
||||||
|
/// Assumes a spawn exists and that there is only one of them
|
||||||
|
pub fn getSpawn(database: *Database) Entity {
|
||||||
|
for (database.entities) |entity| {
|
||||||
|
if (entity.kind == .Player) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@panic("No player spawn found! Invalid state");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// All levels in the game. If two rooms are next to each other, they
|
// All levels in the game. If two rooms are next to each other, they
|
||||||
|
|
|
@ -55,10 +55,11 @@ fn make(step: *std.build.Step) !void {
|
||||||
var levels = std.ArrayList(world.Level).init(allocator);
|
var levels = std.ArrayList(world.Level).init(allocator);
|
||||||
defer levels.deinit();
|
defer levels.deinit();
|
||||||
|
|
||||||
for (ldtk.levels) |level| {
|
|
||||||
var entity_array = std.ArrayList(world.Entity).init(allocator);
|
var entity_array = std.ArrayList(world.Entity).init(allocator);
|
||||||
defer entity_array.deinit();
|
defer entity_array.deinit();
|
||||||
|
|
||||||
|
for (ldtk.levels) |level| {
|
||||||
|
std.log.warn("Level: {}", .{levels.items.len});
|
||||||
const parsed_level = try parseLevel(.{
|
const parsed_level = try parseLevel(.{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.ldtk = ldtk,
|
.ldtk = ldtk,
|
||||||
|
@ -70,7 +71,6 @@ fn make(step: *std.build.Step) !void {
|
||||||
}
|
}
|
||||||
defer for (levels.items) |level| {
|
defer for (levels.items) |level| {
|
||||||
allocator.free(level.tiles.?);
|
allocator.free(level.tiles.?);
|
||||||
allocator.free(level.entities.?);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var circuit = try buildCircuit(allocator, levels.items);
|
var circuit = try buildCircuit(allocator, levels.items);
|
||||||
|
@ -109,7 +109,7 @@ fn make(step: *std.build.Step) !void {
|
||||||
defer data.deinit();
|
defer data.deinit();
|
||||||
const writer = data.writer();
|
const writer = data.writer();
|
||||||
|
|
||||||
try world.write(writer, level_headers.items, circuit.items, levels.items);
|
try world.write(writer, level_headers.items, entity_array.items, circuit.items, levels.items);
|
||||||
|
|
||||||
// Open output file and write data into it
|
// Open output file and write data into it
|
||||||
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
||||||
|
@ -163,20 +163,28 @@ fn parseLevel(opt: struct {
|
||||||
// Parsing code for wire entities. They're a little more complex
|
// Parsing code for wire entities. They're a little more complex
|
||||||
// than the rest
|
// than the rest
|
||||||
if (kind_opt) |kind| {
|
if (kind_opt) |kind| {
|
||||||
|
const levelc = world.Coordinate.fromWorld(world_x, world_y);
|
||||||
if (kind != .WireNode) {
|
if (kind != .WireNode) {
|
||||||
|
const entc = world.Coordinate.init(.{
|
||||||
|
@intCast(i16, entity.__grid[0]),
|
||||||
|
@intCast(i16, entity.__grid[1]),
|
||||||
|
});
|
||||||
const world_entity = world.Entity{
|
const world_entity = world.Entity{
|
||||||
.kind = kind,
|
.kind = kind,
|
||||||
.x = @intCast(i16, entity.__grid[0]),
|
.coord = levelc.addC(entc)
|
||||||
.y = @intCast(i16, entity.__grid[1]),
|
|
||||||
};
|
};
|
||||||
try entity_array.append(world_entity);
|
try entity_array.append(world_entity);
|
||||||
} else {
|
} else {
|
||||||
const p1_x: i16 = @intCast(i16, entity.__grid[0]);
|
|
||||||
const p1_y: i16 = @intCast(i16, entity.__grid[1]);
|
|
||||||
var anchor1 = false;
|
var anchor1 = false;
|
||||||
var anchor2 = false;
|
var anchor2 = false;
|
||||||
var p2_x: i16 = p1_x;
|
const p1_c = world.Coordinate.init(.{
|
||||||
var p2_y: i16 = p1_y;
|
@intCast(i16, entity.__grid[0]),
|
||||||
|
@intCast(i16, entity.__grid[1]),
|
||||||
|
});
|
||||||
|
var p2_c = world.Coordinate.init(.{
|
||||||
|
@intCast(i16, entity.__grid[0]),
|
||||||
|
@intCast(i16, entity.__grid[1]),
|
||||||
|
});
|
||||||
for (entity.fieldInstances) |field| {
|
for (entity.fieldInstances) |field| {
|
||||||
if (std.mem.eql(u8, field.__identifier, "Anchor")) {
|
if (std.mem.eql(u8, field.__identifier, "Anchor")) {
|
||||||
const anchors = field.__value.Array.items;
|
const anchors = field.__value.Array.items;
|
||||||
|
@ -187,26 +195,28 @@ fn parseLevel(opt: struct {
|
||||||
const endpoint = field.__value.Array.items[end];
|
const endpoint = field.__value.Array.items[end];
|
||||||
const x = endpoint.Object.get("cx").?;
|
const x = endpoint.Object.get("cx").?;
|
||||||
const y = endpoint.Object.get("cy").?;
|
const y = endpoint.Object.get("cy").?;
|
||||||
p2_x = @intCast(i16, x.Integer);
|
p2_c.val = .{
|
||||||
p2_y = @intCast(i16, y.Integer);
|
@intCast(i16, x.Integer),
|
||||||
|
@intCast(i16, y.Integer),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const wire_begin = world.Entity{
|
const wire_begin = world.Entity{
|
||||||
.kind = if (anchor1) .WireAnchor else .WireNode,
|
.kind = if (anchor1) .WireAnchor else .WireNode,
|
||||||
.x = p1_x,
|
.coord = p1_c.addC(levelc),
|
||||||
.y = p1_y,
|
|
||||||
};
|
};
|
||||||
try entity_array.append(wire_begin);
|
try entity_array.append(wire_begin);
|
||||||
|
|
||||||
const wire_end = world.Entity{
|
const wire_end = world.Entity{
|
||||||
.kind = if (anchor2) .WireEndAnchor else .WireEndNode,
|
.kind = if (anchor2) .WireEndAnchor else .WireEndNode,
|
||||||
.x = p2_x,
|
.coord = p2_c.addC(levelc),
|
||||||
.y = p2_y,
|
|
||||||
};
|
};
|
||||||
try entity_array.append(wire_end);
|
try entity_array.append(wire_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std.log.warn("Entities: {}", .{entity_array.items.len});
|
||||||
} else if (std.mem.eql(u8, layer.__identifier, "Circuit")) {
|
} else if (std.mem.eql(u8, layer.__identifier, "Circuit")) {
|
||||||
// Circuit
|
// Circuit
|
||||||
std.debug.assert(layer.__type == .IntGrid);
|
std.debug.assert(layer.__type == .IntGrid);
|
||||||
|
@ -235,14 +245,13 @@ fn parseLevel(opt: struct {
|
||||||
const width = @intCast(u16, circuit.__cWid);
|
const width = @intCast(u16, circuit.__cWid);
|
||||||
const size = @intCast(u16, width * circuit.__cHei);
|
const size = @intCast(u16, width * circuit.__cHei);
|
||||||
|
|
||||||
|
// Entities go into global scope now
|
||||||
var parsed_level = world.Level{
|
var parsed_level = world.Level{
|
||||||
.world_x = world_x,
|
.world_x = world_x,
|
||||||
.world_y = world_y,
|
.world_y = world_y,
|
||||||
.width = @intCast(u16, width),
|
.width = @intCast(u16, width),
|
||||||
.size = @intCast(u16, size),
|
.size = @intCast(u16, size),
|
||||||
.entity_count = @intCast(u16, entity_array.items.len),
|
|
||||||
.tiles = try allocator.alloc(world.TileData, size),
|
.tiles = try allocator.alloc(world.TileData, size),
|
||||||
.entities = try allocator.dupe(world.Entity, entity_array.items),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const tiles = parsed_level.tiles.?;
|
const tiles = parsed_level.tiles.?;
|
||||||
|
|
Loading…
Reference in New Issue