From d3450e43238277e5cd4d29873df61c5633126275 Mon Sep 17 00:00:00 2001 From: Louis Pearson Date: Tue, 9 Aug 2022 20:49:43 -0600 Subject: [PATCH] Make circuit rely on database --- assets/maps/wired.ldtk | 13 +-- src/circuit.zig | 200 +++++++++++++++++++++++------------------ src/extract.zig | 15 +++- src/game.zig | 103 +++++++++++---------- src/world.zig | 13 ++- tools/LDtkImport.zig | 36 +++----- 6 files changed, 207 insertions(+), 173 deletions(-) diff --git a/assets/maps/wired.ldtk b/assets/maps/wired.ldtk index 7e68601..5f02da0 100644 --- a/assets/maps/wired.ldtk +++ b/assets/maps/wired.ldtk @@ -4246,9 +4246,9 @@ "defUid": 93, "px": [84,124], "fieldInstances": [ - { "__identifier": "Point", "__value": [{ "cx": 15, "cy": 15 }], "__type": "Array", "__tile": null, "defUid": 94, "realEditorValues": [{ + { "__identifier": "Point", "__value": [{ "cx": 14, "cy": 15 }], "__type": "Array", "__tile": null, "defUid": 94, "realEditorValues": [{ "id": "V_String", - "params": ["15,15"] + "params": ["14,15"] }] }, { "__identifier": "Anchor", "__value": [ true, true ], "__type": "Array", "__tile": null, "defUid": 98, "realEditorValues": [ { "id": "V_Bool", @@ -4330,12 +4330,13 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,0, 0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0, - 0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,7,10,0,1,0,0, - 2,1,0,0,0,0,0,0,1,0,0,4,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,1,1, + 0,0,0,1,0,0,1,0,0,1,0,0,1,0,9,0,1,0,0,0,0,0,0,1,0,0,1,1,1,7,10,0,1,0,2, + 0,1,0,0,0,0,0,0,1,0,0,4,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,1,1, 1,1,1,0,0,0,1,0,0,0,0,0,0,8,0,0,9,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ], "autoLayerTiles": [ + { "px": [112,112], "src": [64,48], "f": 0, "t": 104, "d": [106,294] }, { "px": [48,144], "src": [8,48], "f": 0, "t": 97, "d": [104,366] }, { "px": [24,88], "src": [96,48], "f": 0, "t": 108, "d": [35,223] }, { "px": [72,104], "src": [96,48], "f": 0, "t": 108, "d": [35,269] }, @@ -4345,7 +4346,6 @@ { "px": [96,136], "src": [24,48], "f": 0, "t": 99, "d": [37,352] }, { "px": [48,120], "src": [104,48], "f": 0, "t": 109, "d": [40,306] }, { "px": [48,88], "src": [112,48], "f": 0, "t": 110, "d": [41,226] }, - { "px": [128,120], "src": [88,48], "f": 0, "t": 107, "d": [43,316] }, { "px": [32,88], "src": [48,48], "f": 0, "t": 102, "d": [44,224] }, { "px": [40,88], "src": [48,48], "f": 0, "t": 102, "d": [44,225] }, { "px": [56,88], "src": [48,48], "f": 0, "t": 102, "d": [44,227] }, @@ -4377,6 +4377,7 @@ { "px": [128,112], "src": [72,48], "f": 0, "t": 105, "d": [45,296] }, { "px": [24,120], "src": [72,48], "f": 0, "t": 105, "d": [45,303] }, { "px": [96,120], "src": [72,48], "f": 0, "t": 105, "d": [45,312] }, + { "px": [128,120], "src": [72,48], "f": 0, "t": 105, "d": [45,316] }, { "px": [24,128], "src": [72,48], "f": 0, "t": 105, "d": [45,323] }, { "px": [96,128], "src": [72,48], "f": 0, "t": 105, "d": [45,332] }, { "px": [128,128], "src": [72,48], "f": 0, "t": 105, "d": [45,336] }, @@ -4384,7 +4385,7 @@ { "px": [48,136], "src": [72,48], "f": 0, "t": 105, "d": [45,346] }, { "px": [128,136], "src": [72,48], "f": 0, "t": 105, "d": [45,356] }, { "px": [80,120], "src": [8,8], "f": 0, "t": 17, "d": [130,310] }, - { "px": [120,120], "src": [16,8], "f": 0, "t": 18, "d": [59,315] }, + { "px": [112,120], "src": [0,8], "f": 0, "t": 16, "d": [57,314] }, { "px": [48,128], "src": [104,8], "f": 0, "t": 29, "d": [79,326] }, { "px": [72,120], "src": [48,8], "f": 0, "t": 22, "d": [83,309] } ], diff --git a/src/circuit.zig b/src/circuit.zig index 76640dc..b5f1e05 100644 --- a/src/circuit.zig +++ b/src/circuit.zig @@ -139,15 +139,15 @@ fn get_plugs(tile: u8) Plugs { }; } -pub fn get_cell(this: @This(), cell: Cell) ?u8 { - const i = this.indexOf(cell) orelse return null; +pub fn getCoord(this: @This(), coord: world.Coordinate) ?u8 { + const i = this.indexOf(coord.toVec2()) orelse return null; return if (this.map[i] != 0) this.map[i] else null; } -pub fn set_cell(this: *@This(), cell: Cell, tile: u8) void { - const i = this.indexOf(cell) orelse return; +pub fn setCoord(this: @This(), coord: world.Coordinate, tile: u8) void { + const i = this.indexOf(coord.toVec2()) orelse return; this.map[i] = tile; - this.levels[i] = 0; + // this.levels[i] = 255; } const MAXCELLS = 400; @@ -156,37 +156,37 @@ const MAXSOURCES = 10; const MAXDOORS = 40; const MAXLOGIC = 40; -pub const CellData = struct { level: u8 = 0, tile: u8 }; - -pub const BridgeState = struct { cells: [2]Cell, id: usize, enabled: bool }; -pub const DoorState = struct { cell: Cell, enabled: bool }; +pub const NodeCoord = struct { coord: world.Coordinate, node_id: world.NodeID }; +pub const Source = NodeCoord; +pub const BridgeState = struct { coords: [2]world.Coordinate, id: usize, enabled: bool }; +pub const DoorState = struct { coord: world.Coordinate, enabled: bool }; /// Tile id of the tiles map: []u8, -/// Logic levels of the tiles -levels: []u8, +/// CircuitNode ID for each tile +nodes: []world.NodeID, map_size: Vec2, bridges: util.Buffer(BridgeState), -sources: util.Buffer(Cell), +sources: util.Buffer(Source), doors: util.Buffer(DoorState), pub const Options = struct { map: []u8, - levels: []u8, + nodes: []u8, map_size: Vec2, bridges: []BridgeState, - sources: []Cell, + sources: []Source, doors: []DoorState, }; pub fn init(opt: Options) @This() { - std.debug.assert(opt.map.len == opt.levels.len); + std.debug.assert(opt.map.len == opt.nodes.len); var this = @This(){ .map = opt.map, - .levels = opt.levels, + .nodes = opt.nodes, .map_size = opt.map_size, .bridges = util.Buffer(BridgeState).init(opt.bridges), - .sources = util.Buffer(Cell).init(opt.sources), + .sources = util.Buffer(Source).init(opt.sources), .doors = util.Buffer(DoorState).init(opt.doors), }; return this; @@ -197,31 +197,40 @@ pub fn indexOf(this: @This(), cell: Cell) ?usize { return @intCast(usize, @mod(cell[0], this.map_size[0]) + (cell[1] * this.map_size[1])); } -pub fn enable(this: *@This(), cell: Cell) void { - const i = this.indexOf(cell) orelse return; - this.levels[i] += 1; -} - -pub fn bridge(this: *@This(), cells: [2]Cell, bridgeID: usize) void { - if (this.indexOf(cells[0])) |_| { - if (this.indexOf(cells[1])) |_| { - this.bridges.append(.{ .cells = cells, .id = bridgeID, .enabled = false }); +pub fn bridge(this: *@This(), coords: [2]world.Coordinate, bridgeID: usize) void { + if (this.indexOf(coords[0].toVec2())) |_| { + if (this.indexOf(coords[1].toVec2())) |_| { + this.bridges.append(.{ .coords = coords, .id = bridgeID, .enabled = false }); } } } -pub fn addSource(this: *@This(), cell: Cell) void { - if (this.indexOf(cell)) |_| { - this.sources.append(cell); +pub fn addSource(this: *@This(), source: Source) void { + w4.tracef("%d, %d", source.coord.val[0], source.coord.val[1]); + if (this.indexOf(source.coord.toVec2())) |_| { + this.sources.append(source); } } -pub fn addDoor(this: *@This(), cell: Cell) !void { - if (this.indexOf(cell)) |_| { - this.doors.append(.{ .cell = cell, .enabled = false }); +pub fn addDoor(this: *@This(), coord: world.Coordinate) !void { + if (this.indexOf(coord.toVec2())) |_| { + this.doors.append(.{ .coord = coord, .enabled = false }); } } +pub fn enabledBridge(this: @This(), id: usize) ?usize { + var count: usize = 0; + for (this.bridges.items) |b| { + if (b.enabled) { + if (count == id) { + return b.id; + } + count += 1; + } + } + return null; +} + pub fn enabledBridges(this: @This(), alloc: std.mem.Allocator) !util.Buffer(usize) { var items = try alloc.alloc(usize, this.bridges.len); var buffer = util.Buffer(usize).init(items); @@ -243,28 +252,28 @@ pub fn enabledDoors(this: @This(), alloc: std.mem.Allocator) !util.Buffer(Cell) return buffer; } -pub fn isEnabled(this: @This(), cell: Cell) bool { - const i = this.indexOf(cell) orelse return false; - return this.levels[i] >= 1; +pub fn getNodeID(this: @This(), coord: world.Coordinate) ?world.NodeID { + const i = this.indexOf(coord.toVec2()) orelse return null; + if (this.nodes[i] == std.math.maxInt(world.NodeID)) return null; + return this.nodes[i]; } -pub fn switchOn(this: *@This(), cell: Cell) void { - if (this.get_cell(cell)) |tile| { +pub fn switchOn(this: *@This(), coord: world.Coordinate) void { + if (this.getCoord(coord)) |tile| { if (T.is_switch(tile)) { if (switchIsOn(tile)) return; const toggled = toggle_switch(tile); - this.set_cell(cell, toggled); + this.setCoord(coord, toggled); return; } } } -pub fn toggle(this: *@This(), c: Cell) ?u8 { - const cell = c; - if (this.get_cell(cell)) |tile| { +pub fn toggle(this: *@This(), coord: world.Coordinate) ?u8 { + if (this.getCoord(coord)) |tile| { if (T.is_switch(tile)) { const toggled = toggle_switch(tile); - this.set_cell(cell, toggled); + this.setCoord(coord, toggled); return toggled; } } @@ -280,7 +289,7 @@ pub fn clearMap(this: *@This()) void { } pub fn clear(this: *@This()) void { - std.mem.set(u8, this.levels, 0); + std.mem.set(u8, this.nodes, std.math.maxInt(world.NodeID)); for (this.doors.items) |*door| { door.enabled = false; } @@ -294,70 +303,87 @@ pub fn reset(this: *@This()) void { } const w4 = @import("wasm4.zig"); -const Queue = util.Queue(Cell); // Returns number of cells filled -pub fn fill(this: *@This(), alloc: std.mem.Allocator) !usize { +pub fn fill(this: *@This(), alloc: std.mem.Allocator, db: world.Database, level: world.Level) !usize { var count: usize = 0; + w4.tracef("[fill] begin"); - var q_buf = try alloc.alloc(Cell, MAXCELLS); + const Queue = util.Queue(NodeCoord); + var q_buf = try alloc.alloc(NodeCoord, MAXCELLS); var q = Queue.init(q_buf); for (this.sources.items) |source| { + w4.tracef("[fill] inserting source (%d, %d)", source.coord.val[0], source.coord.val[1]); try q.insert(source); } + // if (this.sources.items.len == 0) { + // w4.tracef("[fill] no sources %d", this.sources.items.len); + // } + + while (q.remove()) |node| { + const tile = this.getCoord(node.coord) orelse continue; + const index = this.indexOf(node.coord.toVec2()) orelse continue; + const hasVisited = this.nodes[index] != std.math.maxInt(world.NodeID); + + w4.tracef("[fill] %d, %d, %d", tile, index, hasVisited); + if (hasVisited) continue; + + this.nodes[index] = node.node_id; - while (q.remove()) |cell| { - const tile = this.get_cell(cell) orelse { - for (this.doors.items) |*d| { - if (@reduce(.And, d.cell == cell)) { - d.enabled = true; - } - } - continue; - }; - const index = this.indexOf(cell) orelse continue; - const hasVisited = this.levels[index] != 0; - this.enable(cell); - if (hasVisited and !T.is_logic(tile)) continue; count += 1; - if (get_logic(tile)) |logic| { - // TODO: implement other logic (though I'm pretty sure that requires a graph...) - if (logic != .And) continue; - if (this.levels[index] < 2) continue; - try q.insert(cell + util.Dir.up); + + if (get_logic(tile)) |_| { + // w4.tracef("[fill] logic"); + const new_id = db.getLevelNodeID(level, node.coord) orelse { + w4.tracef("[fill] missing logic"); + continue; + }; + try q.insert(.{ .node_id = new_id, .coord = node.coord.add(.{ 0, -1 }) }); + continue; } for (get_outputs(tile)) |conductor, i| { + // w4.tracef("[fill] outputs"); if (!conductor) continue; + // w4.tracef("[fill] conductor"); const s = @intToEnum(Side, i); const delta = s.dir(); // TODO: check that cell can recieve from this side - const nextCell = cell + delta; - if (nextCell[0] < 0 or nextCell[1] < 0 or - nextCell[0] >= this.map_size[0] or - nextCell[1] >= this.map_size[1]) - continue; - const nextTile = this.get_cell(nextCell) orelse here: { - for (this.doors.items) |*d| { - if (@reduce(.And, d.cell == nextCell)) { - d.enabled = true; - } - } - break :here 0; - }; - if (get_inputs(nextTile)[@enumToInt(s.opposite())]) - try q.insert(nextCell); + const nextCoord = node.coord.addC(world.Coordinate.fromVec2(delta)); + const tl = world.Coordinate.init(.{ 0, 0 }); + const br = world.Coordinate.fromVec2(this.map_size); + // w4.tracef("[fill] next (%d, %d)", nextCoord.val[0], nextCoord.val[1]); + // w4.tracef("[fill] range (%d, %d)-(%d, %d)", tl.val[0], tl.val[1], br.val[0], br.val[1]); + if (!nextCoord.within(tl, br)) continue; + // w4.tracef("[fill] within %d", nextCoord.within(tl, br)); + const nextTile = this.getCoord(nextCoord) orelse 0; + // w4.tracef("[fill] nextTile"); + if (get_inputs(nextTile)[@enumToInt(s.opposite())]) { + // w4.tracef("[fill] get_inputs"); + try q.insert(.{ + .node_id = node.node_id, + .coord = nextCoord, + }); + } } if (T.is_plug(tile)) { + // w4.tracef("[fill] plug"); for (this.bridges.items) |*b| { - if (@reduce(.And, b.cells[0] == cell)) { - try q.insert(b.cells[1]); + if (b.coords[0].eq(node.coord)) { + try q.insert(.{ + .coord = b.coords[1], + .node_id = node.node_id, + }); b.enabled = true; - } else if (@reduce(.And, b.cells[1] == cell)) { - try q.insert(b.cells[0]); + } else if (b.coords[1].eq(node.coord)) { + try q.insert(.{ + .coord = b.coords[0], + .node_id = node.node_id, + }); b.enabled = true; } } } + w4.tracef("[fill] end search step"); } return count; } @@ -369,16 +395,18 @@ const tilemap_width = 16; const tilemap_height = 16; const tilemap_stride = 128; -pub fn draw(this: @This(), offset: Vec2) void { +pub fn draw(this: @This(), db: world.Database, offset: Vec2) void { var y: usize = 0; while (y < height) : (y += 1) { var x: usize = 0; while (x < width) : (x += 1) { const cell = Vec2{ @intCast(i32, x), @intCast(i32, y) }; const pos = cell * tile_size; - const tile = this.get_cell(cell + offset) orelse continue; + const coord = world.Coordinate.fromVec2(cell + offset); + const tile = this.getCoord(coord) orelse continue; if (tile == 0) continue; - if (this.isEnabled(cell + offset)) w4.DRAW_COLORS.* = 0x0210 else w4.DRAW_COLORS.* = 0x0310; + const energized = if (this.getNodeID(coord)) |node| db.circuit_info[node].energized else false; + if (energized) w4.DRAW_COLORS.* = 0x0210 else w4.DRAW_COLORS.* = 0x0310; const t = Vec2{ @intCast(i32, (tile % tilemap_width) * tile_size[0]), @intCast(i32, (tile / tilemap_width) * tile_size[0]), diff --git a/src/extract.zig b/src/extract.zig index e6786ef..0613a4d 100644 --- a/src/extract.zig +++ b/src/extract.zig @@ -18,6 +18,7 @@ pub const Options = struct { plug: world.AutoTileset, switch_on: world.AutoTileset, switch_off: world.AutoTileset, + db: world.Database, }; fn is_solid(tile: u7) bool { @@ -32,6 +33,7 @@ pub fn extractLevel(opt: Options) !void { const alloc = opt.alloc; const level = opt.level; const tileset = opt.tileset; + const db = opt.db; const tiles = level.tiles orelse return error.NullTiles; @@ -138,7 +140,18 @@ pub fn extractLevel(opt: Options) !void { const y = @divTrunc(i, width); const stride = width; - if (circuit_map[i] == .Source) circuit.addSource(.{@intCast(i32, x), @intCast(i32, y)}); + if (circuit_map[i] == .Source) { + const levelc = world.Coordinate.fromVec2(.{ @intCast(i32, x), @intCast(i32, y) }); + const coord = world.Coordinate.fromWorld(level.world_x, level.world_y).addC(levelc); + w4.tracef("[extract] source (%d, %d)", coord.val[0], coord.val[1]); + if (db.getNodeID(coord)) |node_id| { + circuit.addSource(.{ + .coord = levelc, + .node_id = node_id, + }); + w4.tracef("[extract] node id (%d)", node_id); + } + } if (circuit_map[i] == .None) { autotiles[i] = null; diff --git a/src/game.zig b/src/game.zig index 37afc37..08cbdd0 100644 --- a/src/game.zig +++ b/src/game.zig @@ -178,7 +178,7 @@ var ScoreCoin = Sprite{ var map_buf: [400]u8 = undefined; -var circuit_lvl_buf: [400]u8 = undefined; +var circuit_node_buf: [400]u8 = undefined; var circuit_buf: [400]u8 = undefined; var circuit_options: Circuit.Options = undefined; @@ -209,6 +209,8 @@ fn loadLevel(lvl: usize) !void { level = try db.levelLoad(alloc, lvl); const levelc = world.Coordinate.fromWorld(level.world_x, level.world_y); + w4.tracef("Loading level [%d] (%d, %d)", lvl, level.world_x, level.world_y); + try extract.extractLevel(.{ .alloc = frame_alloc, .level = level, @@ -219,6 +221,7 @@ fn loadLevel(lvl: usize) !void { .plug = world.Tiles.Plugs, .switch_off = world.Tiles.SwitchesOff, .switch_on = world.Tiles.SwitchesOn, + .db = db, }); const tile_size = Vec2{ 8, 8 }; @@ -258,7 +261,7 @@ fn loadLevel(lvl: usize) !void { var i: usize = 0; while (db.getDoor(level, i)) |door| : (i += 1) { const coord = door.coord.subC(levelc); - try circuit.addDoor(coord.toVec2()); + try circuit.addDoor(coord); } } @@ -269,7 +272,8 @@ fn loadLevel(lvl: usize) !void { var e = false; if (db.isEnergized(globalc)) { e = true; - circuit.addSource(.{ join.val[0], join.val[1] }); + const node_id = db.getNodeID(globalc) orelse continue; + circuit.addSource(.{ .coord = join, .node_id = node_id }); } w4.tracef("---- Join %d: (%d, %d) <%d>", i, globalc.val[0], globalc.val[1], @boolToInt(e)); } @@ -282,7 +286,7 @@ fn loadLevel(lvl: usize) !void { var e = false; if (db.getSwitchState(globalc)) |state| { e = true; - if (state != 0) circuit.switchOn(.{ _switch.val[0], _switch.val[1] }); + if (state != 0) circuit.switchOn(levelc); } w4.tracef("---- Switch %d: (%d, %d) <%d>", i, globalc.val[0], globalc.val[1], @boolToInt(e)); } @@ -378,10 +382,10 @@ pub fn start() !void { circuit_options = .{ .map = &circuit_buf, - .levels = &circuit_lvl_buf, + .nodes = &circuit_node_buf, .map_size = level_size, .bridges = try alloc.alloc(Circuit.BridgeState, 5), - .sources = try alloc.alloc(util.Cell, 5), + .sources = try alloc.alloc(Circuit.Source, 5), .doors = try alloc.alloc(Circuit.DoorState, 10), }; circuit = Circuit.init(circuit_options); @@ -481,7 +485,7 @@ pub fn update(time: usize) !State { camera = newCamera; map.draw(camera); - circuit.draw(camera); + circuit.draw(db, camera); for (wires.slice()) |*wire| { wireDrawProcess(1, wire); @@ -503,12 +507,13 @@ pub fn update(time: usize) !State { } { - const pos = util.world2cell(player.pos.pos); - const shouldHum = circuit.isEnabled(pos) or - circuit.isEnabled(pos + util.Dir.up) or - circuit.isEnabled(pos + util.Dir.down) or - circuit.isEnabled(pos + util.Dir.left) or - circuit.isEnabled(pos + util.Dir.right); + // const pos = util.world2cell(player.pos.pos); + const shouldHum = false; + // circuit.isEnabled(pos) or + // circuit.isEnabled(pos + util.Dir.up) or + // circuit.isEnabled(pos + util.Dir.down) or + // circuit.isEnabled(pos + util.Dir.left) or + // circuit.isEnabled(pos + util.Dir.right); if (shouldHum) { w4.tone(.{ .start = 60 }, .{ .release = 255, .sustain = 0 }, 1, .{ .channel = .pulse1, .mode = .p50 }); } @@ -588,7 +593,8 @@ const Interaction = struct { fn getNearestCircuitInteraction(pos: Vec2f) ?Interaction { const cell = util.world2cell(pos); - if (circuit.get_cell(cell)) |tile| { + const coord = Coord.fromVec2(cell); + if (circuit.getCoord(coord)) |tile| { if (world.Tiles.is_switch(tile)) { return Interaction{ .details = .lever, .pos = cell * Map.tile_size + Vec2{ 4, 4 } }; } @@ -598,9 +604,10 @@ fn getNearestCircuitInteraction(pos: Vec2f) ?Interaction { fn getNearestPlugInteraction(pos: Vec2f, wireID: usize, which: usize) ?Interaction { const cell = util.world2cell(pos); - if (circuit.get_cell(cell)) |tile| { + const coord = world.Coordinate.fromVec2(cell); + if (circuit.getCoord(coord)) |tile| { if (world.Tiles.is_plug(tile)) { - const active = circuit.isEnabled(cell); + const active = db.isEnergized(coord); return Interaction{ .details = .{ .plug = .{ .wireID = wireID, .which = which } }, .pos = cell * Map.tile_size + Vec2{ 4, 4 }, @@ -706,17 +713,16 @@ fn manipulationProcess(pos: *Pos, control: *Control) !void { }, .lever => { const cell = @divTrunc(i.pos, Map.tile_size); - const new_switch = circuit.toggle(cell); + const coord = Coord.fromVec2(cell); + const new_switch = circuit.toggle(coord); if (new_switch) |tile| { const T = world.Tiles; const new_state: u8 = switch (tile) { T.SwitchTeeWestOn, T.SwitchTeeEastOn, T.SwitchVerticalOn => 1, else => 0, }; - const x = level.world_x * 20 + @intCast(i16, cell[0]); - const y = level.world_y * 20 + @intCast(i16, cell[1]); - db.setSwitch(Coord.init(.{ x, y }), new_state); + db.setSwitch(coord.addC(Coord.fromWorld(level.world_x, level.world_y)), new_state); } try updateCircuit(); }, @@ -731,37 +737,35 @@ fn updateCircuit() !void { wire.enabled = false; if (!wire.begin().pinned or !wire.end().pinned) continue; const nodes = wire.nodes.constSlice(); - const cellBegin = util.world2cell(nodes[0].pos); - const cellEnd = util.world2cell(nodes[nodes.len - 1].pos); + const cellBegin = Coord.fromVec2(util.world2cell(nodes[0].pos)); + const cellEnd = Coord.fromVec2(util.world2cell(nodes[nodes.len - 1].pos)); circuit.bridge(.{ cellBegin, cellEnd }, wireID); const topleft = Coord.fromWorld(level.world_x, level.world_y); - const p1 = Coord.init(.{ - @intCast(i16, cellBegin[0]), - @intCast(i16, cellBegin[1]), - }).addC(topleft); - const p2 = Coord.init(.{ - @intCast(i16, cellEnd[0]), - @intCast(i16, cellEnd[1]), - }).addC(topleft); + const globalBegin = cellBegin.addC(topleft); + const globalEnd = cellEnd.addC(topleft); - db.connectPlugs(p1, p2) catch { + db.connectPlugs(globalBegin, globalEnd) catch { w4.tracef("connect plugs error"); }; } + try db.updateCircuit(frame_alloc); + // Simulate circuit - _ = try circuit.fill(frame_alloc); + _ = try circuit.fill(frame_alloc, db, level); + w4.tracef("[updateCircuit] circuit filled"); + // for (circuit.nodes) |node, i| { + // w4.tracef("%d: %d", i, node); + // } // Energize wires - for (wires.slice()) |*wire| { - const begin = wire.begin(); - const end = wire.end(); - const cellBegin = util.world2cell(begin.pos); - const cellEnd = util.world2cell(end.pos); - if ((circuit.isEnabled(cellBegin) and begin.pinned) or - (circuit.isEnabled(cellEnd) and end.pinned)) wire.enabled = true; + { + var i: usize = 0; + while (circuit.enabledBridge(i)) |wireID| : (i += 1) { + wires.slice()[wireID].enabled = true; + } } // Add doors to map @@ -770,27 +774,22 @@ fn updateCircuit() !void { const tile: u8 = if (door.kind == .Door) world.Tiles.Door else world.Tiles.Trapdoor; 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); + if (db.isEnergized(door.coord)) { + w4.tracef("[door] open (%d, %d)", door.coord.val[0], door.coord.val[1]); + try map.set_cell(coord.toVec2(), world.Tiles.Empty); + } else { + w4.tracef("[door] closed (%d, %d)", door.coord.val[0], door.coord.val[1]); + try map.set_cell(coord.toVec2(), tile); + } } - // Remove doors that have been unlocked - const enabledDoors = try circuit.enabledDoors(frame_alloc); - defer frame_alloc.free(enabledDoors.items); - for (enabledDoors.items) |door| { - w4.tracef("[enabledDoors] (%d, %d)", door[0], door[1]); - try map.set_cell(door, world.Tiles.Empty); - } - - try db.updateCircuit(frame_alloc); - for (db.circuit_info) |node, n| { const e = @boolToInt(node.energized); switch (node.kind) { .Conduit => |Conduit| w4.tracef("[%d]: Conduit [%d, %d] <%d>", n, Conduit[0], Conduit[1], e), .And => |And| w4.tracef("[%d]: And [%d, %d] <%d>", n, And[0], And[1], e), .Xor => |Xor| w4.tracef("[%d]: Xor [%d, %d] <%d>", n, Xor[0], Xor[1], e), - .Source => w4.tracef("[%d]: Source", n), + .Source => w4.tracef("[%d]: Source (%d, %d)", n, node.coord.val[0], node.coord.val[1]), .Socket => |Socket| { const socket = Socket orelse std.math.maxInt(world.NodeID); w4.tracef("[%d]: Socket [%d] <%d>", n, socket, e); diff --git a/src/world.zig b/src/world.zig index 3c7de27..8e651d0 100644 --- a/src/world.zig +++ b/src/world.zig @@ -47,9 +47,9 @@ pub const Tiles = struct { return tile >= 16 and tile < 20; } - pub const LogicAnd = 21; - pub const LogicNot = 22; - pub const LogicXor = 23; + pub const LogicAnd = 20; + pub const LogicNot = 21; + pub const LogicXor = 22; pub fn is_logic(tile: u8) bool { return tile >= 21 and tile <= 24; @@ -753,7 +753,7 @@ pub const Database = struct { // Circuit functions - fn getNodeID(db: *Database, coord: Coord) ?NodeID { + pub fn getNodeID(db: Database, coord: Coord) ?NodeID { for (db.circuit_info) |node, i| { if (!coord.eq(node.coord)) continue; return @intCast(NodeID, i); @@ -761,6 +761,11 @@ pub const Database = struct { return null; } + pub fn getLevelNodeID(db: Database, level: Level, coord: Coord) ?NodeID { + const levelc = Coord.fromWorld(level.world_x, level.world_y); + return db.getNodeID(coord.addC(levelc)); + } + pub fn connectPlugs(db: *Database, p1: Coord, p2: Coord) !void { const p1id = db.getNodeID(p1) orelse return; const p2id = db.getNodeID(p2) orelse return; diff --git a/tools/LDtkImport.zig b/tools/LDtkImport.zig index 6dd5eca..7da4a33 100644 --- a/tools/LDtkImport.zig +++ b/tools/LDtkImport.zig @@ -480,17 +480,18 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL // Add switch outlets if (input_dir != .West and west) { const out_node = @intCast(world.NodeID, nodes.items.len); + const new_coord = coord.add(.{1, 0}); try nodes.append(.{ .kind = .{ .SwitchOutlet = .{ .source = next_node, .which = 0, } }, - .coord = coord, + .coord = new_coord, }); const right = try alloc.create(Node); right.* = Node{ .data = .{ .last_node = out_node, - .coord = coord.add(.{ 1, 0 }), + .coord = new_coord, .last_coord = coord, } }; bfs_queue.append(right); @@ -498,17 +499,18 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL if (input_dir != .East and east) { const out_node = @intCast(world.NodeID, nodes.items.len); + const new_coord = coord.add(.{-1, 0}); try nodes.append(.{ .kind = .{ .SwitchOutlet = .{ .source = next_node, .which = 0, } }, - .coord = coord, + .coord = new_coord, }); const left = try alloc.create(Node); left.* = Node{ .data = .{ .last_node = out_node, - .coord = coord.add(.{ -1, 0 }), + .coord = new_coord, .last_coord = coord, } }; bfs_queue.append(left); @@ -516,17 +518,18 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL if (input_dir != .South and south) { const out_node = @intCast(world.NodeID, nodes.items.len); + const new_coord = coord.add(.{0, 1}); try nodes.append(.{ .kind = .{ .SwitchOutlet = .{ .source = next_node, .which = 1, } }, - .coord = coord, + .coord = new_coord, }); const down = try alloc.create(Node); down.* = Node{ .data = .{ .last_node = out_node, - .coord = coord.add(.{ 0, 1 }), + .coord = new_coord, .last_coord = coord, } }; bfs_queue.append(down); @@ -534,17 +537,18 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL if (input_dir != .North and north) { const out_node = @intCast(world.NodeID, nodes.items.len); + const new_coord = coord.add(.{0, -1}); try nodes.append(.{ .kind = .{ .SwitchOutlet = .{ .source = next_node, .which = 1, } }, - .coord = coord, + .coord = new_coord, }); const up = try alloc.create(Node); up.* = Node{ .data = .{ .last_node = out_node, - .coord = coord.add(.{ 0, -1 }), + .coord = new_coord, .last_coord = coord, } }; bfs_queue.append(up); @@ -695,21 +699,5 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL } } - var i: usize = 0; - while (i < nodes.items.len) : (i += 1) { - switch (nodes.items[i].kind) { - // .Source => { - // }, - .And => {}, - .Xor => {}, - .Conduit => {}, - .Plug => {}, - .Switch => {}, - .Join => {}, - .Outlet => {}, - else => {}, - } - } - return nodes; }