128 lines
3.7 KiB
Zig
128 lines
3.7 KiB
Zig
|
const std = @import("std");
|
||
|
const engine = @import("../engine.zig");
|
||
|
|
||
|
pub const Level = struct {
|
||
|
pub fn Column(comptime Value: type) type {
|
||
|
return struct {
|
||
|
const Self = @This();
|
||
|
|
||
|
values: std.AutoHashMap(i64, Value),
|
||
|
|
||
|
pub fn init(allocator: std.mem.Allocator) Self {
|
||
|
return Self{
|
||
|
.values = std.AutoHashMap(i64, Value).init(allocator),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
pub fn deinit(self: Self) void {
|
||
|
self.values.deinit();
|
||
|
}
|
||
|
|
||
|
pub fn get(self: Self, row: i64) ?Value {
|
||
|
return self.values.get(row);
|
||
|
}
|
||
|
|
||
|
pub fn set(self: *Self, row: i64, value: Value) !void {
|
||
|
try self.values.put(row, value);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
pub fn Components(comptime Value: type) type {
|
||
|
return struct {
|
||
|
const Self = @This();
|
||
|
|
||
|
allocator: std.mem.Allocator,
|
||
|
columns: std.ArrayList(Column(Value)),
|
||
|
|
||
|
pub fn init(allocator: std.mem.Allocator) Self {
|
||
|
return Self{
|
||
|
.allocator = allocator,
|
||
|
.columns = std.ArrayList(Column(Value)).init(allocator),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
pub fn deinit(self: Self) void {
|
||
|
for (self.columns.items) |item| {
|
||
|
item.deinit();
|
||
|
}
|
||
|
self.columns.deinit();
|
||
|
}
|
||
|
|
||
|
pub fn column(self: Self, i: i64) *Column(Value) {
|
||
|
return &self.columns.items[@intCast(usize, i)];
|
||
|
}
|
||
|
|
||
|
fn ensureColumns(self: *Self, n: usize) !void {
|
||
|
while (self.columns.items.len < n) {
|
||
|
try self.columns.append(Column(Value).init(self.allocator));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn set(self: *Self, c: i64, r: i64, value: Value) !void {
|
||
|
try self.ensureColumns(@intCast(usize, c) + 1);
|
||
|
try self.column(c).set(r, value);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
pub const Tile = enum {
|
||
|
Grass,
|
||
|
};
|
||
|
|
||
|
pub const Collectable = enum {
|
||
|
Star,
|
||
|
};
|
||
|
|
||
|
character: engine.Point,
|
||
|
tiles: Components(Tile),
|
||
|
collectables: Components(Collectable),
|
||
|
|
||
|
pub fn load(allocator: std.mem.Allocator, path: []const u8) !Level {
|
||
|
const path_ = try std.fs.realpathAlloc(allocator, path);
|
||
|
defer allocator.free(path_);
|
||
|
|
||
|
const file = try std.fs.openFileAbsolute(path_, .{ .mode = .read_only });
|
||
|
defer file.close();
|
||
|
|
||
|
const data = try file.readToEndAlloc(allocator, 1024 * 1024);
|
||
|
defer allocator.free(data);
|
||
|
|
||
|
return try Level.loadFromMemory(allocator, data);
|
||
|
}
|
||
|
|
||
|
pub fn loadFromMemory(allocator: std.mem.Allocator, data: []const u8) !Level {
|
||
|
const n = std.mem.count(u8, data, "\n");
|
||
|
_ = n;
|
||
|
|
||
|
var character: ?engine.Point = null;
|
||
|
var tiles = Components(Tile).init(allocator);
|
||
|
var collectables = Components(Collectable).init(allocator);
|
||
|
|
||
|
var lines = std.mem.split(u8, data, "\n");
|
||
|
var y: i64 = 0;
|
||
|
while (lines.next()) |line| {
|
||
|
defer y += 1;
|
||
|
|
||
|
try tiles.ensureColumns(line.len);
|
||
|
try collectables.ensureColumns(line.len);
|
||
|
|
||
|
for (line, 0..) |tile, column| {
|
||
|
var x = @intCast(i64, column);
|
||
|
switch (tile) {
|
||
|
'P' => character = engine.Point.init(x, y),
|
||
|
'S' => try collectables.set(x, y, Collectable.Star),
|
||
|
'x' => try tiles.set(x, y, Tile.Grass),
|
||
|
else => {},
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Level{
|
||
|
.character = character.?,
|
||
|
.tiles = tiles,
|
||
|
.collectables = collectables,
|
||
|
};
|
||
|
}
|
||
|
};
|