const std = @import("std"); const json_utils = @import("json_utils.zig"); const Server = @import("./server.zig"); const Position = @import("./position.zig"); const parseDateTime = Server.parseDateTime; const ItemId = Server.ItemId; const Allocator = std.mem.Allocator; const json = std.json; const assert = std.debug.assert; const SkillStats = @import("./skill_stats.zig"); const CombatStats = @import("./combat_stats.zig"); const Equipment = @import("./equipment.zig"); const BoundedSlotsArray = @import("./slot_array.zig").BoundedSlotsArray; const Inventory = BoundedSlotsArray(20); const Character = @This(); allocator: Allocator, name: []u8, skin: []u8, account: ?[]u8, gold: i64, hp: i64, haste: i64, position: Position, cooldown_expiration: f64, combat: SkillStats, mining: SkillStats, woodcutting: SkillStats, fishing: SkillStats, weaponcrafting: SkillStats, gearcrafting: SkillStats, jewelrycrafting: SkillStats, cooking: SkillStats, water: CombatStats, fire: CombatStats, earth: CombatStats, air: CombatStats, equipment: Equipment, inventory_max_items: i64, inventory: Inventory, pub fn parse(api: *Server, obj: json.ObjectMap, allocator: Allocator) !Character { const inventory = json_utils.getArray(obj, "inventory") orelse return error.MissingProperty; const cooldown_expiration = json_utils.getString(obj, "cooldown_expiration") orelse return error.MissingProperty; const x = try json_utils.getIntegerRequired(obj, "x"); const y = try json_utils.getIntegerRequired(obj, "y"); const name = (try json_utils.dupeString(allocator, obj, "name")) orelse return error.MissingProperty; assert(name.len > 0); return Character{ .allocator = allocator, .account = try json_utils.dupeString(allocator, obj, "account"), .name = name, .skin = (try json_utils.dupeString(allocator, obj, "skin")) orelse return error.MissingProperty, .gold = try json_utils.getIntegerRequired(obj, "gold"), .hp = try json_utils.getIntegerRequired(obj, "hp"), .haste = try json_utils.getIntegerRequired(obj, "haste"), .position = Position.init(x, y), .cooldown_expiration = parseDateTime(cooldown_expiration) orelse return error.InvalidDateTime, .combat = try SkillStats.parse(obj, "level", "xp", "max_xp"), .mining = try SkillStats.parse(obj, "mining_level", "mining_xp", "mining_max_xp"), .woodcutting = try SkillStats.parse(obj, "woodcutting_level", "woodcutting_xp", "woodcutting_max_xp"), .fishing = try SkillStats.parse(obj, "fishing_level", "fishing_xp", "fishing_max_xp"), .weaponcrafting = try SkillStats.parse(obj, "weaponcrafting_level", "weaponcrafting_xp", "weaponcrafting_max_xp"), .gearcrafting = try SkillStats.parse(obj, "gearcrafting_level", "gearcrafting_xp", "gearcrafting_max_xp"), .jewelrycrafting = try SkillStats.parse(obj, "jewelrycrafting_level", "jewelrycrafting_xp", "jewelrycrafting_max_xp"), .cooking = try SkillStats.parse(obj, "cooking_level", "cooking_xp", "cooking_max_xp"), .water = try CombatStats.parse(obj, "attack_water", "dmg_water", "res_water"), .fire = try CombatStats.parse(obj, "attack_fire", "dmg_fire", "res_fire"), .earth = try CombatStats.parse(obj, "attack_earth", "dmg_earth", "res_earth"), .air = try CombatStats.parse(obj, "attack_air", "dmg_air", "res_air"), .equipment = try Equipment.parse(api, obj), .inventory_max_items = json_utils.getInteger(obj, "inventory_max_items") orelse return error.MissingProperty, .inventory = try Inventory.parse(api, inventory) }; } pub fn deinit(self: *Character) void { if (self.account) |str| self.allocator.free(str); self.allocator.free(self.name); self.allocator.free(self.skin); } pub fn getItemCount(self: *const Character) u64 { return self.inventory.totalQuantity(); } pub fn format( self: Character, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void { _ = fmt; _ = options; try writer.print("{s}{{ .name = \"{s}\", .position = {} ... }}", .{ @typeName(Character), self.name, self.position }); }