artificer/api/character.zig

161 lines
5.3 KiB
Zig

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();
const TaskMasterTask = struct {
target: []u8,
type: []u8,
progress: u64,
total: u64,
};
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: u64,
inventory: Inventory,
task: ?TaskMasterTask,
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;
if (name.len == 0) {
return error.InvalidName;
}
const inventory_max_items = json_utils.getInteger(obj, "inventory_max_items") orelse return error.MissingProperty;
if (inventory_max_items < 0) {
return error.InvalidInventoryMaxItems;
}
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),
};
}
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 = @intCast(inventory_max_items),
.inventory = try Inventory.parse(api, inventory),
.task = task
};
}
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 {
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
});
}