Make circuit rely on database

master
Louis Pearson 2022-08-09 20:49:43 -06:00
parent 3036ccd1e8
commit d3450e4323
6 changed files with 207 additions and 173 deletions

View File

@ -4246,9 +4246,9 @@
"defUid": 93,
"px": [84,124],
"fieldInstances": [
{ "__identifier": "Point", "__value": [{ "cx": 15, "cy": 15 }], "__type": "Array<Point>", "__tile": null, "defUid": 94, "realEditorValues": [{
{ "__identifier": "Point", "__value": [{ "cx": 14, "cy": 15 }], "__type": "Array<Point>", "__tile": null, "defUid": 94, "realEditorValues": [{
"id": "V_String",
"params": ["15,15"]
"params": ["14,15"]
}] },
{ "__identifier": "Anchor", "__value": [ true, true ], "__type": "Array<Bool>", "__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] }
],

View File

@ -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]),

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}