const std = @import("std"); const Api = @import("artifacts-api"); const Server = Api.Server; const Position = Api.Position; const Allocator = std.mem.Allocator; const assert = std.debug.assert; const CharacterTask = @import("./task.zig").Task; const QueuedAction = @import("./action.zig").Action; const QueuedActionResult = @import("./action.zig").ActionResult; const Brain = @This(); name: []const u8, action_queue: std.ArrayList(QueuedAction), task: ?CharacterTask = null, paused_until: ?i64 = null, pub fn init(allocator: Allocator, name: []const u8) !Brain { return Brain{ .name = try allocator.dupe(u8, name), .action_queue = std.ArrayList(QueuedAction).init(allocator), }; } pub fn deinit(self: Brain) void { const allocator = self.action_queue.allocator; allocator.free(self.name); self.action_queue.deinit(); } pub fn performNextAction(self: *Brain, api: *Server) !void { const log = std.log.default; assert(self.action_queue.items.len > 0); const retry_delay = std.time.ns_per_ms * 500; // 500ms const next_action = self.action_queue.items[0]; const action_result = try next_action.perform(api, self.name); if (action_result.getErrorResponse()) |error_response| { switch (error_response) { .retry => { self.paused_until = std.time.timestamp() + retry_delay; log.warn("[{s}] retry action", .{self.name}); return; }, .restart => { log.warn("[{s}] clear action queue", .{self.name}); self.action_queue.clearAndFree(); return; }, .abort => { try action_result.getError(); // The error above should always return unreachable; }, .ignore => { }, } } _ = self.action_queue.orderedRemove(0); if (self.task) |*task| { task.onActionCompleted(action_result); } } pub fn step(self: *Brain, api: *Api.Server) !void { if (self.paused_until) |paused_until| { if (std.time.timestamp() < paused_until) { return; } self.paused_until = null; } if (self.action_queue.items.len > 0) return; if (self.task) |task| { if (task.isComplete()) { // if (try brain.depositItemsToBank(&self.server)) { // continue; // } self.task = null; } } if (self.task) |task| { try task.queueActions(api, self.name, &self.action_queue); } } pub fn cooldown(self: *Brain, api: *Server) i64 { const character = api.store.getCharacter(self.name).?; const cooldown_expiration: i64 = @intFromFloat(character.cooldown_expiration * std.time.ns_per_s); if (self.paused_until) |pause_until| { return @max(cooldown_expiration, pause_until); } else { return cooldown_expiration; } }