// zig fmt: off const std = @import("std"); const Store = @import("../store.zig"); const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils; const json_utils = @import("../json_utils.zig"); pub const Equipment = @import("./equipment.zig"); const Task = @import("./task.zig"); const SimpleItem = @import("./simple_item.zig"); const Character = @This(); pub const Skin = enum { men1, men2, men3, women1, women2, women3, const Utils = EnumStringUtils(Skin, .{ .{ "men1" , Skin.men1 }, .{ "men2" , Skin.men2 }, .{ "men3" , Skin.men3 }, .{ "women1", Skin.women1 }, .{ "women2", Skin.women2 }, .{ "women3", Skin.women3 }, }); pub const fromString = Utils.fromString; pub const toString = Utils.toString; }; pub const Skill = enum { combat, fishing, weaponcrafting, gearcrafting, jewelrycrafting, cooking, woodcutting, mining, alchemy, const Utils = EnumStringUtils(Skill, .{ .{ "combat" , Skill.combat }, .{ "fishing" , Skill.fishing }, .{ "weaponcrafting" , Skill.weaponcrafting }, .{ "gearcrafting" , Skill.gearcrafting }, .{ "jewelrycrafting", Skill.jewelrycrafting }, .{ "cooking" , Skill.cooking }, .{ "woodcutting" , Skill.woodcutting }, .{ "mining" , Skill.mining }, .{ "alchemy" , Skill.alchemy }, }); pub const toString = Utils.toString; pub const fromString = Utils.fromString; }; pub const SkillStats = struct { level: u64 = 0, xp: u64 = 0, max_xp: u64 = 0, pub fn parse(object: std.json.ObjectMap, level: []const u8, xp: []const u8, max_xp: []const u8) !SkillStats { return SkillStats{ .level = try json_utils.getPositiveIntegerRequired(object, level), .xp = try json_utils.getPositiveIntegerRequired(object, xp), .max_xp = try json_utils.getPositiveIntegerRequired(object, max_xp), }; } }; pub const Element = enum { water, fire, earth, air, }; pub const ElementalStats = struct { attack: i64, damage: i64, resistance: i64, pub fn parse(object: std.json.ObjectMap, attack: []const u8, damage: []const u8, resistance: []const u8) !ElementalStats { return ElementalStats{ .attack = try json_utils.getIntegerRequired(object, attack), .damage = try json_utils.getIntegerRequired(object, damage), .resistance = try json_utils.getIntegerRequired(object, resistance), }; } }; const TaskMasterTask = struct { target: Store.Id, type: Task.Type, progress: u64, total: u64, fn parse(store: *Store, obj: std.json.ObjectMap) !?TaskMasterTask { const task_target = try json_utils.getStringRequired(obj, "task"); if (task_target.len == 0) { return null; } const task_type = try json_utils.getStringRequired(obj, "task_type"); const progress = try json_utils.getPositiveIntegerRequired(obj, "task_progress"); const total = try json_utils.getPositiveIntegerRequired(obj, "task_total"); return TaskMasterTask{ .target = try store.tasks.getOrReserveId(task_target), .type = Task.Type.fromString(task_type) orelse return error.InvalidTaskType, .total = total, .progress = progress, }; } }; pub const ElementalStatsArray = std.EnumArray(Element, ElementalStats); pub const Skills = std.EnumArray(Skill, SkillStats); pub const max_name_size = 12; pub const Name = std.BoundedArray(u8, max_name_size); pub const max_account_size = 32; pub const Account = std.BoundedArray(u8, max_account_size); pub const Inventory = SimpleItem.BoundedArray(20); name: Name, account: Account, skin: Skin, gold: u64, skills: Skills, elemental_stats: ElementalStatsArray, equipment: Equipment, task: ?TaskMasterTask, inventory_max_items: u64, inventory: Inventory, pub fn parse(store: *Store, obj: std.json.ObjectMap) !Character { const name = try json_utils.getStringRequired(obj, "name"); if (name.len == 0) { return error.InvalidName; } const inventory = try json_utils.getArrayRequired(obj, "inventory"); const account = try json_utils.getStringRequired(obj, "name"); const skin = try json_utils.getStringRequired(obj, "skin"); const gold = try json_utils.getPositiveIntegerRequired(obj, "gold"); const inventory_max_items = try json_utils.getPositiveIntegerRequired(obj, "inventory_max_items"); const skill_stats = Skills.init(.{ .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"), .alchemy = try SkillStats.parse(obj, "alchemy_level", "alchemy_xp", "alchemy_max_xp"), }); const elemental_stats = ElementalStatsArray.init(.{ .water = try ElementalStats.parse(obj, "attack_water", "dmg_water", "res_water"), .fire = try ElementalStats.parse(obj, "attack_fire", "dmg_fire", "res_fire"), .earth = try ElementalStats.parse(obj, "attack_earth", "dmg_earth", "res_earth"), .air = try ElementalStats.parse(obj, "attack_air", "dmg_air", "res_air"), }); return Character{ .name = try Name.fromSlice(name), .account = try Account.fromSlice(account), .skin = Skin.fromString(skin) orelse return error.SkinNotFound, .gold = gold, .skills = skill_stats, .elemental_stats = elemental_stats, .equipment = try Equipment.parse(store, obj), .task = try TaskMasterTask.parse(store, obj), .inventory_max_items = inventory_max_items, .inventory = try Inventory.parse(store, inventory) }; } pub fn parseAndAppend(store: *Store, obj: std.json.ObjectMap) !Store.Id { return store.characters.appendOrUpdate(try parse(store, obj)); }