diff --git a/src/artifacts.zig b/src/artifacts.zig index acdd5e2..4b15b9c 100644 --- a/src/artifacts.zig +++ b/src/artifacts.zig @@ -44,9 +44,9 @@ pub const FightError = APIError || error { MonsterNotFound, }; -pub const GatheringError = APIError || error { +pub const GatherError = APIError || error { CharacterIsBusy, - CharacterMissingSkill, + NotEnoughSkill, CharacterIsFull, CharacterNotFound, CharacterInCooldown, @@ -92,6 +92,17 @@ pub const BankWithdrawItemError = APIError || error { BankNotFound }; +pub const CraftError = APIError || error { + RecipeNotFound, + NotEnoughItems, + CharacterIsBusy, + NotEnoughSkill, + CharacterIsFull, + CharacterNotFound, + CharacterInCooldown, + WorkshopNotFound +}; + const ServerStatus = struct { allocator: Allocator, status: []const u8, @@ -297,57 +308,57 @@ pub const FightResult = struct { } }; -pub const GatheringResult = struct { - const Details = struct { - const Item = struct { - id: ItemId, - quantity: i64 - }; - - xp: i64, - items: std.BoundedArray(Item, 8), - - fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !Details { - var items = std.BoundedArray(Item, 8).init(0) catch unreachable; - const items_obj = json_utils.getArray(obj, "items") orelse return error.MissingProperty; - for (items_obj.items) |item_value| { - const item_obj = json_utils.asObject(item_value) orelse return error.MissingProperty; - const code = try json_utils.getStringRequired(item_obj, "code"); - - try items.append(Item{ - .id = try api.getItemId(code), - .quantity = try json_utils.getIntegerRequired(item_obj, "quantity") - }); - } - - return Details{ - .xp = try json_utils.getIntegerRequired(obj, "xp"), - .items = items, - }; - } +pub const SkillDetails = struct { + pub const Item = struct { + id: ItemId, + quantity: i64 }; - cooldown: Cooldown, - details: Details, + xp: i64, + items: std.BoundedArray(Item, 8), - pub fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !GatheringResult { + fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !SkillDetails { + var items = std.BoundedArray(Item, 8).init(0) catch unreachable; + const items_obj = json_utils.getArray(obj, "items") orelse return error.MissingProperty; + for (items_obj.items) |item_value| { + const item_obj = json_utils.asObject(item_value) orelse return error.MissingProperty; + const code = try json_utils.getStringRequired(item_obj, "code"); + + try items.append(Item{ + .id = try api.getItemId(code), + .quantity = try json_utils.getIntegerRequired(item_obj, "quantity") + }); + } + + return SkillDetails{ + .xp = try json_utils.getIntegerRequired(obj, "xp"), + .items = items, + }; + } +}; + +pub const GatherResult = struct { + cooldown: Cooldown, + details: SkillDetails, + + pub fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !GatherResult { const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty; const details = json_utils.getObject(obj, "details") orelse return error.MissingProperty; - return GatheringResult{ + return GatherResult{ .cooldown = try Cooldown.parse(cooldown), - .details = try Details.parse(api, details) + .details = try SkillDetails.parse(api, details) }; } - pub fn parseError(status: std.http.Status) ?GatheringError { + pub fn parseError(status: std.http.Status) ?GatherError { return switch (@intFromEnum(status)) { - 486 => return GatheringError.CharacterIsBusy, - 493 => return GatheringError.CharacterMissingSkill, - 497 => return GatheringError.CharacterIsFull, - 498 => return GatheringError.CharacterNotFound, - 499 => return GatheringError.CharacterInCooldown, - 598 => return GatheringError.ResourceNotFound, + 486 => return GatherError.CharacterIsBusy, + 493 => return GatherError.NotEnoughSkill, + 497 => return GatherError.CharacterIsFull, + 498 => return GatherError.CharacterNotFound, + 499 => return GatherError.CharacterInCooldown, + 598 => return GatherError.ResourceNotFound, else => null }; } @@ -468,6 +479,35 @@ pub const ItemTransactionResult = struct { } }; +pub const CraftResult = struct { + cooldown: Cooldown, + details: SkillDetails, + + pub fn parse(api: *ArtifactsAPI, obj: json.ObjectMap) !CraftResult { + const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty; + const details = json_utils.getObject(obj, "details") orelse return error.MissingProperty; + + return CraftResult{ + .cooldown = try Cooldown.parse(cooldown), + .details = try SkillDetails.parse(api, details) + }; + } + + pub fn parseError(status: std.http.Status) ?CraftError { + return switch (@intFromEnum(status)) { + 404 => return CraftError.RecipeNotFound, + 478 => return CraftError.NotEnoughItems, + 486 => return CraftError.CharacterIsBusy, + 493 => return CraftError.NotEnoughSkill, + 497 => return CraftError.CharacterIsFull, + 498 => return CraftError.CharacterNotFound, + 499 => return CraftError.CharacterInCooldown, + 598 => return CraftError.WorkshopNotFound, + else => null + }; + } +}; + pub const ArtifactsFetchResult = struct { arena: std.heap.ArenaAllocator, status: std.http.Status, @@ -741,15 +781,15 @@ pub fn actionFight(self: *ArtifactsAPI, name: []const u8) FightError!FightResult ); } -pub fn actionGathering(self: *ArtifactsAPI, name: []const u8) GatheringError!GatheringResult { +pub fn actionGather(self: *ArtifactsAPI, name: []const u8) GatherError!GatherResult { const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/gathering", .{name}); defer self.allocator.free(path); return try self.fetchObject( - GatheringError, - GatheringResult.parseError, - GatheringResult, - GatheringResult.parse, .{ }, + GatherError, + GatherResult.parseError, + GatherResult, + GatherResult.parse, .{ }, .{ .method = .POST, .path = path } ); } @@ -852,6 +892,27 @@ pub fn actionBankWithdrawItem( ); } +pub fn actionCraft( + self: *ArtifactsAPI, + name: []const u8, + code: []const u8, + quantity: u64 +) !CraftResult { + const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/crafting", .{name}); + defer self.allocator.free(path); + + const payload = try std.fmt.allocPrint(self.allocator, "{{ \"code\":\"{s}\",\"quantity\":{} }}", .{code, quantity}); + defer self.allocator.free(payload); + + return try self.fetchObject( + CraftError, + CraftResult.parseError, + CraftResult, + CraftResult.parse, .{ }, + .{ .method = .POST, .path = path, .payload = payload } + ); +} + test "parse date time" { try std.testing.expectEqual(1723069394.105, parseDateTime("2024-08-07T22:23:14.105Z").?); } diff --git a/src/main.zig b/src/main.zig index f718707..a76055a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -24,7 +24,7 @@ const Position = struct { const QueuedAction = union(enum) { move: Position, attack, - gathering, + gather, depositGold: u64, depositItem: struct { id: ArtifactsAPI.ItemId, quantity: u64 }, }; @@ -172,7 +172,7 @@ fn gatherResourceRoutine(managed_char: *ManagedCharacter, resource_pos: Position return; } - try action_queue.append(.{ .gathering = {} }); + try action_queue.append(.{ .gather = {} }); } pub fn main() !void { @@ -259,9 +259,9 @@ pub fn main() !void { cooldown = result.cooldown; char.character.inventory.removeItem(item.id, item.quantity); }, - .gathering => { + .gather => { std.log.debug("{s} gathers", .{char.character.name}); - var result = try api.actionGathering(char.character.name); + var result = try api.actionGather(char.character.name); cooldown = result.cooldown; for (result.details.items.slice()) |item| {