Flesh out world data format, make parseLevel fn
parent
9655abc120
commit
3fcd7e0942
|
@ -389,6 +389,16 @@ pub const Entity = struct {
|
|||
}
|
||||
};
|
||||
|
||||
// Data format:
|
||||
// | node count | level count |
|
||||
// | node headers... |
|
||||
// | level headers... |
|
||||
// | node data... |
|
||||
// | level data... |
|
||||
|
||||
const LevelHeader = struct { x: u8, y: u8, offset: u16 };
|
||||
|
||||
|
||||
pub const World = struct {
|
||||
/// All levels in the game. If two rooms are next to each other, they
|
||||
/// are assumed to be neighbors. Leaving the screen will load in the next
|
||||
|
@ -403,25 +413,37 @@ pub const World = struct {
|
|||
/// I will need to freeze it and move it in a snake like fashion. Or just leave the
|
||||
/// other level loaded.
|
||||
levels: []Level,
|
||||
/// List of all circuit joins between levels. Levels can have multiple joins
|
||||
circuit_nodes: []CircuitNode,
|
||||
/// An abstract representation of all circuits in game.
|
||||
abstract_circuit: []CircuitNode,
|
||||
|
||||
// pub fn write(world: Entity, writer: anytype) !void {
|
||||
// try writer.writeInt(u16, circuit_nodes.len, .Little);
|
||||
// try writer.writeInt(u16, levels.len, .Little);
|
||||
// for (circuit_nodes) |node| {
|
||||
// try node.write_header(writer);
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
const NodeID = u16;
|
||||
|
||||
pub const CircuitNode = struct {
|
||||
energized: bool,
|
||||
kind: CircuitKind,
|
||||
kind: NodeKind,
|
||||
inputs: []usize,
|
||||
|
||||
// pub fn write_header(node: CircuitNode, writer: anytype) !void {
|
||||
// try writer.writeInt(u16, )
|
||||
// }
|
||||
};
|
||||
|
||||
pub const CircuitKind = enum {
|
||||
/// This join is conditional on logic state inside of the level
|
||||
Logic,
|
||||
/// This join is a source of power
|
||||
pub const NodeKind = union(enum) {
|
||||
/// An And logic gate,
|
||||
And: [2]NodeID,
|
||||
/// This node is a source of power
|
||||
Source,
|
||||
/// This node has no logic and provides no power
|
||||
Conduit,
|
||||
// TODO: This type of node would be a wire stretching
|
||||
// between multiple levels. This doesn't work with the rules
|
||||
// for moving wires between levels at the moment.
|
||||
// Bridge,
|
||||
/// This node has no logic but can pass it on from another source
|
||||
Conduit: NodeID,
|
||||
/// This node represents a physical plug in the game world
|
||||
Plug: NodeID,
|
||||
};
|
||||
|
|
|
@ -57,16 +57,53 @@ fn make(step: *std.build.Step) !void {
|
|||
const ldtk = ldtk_parser.root;
|
||||
|
||||
if (ldtk.levels.len > 0) {
|
||||
const level0 = ldtk.levels[0];
|
||||
if (level0.layerInstances) |layers| {
|
||||
const world_x: u8 = @intCast(u8, @divExact(level0.worldX, (ldtk.worldGridWidth orelse 160)));
|
||||
const world_y: u8 = @intCast(u8, @divExact(level0.worldY, (ldtk.worldGridHeight orelse 160)));
|
||||
const level = ldtk.levels[0];
|
||||
|
||||
var entity_array = std.ArrayList(world.Entity).init(allocator);
|
||||
defer entity_array.deinit();
|
||||
|
||||
const parsed_level = try parseLevel(.{
|
||||
.allocator = allocator,
|
||||
.ldtk = ldtk,
|
||||
.level = level,
|
||||
.entity_array = &entity_array,
|
||||
});
|
||||
defer allocator.free(parsed_level.tiles.?);
|
||||
|
||||
// Save the level!
|
||||
try parsed_level.write(writer);
|
||||
}
|
||||
|
||||
// Open output file and write data
|
||||
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
};
|
||||
try cwd.writeFile(output, data.items);
|
||||
|
||||
this.world_data.path = output;
|
||||
}
|
||||
|
||||
/// Returns parsed layers of the
|
||||
fn parseLevel(opt: struct {
|
||||
allocator: std.mem.Allocator,
|
||||
ldtk: LDtk.Root,
|
||||
level: LDtk.Level,
|
||||
entity_array: *std.ArrayList(world.Entity),
|
||||
}) !world.Level {
|
||||
const ldtk = opt.ldtk;
|
||||
const level = opt.level;
|
||||
const entity_array = opt.entity_array;
|
||||
const allocator = opt.allocator;
|
||||
|
||||
const layers = level.layerInstances orelse return error.NoLayers;
|
||||
|
||||
const world_x: u8 = @intCast(u8, @divExact(level.worldX, (ldtk.worldGridWidth orelse 160)));
|
||||
const world_y: u8 = @intCast(u8, @divExact(level.worldY, (ldtk.worldGridHeight orelse 160)));
|
||||
|
||||
var circuit_layer: ?LDtk.LayerInstance = null;
|
||||
var collision_layer: ?LDtk.LayerInstance = null;
|
||||
|
||||
for (layers) |layer| {
|
||||
if (std.mem.eql(u8, layer.__identifier, "Entities")) {
|
||||
// Entities
|
||||
|
@ -159,7 +196,7 @@ fn make(step: *std.build.Step) !void {
|
|||
const width = @intCast(u16, circuit.__cWid);
|
||||
const size = @intCast(u16, width * circuit.__cHei);
|
||||
|
||||
var level = world.Level{
|
||||
var parsed_level = world.Level{
|
||||
.world_x = world_x,
|
||||
.world_y = world_y,
|
||||
.width = @intCast(u16, width),
|
||||
|
@ -168,10 +205,11 @@ fn make(step: *std.build.Step) !void {
|
|||
.tiles = null,
|
||||
.entities = entity_array.items,
|
||||
};
|
||||
level.tiles = try allocator.alloc(world.TileData, size);
|
||||
defer allocator.free(level.tiles.?);
|
||||
parsed_level.tiles = try allocator.alloc(world.TileData, size);
|
||||
// NOTE:
|
||||
// defer allocator.free(level.tiles.?);
|
||||
|
||||
const tiles = level.tiles.?;
|
||||
const tiles = parsed_level.tiles.?;
|
||||
|
||||
// Add unchanged tile data
|
||||
for (collision.autoLayerTiles) |autotile| {
|
||||
|
@ -196,17 +234,5 @@ fn make(step: *std.build.Step) !void {
|
|||
}
|
||||
}
|
||||
|
||||
// Save the level!
|
||||
try level.write(writer);
|
||||
}
|
||||
}
|
||||
|
||||
// Open output file and write data
|
||||
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
};
|
||||
try cwd.writeFile(output, data.items);
|
||||
|
||||
this.world_data.path = output;
|
||||
return parsed_level;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue