add accepting task and fighting monster
This commit is contained in:
parent
cc289194a8
commit
429b1dcd6e
@ -43,11 +43,13 @@ const MapNotFound = ErrorDefinition.init("MapNotFound", 404);
|
||||
const ItemNotFound = ErrorDefinition.init("ItemNotFound", 404);
|
||||
const RecipeNotFound = ErrorDefinition.init("RecipeNotFound", 404);
|
||||
|
||||
const BankIsBusy = ErrorDefinition.init("BankIsBusy", 461);
|
||||
const NotEnoughItems = ErrorDefinition.init("NotEnoughItems", 478);
|
||||
const SlotIsFull = ErrorDefinition.init("SlotIsFull", 485);
|
||||
const CharacterIsBusy = ErrorDefinition.init("CharacterIsBusy", 486);
|
||||
const AlreadyHasTask = ErrorDefinition.init("AlreadyHasTask", 486);
|
||||
const BankIsBusy = ErrorDefinition.init("BankIsBusy", 461);
|
||||
const NotEnoughItems = ErrorDefinition.init("NotEnoughItems", 478);
|
||||
const SlotIsFull = ErrorDefinition.init("SlotIsFull", 485);
|
||||
const CharacterIsBusy = ErrorDefinition.init("CharacterIsBusy", 486);
|
||||
const AlreadyHasTask = ErrorDefinition.init("AlreadyHasTask", 486);
|
||||
const HasNoTask = ErrorDefinition.init("HasNoTask", 487);
|
||||
const TaskNotCompleted = ErrorDefinition.init("TaskNotCompleted", 488);
|
||||
|
||||
const CharacterAtDestination = ErrorDefinition.init("CharacterAtDestination", 490);
|
||||
const SlotIsEmpty = ErrorDefinition.init("SlotIsEmpty", 491);
|
||||
@ -183,12 +185,24 @@ const EquipErrorDef = ErrorDefinitionList(&[_]ErrorDefinition{
|
||||
pub const EquipError = FetchError || EquipErrorDef.ErrorSet;
|
||||
pub const parseEquipError = EquipErrorDef.parse;
|
||||
|
||||
const TaskAcceptErrorDef = ErrorDefinitionList(&[_]ErrorDefinition{
|
||||
const AcceptTaskErrorDef = ErrorDefinitionList(&[_]ErrorDefinition{
|
||||
CharacterIsBusy,
|
||||
AlreadyHasTask,
|
||||
CharacterNotFound,
|
||||
CharacterInCooldown,
|
||||
TaskMasterNotFound
|
||||
});
|
||||
pub const TaskAcceptError = FetchError || TaskAcceptErrorDef.ErrorSet;
|
||||
pub const parseTaskAcceptError = TaskAcceptErrorDef.parse;
|
||||
pub const AcceptTaskError = FetchError || AcceptTaskErrorDef.ErrorSet;
|
||||
pub const parseAcceptTaskError = AcceptTaskErrorDef.parse;
|
||||
|
||||
const TaskCompleteErrorDef = ErrorDefinitionList(&[_]ErrorDefinition{
|
||||
CharacterIsBusy,
|
||||
HasNoTask,
|
||||
TaskNotCompleted,
|
||||
CharacterIsFull,
|
||||
CharacterNotFound,
|
||||
CharacterInCooldown,
|
||||
TaskMasterNotFound
|
||||
});
|
||||
pub const TaskCompleteError = FetchError || TaskCompleteErrorDef.ErrorSet;
|
||||
pub const parseTaskCompleteError = TaskCompleteErrorDef.parse;
|
||||
|
@ -4,6 +4,7 @@ pub const parseDateTime = @import("./date_time/parse.zig").parseDateTime;
|
||||
pub const Server = @import("server.zig");
|
||||
pub const Store = @import("store.zig");
|
||||
pub const Character = @import("./schemas/character.zig");
|
||||
pub const Map = @import("./schemas/map.zig");
|
||||
pub const Position = @import("position.zig");
|
||||
pub const BoundedSlotsArray = @import("schemas/slot_array.zig").BoundedSlotsArray;
|
||||
|
||||
@ -20,3 +21,4 @@ pub const BankDepositGoldError = errors.BankDepositGoldError;
|
||||
pub const BankDepositItemError = errors.BankDepositItemError;
|
||||
pub const BankWithdrawItemError = errors.BankWithdrawItemError;
|
||||
pub const CraftError = errors.CraftError;
|
||||
pub const AcceptTaskError = errors.AcceptTaskError;
|
||||
|
@ -10,6 +10,7 @@ const assert = std.debug.assert;
|
||||
const SkillStats = @import("./skill_stats.zig");
|
||||
const CombatStats = @import("./combat_stats.zig");
|
||||
const Equipment = @import("./equipment.zig");
|
||||
const Task = @import("./task.zig");
|
||||
const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray;
|
||||
|
||||
const Inventory = BoundedSlotsArray(20);
|
||||
@ -17,10 +18,32 @@ const Inventory = BoundedSlotsArray(20);
|
||||
const Character = @This();
|
||||
|
||||
const TaskMasterTask = struct {
|
||||
target: []u8,
|
||||
type: []u8,
|
||||
target_id: Store.CodeId,
|
||||
type: Task.Type,
|
||||
progress: u64,
|
||||
total: u64,
|
||||
|
||||
fn parse(store: *Store, obj: json.ObjectMap) !TaskMasterTask {
|
||||
const task_target = try json_utils.getStringRequired(obj, "task");
|
||||
const task_type = try json_utils.getStringRequired(obj, "task_type");
|
||||
|
||||
const progress = try json_utils.getIntegerRequired(obj, "task_progress");
|
||||
if (progress < 0) {
|
||||
return error.InvalidTaskProgress;
|
||||
}
|
||||
|
||||
const total = try json_utils.getIntegerRequired(obj, "task_total");
|
||||
if (total < 0) {
|
||||
return error.InvalidTaskTotal;
|
||||
}
|
||||
|
||||
return TaskMasterTask{
|
||||
.target_id = try store.getCodeId(task_target),
|
||||
.type = Task.TypeUtils.fromString(task_type) orelse return error.InvalidTaskType,
|
||||
.total = @intCast(total),
|
||||
.progress = @intCast(progress),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
allocator: Allocator,
|
||||
@ -74,22 +97,7 @@ pub fn parse(store: *Store, obj: json.ObjectMap, allocator: Allocator) !Characte
|
||||
var task: ?TaskMasterTask = null;
|
||||
const task_target = try json_utils.getStringRequired(obj, "task");
|
||||
if (task_target.len > 0) {
|
||||
const progress = try json_utils.getIntegerRequired(obj, "task_progress");
|
||||
if (progress < 0) {
|
||||
return error.InvalidTaskProgress;
|
||||
}
|
||||
|
||||
const total = try json_utils.getIntegerRequired(obj, "task_total");
|
||||
if (total < 0) {
|
||||
return error.InvalidTaskTotal;
|
||||
}
|
||||
|
||||
task = TaskMasterTask{
|
||||
.target = try allocator.dupe(u8, task_target),
|
||||
.type = try json_utils.dupeStringRequired(allocator, obj, "task_type"),
|
||||
.total = @intCast(total),
|
||||
.progress = @intCast(progress),
|
||||
};
|
||||
task = try TaskMasterTask.parse(store, obj);
|
||||
}
|
||||
|
||||
return Character{
|
||||
@ -131,11 +139,6 @@ pub fn deinit(self: *Character) void {
|
||||
if (self.account) |str| self.allocator.free(str);
|
||||
self.allocator.free(self.name);
|
||||
self.allocator.free(self.skin);
|
||||
|
||||
if (self.task) |task| {
|
||||
self.allocator.free(task.type);
|
||||
self.allocator.free(task.target);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getItemCount(self: *const Character) u64 {
|
||||
|
@ -24,7 +24,7 @@ pub fn parse(store: *Store, obj: json.ObjectMap, allocator: Allocator) !Map {
|
||||
.name = (try json_utils.dupeString(allocator, obj, "name")) orelse return error.MissingProperty,
|
||||
.skin = (try json_utils.dupeString(allocator, obj, "skin")) orelse return error.MissingProperty,
|
||||
.position = Position.init(x, y),
|
||||
.content = try MapContent.parse(store, content)
|
||||
.content = if (content) |c| try MapContent.parse(store, c) else null
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -27,11 +27,11 @@ pub const TypeUtils = EnumStringUtils(Type, .{
|
||||
type: Type,
|
||||
code_id: Store.CodeId,
|
||||
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) MapContent {
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) !MapContent {
|
||||
const content_type = json_utils.getString(obj, "type") orelse return error.MissingProperty;
|
||||
|
||||
return MapContent{
|
||||
.type = TypeUtils.fromString(content_type) orelse return error.InvalidContentType,
|
||||
.code = (try store.getCodeIdJson(obj, "code")) orelse return error.MissingProperty
|
||||
.code_id = (try store.getCodeIdJson(obj, "code")) orelse return error.MissingProperty
|
||||
};
|
||||
}
|
||||
|
@ -8,14 +8,18 @@ const Items = BoundedSlotsArray(8);
|
||||
|
||||
const SkillInfo = @This();
|
||||
|
||||
xp: i64,
|
||||
xp: u64,
|
||||
items: Items,
|
||||
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap) !SkillInfo {
|
||||
const items = json_utils.getArray(obj, "items") orelse return error.MissingProperty;
|
||||
const xp = try json_utils.getIntegerRequired(obj, "xp");
|
||||
if (xp < 0) {
|
||||
return error.InvalidXp;
|
||||
}
|
||||
|
||||
return SkillInfo{
|
||||
.xp = try json_utils.getIntegerRequired(obj, "xp"),
|
||||
.xp = @intCast(xp),
|
||||
.items = try Items.parse(store, items),
|
||||
};
|
||||
}
|
||||
|
27
api/schemas/task_reward_data.zig
Normal file
27
api/schemas/task_reward_data.zig
Normal file
@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
const Store = @import("../store.zig");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const json = std.json;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Character = @import("./character.zig");
|
||||
const ItemQuantity = @import("./item_quantity.zig");
|
||||
|
||||
const TaskRewardData = @This();
|
||||
|
||||
cooldown: Cooldown,
|
||||
character: Character,
|
||||
reward: ItemQuantity,
|
||||
|
||||
pub fn parse(store: *Store, obj: json.ObjectMap, allocator: Allocator) !TaskRewardData {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
const task = json_utils.getObject(obj, "task") orelse return error.MissingProperty;
|
||||
|
||||
return TaskRewardData{
|
||||
.cooldown = try Cooldown.parse(cooldown),
|
||||
.character = try Character.parse(store, character, allocator),
|
||||
.reward = (try ItemQuantity.parse(store, task)) orelse return error.MissinReward
|
||||
};
|
||||
}
|
@ -45,6 +45,7 @@ pub const UnequipResult = @import("./schemas/equip_request.zig");
|
||||
pub const EquipResult = @import("./schemas/equip_request.zig");
|
||||
const DropRate = @import("./schemas/drop_rate.zig");
|
||||
pub const AcceptTaskResult = @import("./schemas/task_data.zig");
|
||||
pub const CompleteTaskResult = @import("./schemas/task_reward_data.zig");
|
||||
pub const MapContent = @import("./schemas/map_content.zig");
|
||||
pub const MapTile = @import("./schemas/map.zig");
|
||||
pub const Item = @import("./schemas/item.zig");
|
||||
@ -1028,13 +1029,13 @@ pub fn getMonsters(self: *Server, opts: MonsterOptions) FetchError!std.ArrayList
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn acceptTask(self: *Server, name: []const u8) errors.TaskAcceptError!AcceptTaskResult {
|
||||
pub fn acceptTask(self: *Server, name: []const u8) errors.AcceptTaskError!AcceptTaskResult {
|
||||
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/task/new", .{name});
|
||||
defer self.allocator.free(path);
|
||||
|
||||
const result = try self.fetchObject(
|
||||
errors.TaskAcceptError,
|
||||
errors.parseTaskAcceptError,
|
||||
errors.AcceptTaskError,
|
||||
errors.parseAcceptTaskError,
|
||||
AcceptTaskResult,
|
||||
AcceptTaskResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path }
|
||||
@ -1043,3 +1044,19 @@ pub fn acceptTask(self: *Server, name: []const u8) errors.TaskAcceptError!Accept
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn completeTask(self: *Server, name: []const u8) errors.TaskCompleteError!CompleteTaskResult {
|
||||
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/task/complete", .{name});
|
||||
defer self.allocator.free(path);
|
||||
|
||||
const result = try self.fetchObject(
|
||||
errors.TaskCompleteError,
|
||||
errors.parseTaskCompleteError,
|
||||
CompleteTaskResult,
|
||||
CompleteTaskResult.parse, .{ self.allocator },
|
||||
.{ .method = .POST, .path = path }
|
||||
);
|
||||
try self.store.putCharacter(result.character);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -155,7 +155,9 @@ pub fn getMaps(self: *Store, opts: Server.MapOptions) !std.ArrayList(Map) {
|
||||
}
|
||||
if (opts.code) |content_code| {
|
||||
if (map.content == null) continue;
|
||||
if (!std.mem.eql(u8, map.content.?.code, content_code)) continue;
|
||||
|
||||
const map_content_code = self.getCode(map.content.?.code_id).?;
|
||||
if (!std.mem.eql(u8, map_content_code, content_code)) continue;
|
||||
}
|
||||
|
||||
try found.append(map.*);
|
||||
|
@ -38,7 +38,7 @@ pub fn main() !void {
|
||||
std.log.info("Starting main loop", .{});
|
||||
while (true) {
|
||||
const waitUntil = artificer.nextStepAt();
|
||||
const duration = waitUntil - std.time.timestamp();
|
||||
const duration = waitUntil - std.time.milliTimestamp();
|
||||
if (duration > 0) {
|
||||
std.time.sleep(@intCast(duration));
|
||||
}
|
||||
|
30
gui/main.zig
30
gui/main.zig
@ -25,12 +25,34 @@ fn getAPITokenFromArgs(allocator: Allocator) !?[]u8 {
|
||||
return try allocator.dupe(u8, std.mem.trim(u8,token,"\n\t "));
|
||||
}
|
||||
|
||||
fn drawCharacterInfo(ui: *UI, rect: rl.Rectangle, brain: Artificer.Brain) void {
|
||||
fn drawCharacterInfo(ui: *UI, rect: rl.Rectangle, artificer: *Artificer, brain: *Artificer.Brain) !void {
|
||||
var buffer: [256]u8 = undefined;
|
||||
|
||||
const name_height = 20;
|
||||
UI.drawTextCentered(ui.font, brain.name, .{
|
||||
.x = RectUtils.center(rect).x,
|
||||
.y = rect.y + name_height/2
|
||||
}, 20, 2, srcery.bright_white);
|
||||
|
||||
var label_stack = UIStack.init(RectUtils.shrinkTop(rect, name_height + 4), .top_to_bottom);
|
||||
label_stack.gap = 4;
|
||||
|
||||
const now = std.time.milliTimestamp();
|
||||
const cooldown = brain.cooldown(&artificer.server);
|
||||
const seconds_left: f32 = @as(f32, @floatFromInt(@max(cooldown - now, 0))) / std.time.ms_per_s;
|
||||
const cooldown_label = try std.fmt.bufPrint(&buffer, "Cooldown: {d:.3}", .{ seconds_left });
|
||||
UI.drawTextEx(ui.font, cooldown_label, RectUtils.topLeft(label_stack.next(16)), 16, 2, srcery.bright_white);
|
||||
|
||||
var task_label: []u8 = undefined;
|
||||
if (brain.task) |task| {
|
||||
task_label = try std.fmt.bufPrint(&buffer, "Task: {s}", .{ @tagName(task) });
|
||||
} else {
|
||||
task_label = try std.fmt.bufPrint(&buffer, "Task: -", .{ });
|
||||
}
|
||||
UI.drawTextEx(ui.font, task_label, RectUtils.topLeft(label_stack.next(16)), 16, 2, srcery.bright_white);
|
||||
|
||||
const actions_label = try std.fmt.bufPrint(&buffer, "Actions: {}", .{ brain.action_queue.items.len });
|
||||
UI.drawTextEx(ui.font, actions_label, RectUtils.topLeft(label_stack.next(16)), 16, 2, srcery.bright_white);
|
||||
}
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
@ -53,7 +75,7 @@ pub fn main() anyerror!void {
|
||||
defer ui.deinit();
|
||||
|
||||
while (!rl.windowShouldClose()) {
|
||||
if (std.time.timestamp() > artificer.nextStepAt()) {
|
||||
if (std.time.milliTimestamp() > artificer.nextStepAt()) {
|
||||
try artificer.step();
|
||||
}
|
||||
|
||||
@ -68,9 +90,9 @@ pub fn main() anyerror!void {
|
||||
rl.clearBackground(srcery.black);
|
||||
|
||||
var info_stack = UIStack.init(rl.Rectangle.init(0, 0, screen_size.x, screen_size.y), .left_to_right);
|
||||
for (artificer.characters.items) |brain| {
|
||||
for (artificer.characters.items) |*brain| {
|
||||
const info_width = screen_size.x / @as(f32, @floatFromInt(artificer.characters.items.len));
|
||||
drawCharacterInfo(&ui, info_stack.next(info_width), brain);
|
||||
try drawCharacterInfo(&ui, info_stack.next(info_width), &artificer, brain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ pub const Action = union(enum) {
|
||||
deposit_item: Api.ItemQuantity,
|
||||
withdraw_item: Api.ItemQuantity,
|
||||
craft_item: Api.ItemQuantity,
|
||||
accept_task,
|
||||
|
||||
pub fn perform(self: Action, api: *Server, name: []const u8) !ActionResult {
|
||||
const log = std.log.default;
|
||||
@ -61,6 +62,12 @@ pub const Action = union(enum) {
|
||||
return .{
|
||||
.craft_item = api.actionCraft(name, code, item.quantity)
|
||||
};
|
||||
},
|
||||
.accept_task => {
|
||||
log.debug("[{s}] accept task", .{name});
|
||||
return .{
|
||||
.accept_task = api.acceptTask(name)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,6 +95,7 @@ pub const ActionResult = union(enum) {
|
||||
deposit_item: Api.BankDepositItemError!Server.ItemTransactionResult,
|
||||
withdraw_item: Api.BankWithdrawItemError!Server.ItemTransactionResult,
|
||||
craft_item: Api.CraftError!Server.CraftResult,
|
||||
accept_task: Api.AcceptTaskError!Server.AcceptTaskResult,
|
||||
|
||||
const AnyError = Server.MoveError;
|
||||
|
||||
@ -127,6 +135,9 @@ pub const ActionResult = union(enum) {
|
||||
},
|
||||
.craft_item => |result| {
|
||||
_ = try result;
|
||||
},
|
||||
.accept_task => |result| {
|
||||
_ = try result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,6 +160,8 @@ pub const ActionResult = union(enum) {
|
||||
error.ItemNotFound,
|
||||
error.NotEnoughItems,
|
||||
error.RecipeNotFound,
|
||||
error.AlreadyHasTask,
|
||||
error.TaskMasterNotFound,
|
||||
error.WorkshopNotFound => return ErrorResponse.restart,
|
||||
|
||||
error.CharacterNotFound,
|
||||
|
@ -14,7 +14,7 @@ const Brain = @This();
|
||||
name: []const u8,
|
||||
action_queue: std.ArrayList(QueuedAction),
|
||||
task: ?CharacterTask = null,
|
||||
paused_until: ?i64 = null,
|
||||
paused_until: ?i64 = null, // ms
|
||||
|
||||
pub fn init(allocator: Allocator, name: []const u8) !Brain {
|
||||
return Brain{
|
||||
@ -33,7 +33,7 @@ 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 retry_delay = 500; // 500ms
|
||||
|
||||
const next_action = self.action_queue.items[0];
|
||||
const action_result = try next_action.perform(api, self.name);
|
||||
@ -41,7 +41,7 @@ pub fn performNextAction(self: *Brain, api: *Server) !void {
|
||||
if (action_result.getErrorResponse()) |error_response| {
|
||||
switch (error_response) {
|
||||
.retry => {
|
||||
self.paused_until = std.time.timestamp() + retry_delay;
|
||||
self.paused_until = std.time.milliTimestamp() + retry_delay;
|
||||
log.warn("[{s}] retry action", .{self.name});
|
||||
return;
|
||||
},
|
||||
@ -51,6 +51,7 @@ pub fn performNextAction(self: *Brain, api: *Server) !void {
|
||||
return;
|
||||
},
|
||||
.abort => {
|
||||
log.warn("[{s}] abort action {s}", .{ self.name, @tagName(next_action) });
|
||||
try action_result.getError();
|
||||
|
||||
// The error above should always return
|
||||
@ -69,7 +70,7 @@ pub fn performNextAction(self: *Brain, api: *Server) !void {
|
||||
|
||||
pub fn step(self: *Brain, api: *Api.Server) !void {
|
||||
if (self.paused_until) |paused_until| {
|
||||
if (std.time.timestamp() < paused_until) {
|
||||
if (std.time.milliTimestamp() < paused_until) {
|
||||
return;
|
||||
}
|
||||
self.paused_until = null;
|
||||
@ -93,7 +94,7 @@ pub fn step(self: *Brain, api: *Api.Server) !void {
|
||||
|
||||
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);
|
||||
const cooldown_expiration: i64 = @intFromFloat(character.cooldown_expiration * std.time.ms_per_s);
|
||||
|
||||
if (self.paused_until) |pause_until| {
|
||||
return @max(cooldown_expiration, pause_until);
|
||||
|
52
lib/root.zig
52
lib/root.zig
@ -14,7 +14,7 @@ server: Api.Server,
|
||||
characters: std.ArrayList(Brain),
|
||||
task_graph: TaskGraph,
|
||||
|
||||
paused_until: ?i64 = null,
|
||||
paused_until: ?i64 = null, // ms
|
||||
|
||||
pub fn init(allocator: Allocator, token: []const u8) !Artificer {
|
||||
var server = try Api.Server.init(allocator);
|
||||
@ -49,7 +49,7 @@ pub fn deinit(self: *Artificer) void {
|
||||
|
||||
pub fn step(self: *Artificer) !void {
|
||||
if (self.paused_until) |paused_until| {
|
||||
if (std.time.timestamp() < paused_until) {
|
||||
if (std.time.milliTimestamp() < paused_until) {
|
||||
return;
|
||||
}
|
||||
self.paused_until = null;
|
||||
@ -57,7 +57,7 @@ pub fn step(self: *Artificer) !void {
|
||||
|
||||
runNextActions(self.characters.items, &self.server) catch |err| switch (err) {
|
||||
Api.FetchError.ServerUnavailable => {
|
||||
self.paused_until = std.time.timestamp() + std.time.ns_per_min * server_down_retry_interval;
|
||||
self.paused_until = std.time.milliTimestamp() + std.time.ms_per_min * server_down_retry_interval;
|
||||
std.log.warn("Server is down, retrying in {}min", .{ server_down_retry_interval });
|
||||
return;
|
||||
},
|
||||
@ -65,14 +65,40 @@ pub fn step(self: *Artificer) !void {
|
||||
};
|
||||
|
||||
for (self.characters.items) |*brain| {
|
||||
if (brain.task == null) {
|
||||
const character = self.server.store.getCharacter(brain.name).?;
|
||||
if (character.task == null) {
|
||||
brain.task = .{ .accept_task = .{} };
|
||||
}
|
||||
if (brain.task != null) {
|
||||
try brain.step(&self.server);
|
||||
continue;
|
||||
}
|
||||
|
||||
try brain.step(&self.server);
|
||||
const character = self.server.store.getCharacter(brain.name).?;
|
||||
if (character.task) |taskmaster_task| {
|
||||
if (taskmaster_task.total > taskmaster_task.progress) {
|
||||
switch (taskmaster_task.type) {
|
||||
.monsters => {
|
||||
const monster_code = self.server.store.getCode(taskmaster_task.target_id).?;
|
||||
|
||||
const maps = try self.server.getMaps(.{ .code = monster_code });
|
||||
defer maps.deinit();
|
||||
|
||||
if (maps.items.len > 0) {
|
||||
const resource_map: Api.Map = maps.items[0];
|
||||
std.debug.print("fight at {}\n", .{resource_map.position});
|
||||
|
||||
brain.task = .{
|
||||
.fight = .{
|
||||
.at = resource_map.position,
|
||||
.until = .{ .quantity = taskmaster_task.total - taskmaster_task.progress },
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
.crafts => {},
|
||||
.resources => {},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
brain.task = .{ .accept_task = .{} };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,17 +125,11 @@ fn earliestCooldown(characters: []Brain, api: *Api.Server) ?i64 {
|
||||
}
|
||||
|
||||
fn runNextActions(characters: []Brain, api: *Api.Server) !void {
|
||||
const maybe_earliest_cooldown = earliestCooldown(characters, api);
|
||||
if (maybe_earliest_cooldown == null) return;
|
||||
|
||||
const earliest_cooldown = maybe_earliest_cooldown.?;
|
||||
if (earliest_cooldown < std.time.timestamp()) return;
|
||||
|
||||
for (characters) |*brain| {
|
||||
if (brain.action_queue.items.len == 0) continue;
|
||||
|
||||
const cooldown = brain.cooldown(api);
|
||||
if (earliest_cooldown > cooldown) {
|
||||
if (std.time.milliTimestamp() >= cooldown) {
|
||||
try brain.performNextAction(api);
|
||||
}
|
||||
}
|
||||
|
59
lib/task.zig
59
lib/task.zig
@ -7,11 +7,22 @@ const ActionResult = @import("./action.zig").ActionResult;
|
||||
const CodeId = Api.CodeId;
|
||||
const ItemQuantity = Api.ItemQuantity;
|
||||
|
||||
const bank_position: Position = .{ .x = 4, .y = 1 }; // TODO: Figure this out dynamically
|
||||
const bank_position = Position{ .x = 4, .y = 1 }; // TODO: Figure this out dynamically
|
||||
|
||||
const task_master_position = Position{ .x = 1, .y = 2 }; // TODO: Figure this out dynamically
|
||||
|
||||
pub const UntilCondition = union(enum) {
|
||||
xp: u64,
|
||||
item: Api.ItemQuantity,
|
||||
quantity: u64,
|
||||
|
||||
fn isComplete(self: UntilCondition, progress: u64) bool {
|
||||
return switch (self) {
|
||||
.xp => |xp| progress >= xp,
|
||||
.item => |item| progress >= item.quantity,
|
||||
.quantity => |quantity| progress >= quantity,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Task = union(enum) {
|
||||
@ -36,8 +47,8 @@ pub const Task = union(enum) {
|
||||
|
||||
pub fn isComplete(self: Task) bool {
|
||||
return switch (self) {
|
||||
.fight => |args| args.progress >= args.until.item.quantity,
|
||||
.gather => |args| args.progress >= args.until.item.quantity,
|
||||
.fight => |args| args.until.isComplete(args.progress),
|
||||
.gather => |args| args.until.isComplete(args.progress),
|
||||
.craft => |args| args.progress >= args.target.quantity,
|
||||
.accept_task => |args| args.done
|
||||
};
|
||||
@ -48,17 +59,37 @@ pub const Task = union(enum) {
|
||||
.fight => |*args| {
|
||||
if (result.get(.fight)) |r| {
|
||||
const fight_result: Api.Server.FightResult = r;
|
||||
const drops = fight_result.fight.drops;
|
||||
|
||||
args.progress += drops.getQuantity(args.until.item.id);
|
||||
switch (args.until) {
|
||||
.xp => {
|
||||
args.progress += fight_result.fight.xp;
|
||||
},
|
||||
.item => {
|
||||
const drops = fight_result.fight.drops;
|
||||
args.progress += drops.getQuantity(args.until.item.id);
|
||||
},
|
||||
.quantity => {
|
||||
args.progress += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.gather => |*args| {
|
||||
if (result.get(.gather)) |r| {
|
||||
const gather_resutl: Api.Server.GatherResult = r;
|
||||
const items = gather_resutl.details.items;
|
||||
const gather_result: Api.Server.GatherResult = r;
|
||||
|
||||
args.progress += items.getQuantity(args.until.item.id);
|
||||
switch (args.until) {
|
||||
.xp => {
|
||||
args.progress += gather_result.details.xp;
|
||||
},
|
||||
.item => {
|
||||
const items = gather_result.details.items;
|
||||
args.progress += items.getQuantity(args.until.item.id);
|
||||
},
|
||||
.quantity => {
|
||||
args.progress += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.craft => |*args| {
|
||||
@ -69,8 +100,10 @@ pub const Task = union(enum) {
|
||||
args.progress += items.getQuantity(args.target.id);
|
||||
}
|
||||
},
|
||||
.accept_task => {
|
||||
// TODO:
|
||||
.accept_task => |*args| {
|
||||
if (result.get(.accept_task)) |_| {
|
||||
args.done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,7 +126,11 @@ pub const Task = union(enum) {
|
||||
try ctx.craftRoutine(args.at, args.target.id, args.target.quantity);
|
||||
},
|
||||
.accept_task => {
|
||||
// TODO:
|
||||
if (try ctx.moveIfNeeded(task_master_position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try ctx.action_queue.append(.{ .accept_task = {} });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user