add equip goal
This commit is contained in:
parent
87c09f1e27
commit
cdd11147d3
@ -222,6 +222,7 @@ const EquipErrorDef = ErrorDefinitionList(&[_]ErrorDefinition{
|
||||
NotFound,
|
||||
CharacterItemAlreadyEquiped,
|
||||
CharacterLocked,
|
||||
CharacterSlotEquipmentError,
|
||||
CharacterNotSkillLevelRequired,
|
||||
CharacterNotFound,
|
||||
CharacterInCooldown,
|
||||
|
@ -24,6 +24,8 @@ pub const Craft = @import("./schemas/craft.zig");
|
||||
pub const Resource = @import("./schemas/resource.zig");
|
||||
pub const MoveResult = @import("./schemas/move_result.zig");
|
||||
pub const SimpleItem = @import("./schemas/simple_item.zig");
|
||||
pub const EquipResult = @import("./schemas/equip_result.zig");
|
||||
pub const UnequipResult = EquipResult;
|
||||
const SkillUsageResult = @import("./schemas/skill_usage_result.zig");
|
||||
pub const GatherResult = SkillUsageResult;
|
||||
pub const CraftResult = SkillUsageResult;
|
||||
|
37
api/schemas/equip_result.zig
Normal file
37
api/schemas/equip_result.zig
Normal file
@ -0,0 +1,37 @@
|
||||
// zig fmt: off
|
||||
const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const Character = @import("./character.zig");
|
||||
const Cooldown = @import("./cooldown.zig");
|
||||
const Item = @import("./item.zig");
|
||||
|
||||
const EquipResult = @This();
|
||||
|
||||
pub const Slot = Character.Equipment.SlotId;
|
||||
|
||||
cooldown: Cooldown,
|
||||
slot: Slot,
|
||||
item: Item,
|
||||
character: Character,
|
||||
|
||||
fn parse(store: *Store, obj: std.json.ObjectMap) !EquipResult {
|
||||
const cooldown = json_utils.getObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||
const item = json_utils.getObject(obj, "item") orelse return error.MissingProperty;
|
||||
const character = json_utils.getObject(obj, "character") orelse return error.MissingProperty;
|
||||
const slot = try json_utils.getStringRequired(obj, "slot");
|
||||
|
||||
return EquipResult{
|
||||
.character = try Character.parse(store, character),
|
||||
.cooldown = try Cooldown.parse(store, cooldown),
|
||||
.item = try Item.parse(store, item),
|
||||
.slot = Slot.fromString(slot) orelse return error.InvalidSlot
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseAndUpdate(store: *Store, obj: std.json.ObjectMap) !EquipResult {
|
||||
const result = try parse(store, obj);
|
||||
_ = try store.characters.appendOrUpdate(result.character);
|
||||
_ = try store.items.appendOrUpdate(result.item);
|
||||
return result;
|
||||
}
|
@ -3,27 +3,37 @@ const std = @import("std");
|
||||
const json_utils = @import("../json_utils.zig");
|
||||
const Store = @import("../store.zig");
|
||||
const Item = @import("./item.zig");
|
||||
const EnumStringUtils = @import("../enum_string_utils.zig").EnumStringUtils;
|
||||
|
||||
const Equipment = @This();
|
||||
|
||||
pub const UtilitySlot = struct {
|
||||
id: Store.Id,
|
||||
quantity: u64,
|
||||
pub const Slot = struct {
|
||||
item: ?Store.Id = null,
|
||||
quantity: u64 = 0,
|
||||
|
||||
fn parse(store: *Store, obj: std.json.ObjectMap, name: []const u8, quantity: []const u8) !?UtilitySlot {
|
||||
fn parse(store: *Store, obj: std.json.ObjectMap, name: []const u8) !Slot {
|
||||
const item_code = try json_utils.getStringRequired(obj, name);
|
||||
if (item_code.len == 0) {
|
||||
return null;
|
||||
return Slot{};
|
||||
}
|
||||
|
||||
return UtilitySlot{
|
||||
.id = try store.items.getOrReserveId(item_code),
|
||||
.quantity = try json_utils.getPositiveIntegerRequired(obj, quantity),
|
||||
return Slot{
|
||||
.item = try store.items.getOrReserveId(item_code),
|
||||
.quantity = 1
|
||||
};
|
||||
}
|
||||
|
||||
fn parseWithQuantity(store: *Store, obj: std.json.ObjectMap, name: []const u8, quantity: []const u8) !Slot {
|
||||
var slot = try Slot.parse(store, obj, name);
|
||||
if (slot.item != null) {
|
||||
slot.quantity = try json_utils.getPositiveIntegerRequired(obj, quantity);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Slot = enum {
|
||||
pub const SlotId = enum {
|
||||
weapon,
|
||||
shield,
|
||||
helmet,
|
||||
@ -35,92 +45,56 @@ pub const Slot = enum {
|
||||
amulet,
|
||||
artifact1,
|
||||
artifact2,
|
||||
artifact3,
|
||||
utility1,
|
||||
utility2,
|
||||
|
||||
fn name(self: Slot) []const u8 {
|
||||
return switch (self) {
|
||||
.weapon => "weapon",
|
||||
.shield => "shield",
|
||||
.helmet => "helmet",
|
||||
.body_armor => "body_armor",
|
||||
.leg_armor => "leg_armor",
|
||||
.boots => "boots",
|
||||
.ring1 => "ring1",
|
||||
.ring2 => "ring2",
|
||||
.amulet => "amulet",
|
||||
.artifact1 => "artifact1",
|
||||
.artifact2 => "artifact2",
|
||||
.utility1 => "utility1",
|
||||
.utility2 => "utility2",
|
||||
};
|
||||
const Utils = EnumStringUtils(SlotId, .{
|
||||
.{ "weapon" , SlotId.weapon },
|
||||
.{ "shield" , SlotId.shield },
|
||||
.{ "helmet" , SlotId.helmet },
|
||||
.{ "body_armor", SlotId.body_armor },
|
||||
.{ "leg_armor" , SlotId.leg_armor },
|
||||
.{ "boots" , SlotId.boots },
|
||||
.{ "ring1" , SlotId.ring1 },
|
||||
.{ "ring2" , SlotId.ring2 },
|
||||
.{ "amulet" , SlotId.amulet },
|
||||
.{ "artifact1" , SlotId.artifact1 },
|
||||
.{ "artifact2" , SlotId.artifact2 },
|
||||
.{ "artifact3" , SlotId.artifact3 },
|
||||
.{ "utility1" , SlotId.utility1 },
|
||||
.{ "utility2" , SlotId.utility2 },
|
||||
});
|
||||
|
||||
pub const toString = Utils.toString;
|
||||
pub const fromString = Utils.fromString;
|
||||
|
||||
pub fn canHoldManyItems(self: SlotId) bool {
|
||||
return self == .utility1 or self == .utility2;
|
||||
}
|
||||
};
|
||||
|
||||
weapon: ?Store.Id,
|
||||
shield: ?Store.Id,
|
||||
helmet: ?Store.Id,
|
||||
body_armor: ?Store.Id,
|
||||
leg_armor: ?Store.Id,
|
||||
boots: ?Store.Id,
|
||||
pub const Slots = std.EnumArray(SlotId, Slot);
|
||||
|
||||
ring1: ?Store.Id,
|
||||
ring2: ?Store.Id,
|
||||
amulet: ?Store.Id,
|
||||
|
||||
artifact1: ?Store.Id,
|
||||
artifact2: ?Store.Id,
|
||||
artifact3: ?Store.Id,
|
||||
|
||||
utility1: ?UtilitySlot,
|
||||
utility2: ?UtilitySlot,
|
||||
slots: Slots,
|
||||
|
||||
pub fn parse(store: *Store, obj: std.json.ObjectMap) !Equipment {
|
||||
const weapon = try json_utils.getStringRequired(obj, "weapon_slot");
|
||||
const shield = try json_utils.getStringRequired(obj, "shield_slot");
|
||||
const helmet = try json_utils.getStringRequired(obj, "helmet_slot");
|
||||
const body_armor = try json_utils.getStringRequired(obj, "body_armor_slot");
|
||||
const leg_armor = try json_utils.getStringRequired(obj, "leg_armor_slot");
|
||||
const boots = try json_utils.getStringRequired(obj, "boots_slot");
|
||||
const ring1 = try json_utils.getStringRequired(obj, "ring1_slot");
|
||||
const ring2 = try json_utils.getStringRequired(obj, "ring2_slot");
|
||||
const amulet = try json_utils.getStringRequired(obj, "amulet_slot");
|
||||
const artifact1 = try json_utils.getStringRequired(obj, "artifact1_slot");
|
||||
const artifact2 = try json_utils.getStringRequired(obj, "artifact2_slot");
|
||||
const artifact3 = try json_utils.getStringRequired(obj, "artifact3_slot");
|
||||
|
||||
return Equipment{
|
||||
.weapon = try store.items.getOrReserveId(weapon),
|
||||
.shield = try store.items.getOrReserveId(shield),
|
||||
.helmet = try store.items.getOrReserveId(helmet),
|
||||
.body_armor = try store.items.getOrReserveId(body_armor),
|
||||
.leg_armor = try store.items.getOrReserveId(leg_armor),
|
||||
.boots = try store.items.getOrReserveId(boots),
|
||||
.ring1 = try store.items.getOrReserveId(ring1),
|
||||
.ring2 = try store.items.getOrReserveId(ring2),
|
||||
.amulet = try store.items.getOrReserveId(amulet),
|
||||
.artifact1 = try store.items.getOrReserveId(artifact1),
|
||||
.artifact2 = try store.items.getOrReserveId(artifact2),
|
||||
.artifact3 = try store.items.getOrReserveId(artifact3),
|
||||
.utility1 = try UtilitySlot.parse(store, obj, "utility1_slot", "utility1_slot_quantity"),
|
||||
.utility2 = try UtilitySlot.parse(store, obj, "utility2_slot", "utility2_slot_quantity"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getSlot(self: Equipment, slot: Slot) ?Store.Id {
|
||||
return switch (slot) {
|
||||
.weapon => self.weapon,
|
||||
.shield => self.shield,
|
||||
.helmet => self.helmet,
|
||||
.body_armor => self.body_armor,
|
||||
.leg_armor => self.leg_armor,
|
||||
.boots => self.boots,
|
||||
.ring1 => self.ring1,
|
||||
.ring2 => self.ring2,
|
||||
.amulet => self.amulet,
|
||||
.artifact1 => self.artifact1,
|
||||
.artifact2 => self.artifact2,
|
||||
.utility1 => if (self.utility1) |util| util.id else null,
|
||||
.utility2 => if (self.utility2) |util| util.id else null,
|
||||
.slots = Slots.init(.{
|
||||
.weapon = try Slot.parse(store, obj, "weapon_slot"),
|
||||
.shield = try Slot.parse(store, obj, "shield_slot"),
|
||||
.helmet = try Slot.parse(store, obj, "helmet_slot"),
|
||||
.body_armor = try Slot.parse(store, obj, "body_armor_slot"),
|
||||
.leg_armor = try Slot.parse(store, obj, "leg_armor_slot"),
|
||||
.boots = try Slot.parse(store, obj, "boots_slot"),
|
||||
.ring1 = try Slot.parse(store, obj, "ring1_slot"),
|
||||
.ring2 = try Slot.parse(store, obj, "ring2_slot"),
|
||||
.amulet = try Slot.parse(store, obj, "amulet_slot"),
|
||||
.artifact1 = try Slot.parse(store, obj, "artifact1_slot"),
|
||||
.artifact2 = try Slot.parse(store, obj, "artifact2_slot"),
|
||||
.artifact3 = try Slot.parse(store, obj, "artifact3_slot"),
|
||||
.utility1 = try Slot.parseWithQuantity(store, obj, "utility1_slot", "utility1_slot_quantity"),
|
||||
.utility2 = try Slot.parseWithQuantity(store, obj, "utility2_slot", "utility2_slot_quantity"),
|
||||
})
|
||||
};
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ const AuthToken = Root.AuthToken;
|
||||
const log = std.log.scoped(.api);
|
||||
const ServerURL = std.BoundedArray(u8, 256);
|
||||
|
||||
const Equipment = @import("./schemas/equipment.zig");
|
||||
const Item = @import("./schemas/item.zig");
|
||||
const Craft = @import("./schemas/craft.zig");
|
||||
const Status = @import("./schemas/status.zig");
|
||||
@ -25,6 +26,8 @@ const Map = @import("./schemas/map.zig");
|
||||
const GEOrder = @import("./schemas/ge_order.zig");
|
||||
const MoveResult = @import("./schemas/move_result.zig");
|
||||
const SkillUsageResult = @import("./schemas/skill_usage_result.zig");
|
||||
const EquipResult = @import("./schemas/equip_result.zig");
|
||||
const UnequipResult = EquipResult;
|
||||
pub const GatherResult = SkillUsageResult;
|
||||
pub const CraftResult = SkillUsageResult;
|
||||
const Image = Store.Image;
|
||||
@ -502,32 +505,50 @@ fn fetchArray(
|
||||
return result orelse return FetchError.RequestFailed;
|
||||
}
|
||||
|
||||
fn prefetch(self: *Server, allocator: std.mem.Allocator) !void {
|
||||
pub const PrefetchOptions = struct {
|
||||
resources: bool = true,
|
||||
maps: bool = true,
|
||||
monsters: bool = true,
|
||||
items: bool = true,
|
||||
images: bool = false,
|
||||
};
|
||||
|
||||
pub fn prefetch(self: *Server, allocator: std.mem.Allocator, opts: PrefetchOptions) !void {
|
||||
// TODO: Create a version of `getResources`, `getMonsters`, `getItems`, etc..
|
||||
// which don't need an allocator to be passed.
|
||||
// This is for cases when you only care that everything will be saved into the store.
|
||||
|
||||
if (opts.resources) {
|
||||
const resources = try self.getResources(allocator, .{});
|
||||
defer resources.deinit();
|
||||
}
|
||||
|
||||
if (opts.maps) {
|
||||
const maps: std.ArrayList(Map) = try self.getMaps(allocator, .{});
|
||||
defer maps.deinit();
|
||||
}
|
||||
|
||||
if (opts.monsters) {
|
||||
const monsters = try self.getMonsters(allocator, .{});
|
||||
defer monsters.deinit();
|
||||
}
|
||||
|
||||
if (opts.items) {
|
||||
const items = try self.getItems(allocator, .{});
|
||||
defer items.deinit();
|
||||
}
|
||||
|
||||
for (maps.items) |map| {
|
||||
if (opts.images) {
|
||||
for (self.store.maps.items) |map| {
|
||||
const skin: []const u8 = map.skin.slice();
|
||||
if (self.store.images.getId(.map, skin) == null) {
|
||||
_ = try self.getImage(.map, skin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prefetchCached(self: *Server, allocator: std.mem.Allocator, absolute_cache_path: []const u8) !void {
|
||||
pub fn prefetchCached(self: *Server, allocator: std.mem.Allocator, absolute_cache_path: []const u8, opts: PrefetchOptions) !void {
|
||||
const status: Status = try self.getStatus();
|
||||
const version = status.version.slice();
|
||||
|
||||
@ -539,7 +560,7 @@ pub fn prefetchCached(self: *Server, allocator: std.mem.Allocator, absolute_cach
|
||||
} else |_| {}
|
||||
} else |_| {}
|
||||
|
||||
try self.prefetch(allocator);
|
||||
try self.prefetch(allocator, opts);
|
||||
|
||||
const file = try std.fs.createFileAbsolute(absolute_cache_path, .{});
|
||||
defer file.close();
|
||||
@ -1046,6 +1067,66 @@ pub fn craft(self: *Server, character: []const u8, item: []const u8, quantity: u
|
||||
);
|
||||
}
|
||||
|
||||
pub fn equip(self: *Server, character: []const u8, slot: Equipment.SlotId, item: []const u8, quantity: u64) errors.EquipError!EquipResult {
|
||||
const path_buff_size = comptime blk: {
|
||||
var count = 0;
|
||||
count += 4; // "/my/"
|
||||
count += Character.max_name_size;
|
||||
count += 13; // "/action/equip"
|
||||
break :blk count;
|
||||
};
|
||||
|
||||
var path_buff: [path_buff_size]u8 = undefined;
|
||||
const path = std.fmt.bufPrint(
|
||||
&path_buff,
|
||||
"/my/{s}/action/equip",.{ character }
|
||||
) catch return FetchError.InvalidPayload;
|
||||
|
||||
var payload_buff: [256]u8 = undefined;
|
||||
const payload = std.fmt.bufPrint(
|
||||
&payload_buff,
|
||||
"{{ \"slot\":\"{s}\", \"code\":\"{s}\", \"quantity\":{} }}", .{ slot.toString(), item, quantity }
|
||||
) catch return FetchError.InvalidPayload;
|
||||
|
||||
return try self.fetchObject(
|
||||
errors.EquipError,
|
||||
errors.parseEquipError,
|
||||
EquipResult,
|
||||
EquipResult.parseAndUpdate,
|
||||
.{ .method = .POST, .path = path, .payload = payload, .ratelimit = .actions }
|
||||
);
|
||||
}
|
||||
|
||||
pub fn unequip(self: *Server, character: []const u8, slot: Equipment.SlotId, quantity: u64) errors.UnequipError!UnequipResult {
|
||||
const path_buff_size = comptime blk: {
|
||||
var count = 0;
|
||||
count += 4; // "/my/"
|
||||
count += Character.max_name_size;
|
||||
count += 15; // "/action/unequip"
|
||||
break :blk count;
|
||||
};
|
||||
|
||||
var path_buff: [path_buff_size]u8 = undefined;
|
||||
const path = std.fmt.bufPrint(
|
||||
&path_buff,
|
||||
"/my/{s}/action/unequip",.{ character }
|
||||
) catch return FetchError.InvalidPayload;
|
||||
|
||||
var payload_buff: [256]u8 = undefined;
|
||||
const payload = std.fmt.bufPrint(
|
||||
&payload_buff,
|
||||
"{{ \"slot\":\"{s}\", \"quantity\":{} }}", .{ slot.toString(), quantity }
|
||||
) catch return FetchError.InvalidPayload;
|
||||
|
||||
return try self.fetchObject(
|
||||
errors.UnequipError,
|
||||
errors.parseUnequipError,
|
||||
UnequipResult,
|
||||
UnequipResult.parseAndUpdate,
|
||||
.{ .method = .POST, .path = path, .payload = payload, .ratelimit = .actions }
|
||||
);
|
||||
}
|
||||
|
||||
// https://api.artifactsmmo.com/docs/#/operations/generate_token_token_post
|
||||
pub fn generateToken(self: *Server, username: []const u8, password: []const u8) !AuthToken {
|
||||
const base64_encoder = std.base64.standard.Encoder;
|
||||
|
18
cli/main.zig
18
cli/main.zig
@ -50,11 +50,10 @@ pub fn main() !void {
|
||||
const cwd_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||
defer allocator.free(cwd_path);
|
||||
|
||||
const cache_path = try std.fs.path.resolve(allocator, &.{ cwd_path, "./api-store.bin" });
|
||||
const cache_path = try std.fs.path.resolve(allocator, &.{ cwd_path, "./api-store-cli.bin" });
|
||||
defer allocator.free(cache_path);
|
||||
|
||||
// TODO: Don't prefetch images
|
||||
try server.prefetchCached(allocator, cache_path);
|
||||
try server.prefetchCached(allocator, cache_path, .{ .images = false });
|
||||
}
|
||||
|
||||
const character_id = (try server.getCharacter("Blondie")).?;
|
||||
@ -62,17 +61,10 @@ pub fn main() !void {
|
||||
var artificer = try Artificer.init(allocator, &server, character_id);
|
||||
defer artificer.deinit(allocator);
|
||||
|
||||
// _ = try artificer.appendGoal(Artificer.Goal{
|
||||
// .gather = .{
|
||||
// .item = store.items.getId("sap").?,
|
||||
// .quantity = 1
|
||||
// }
|
||||
// });
|
||||
|
||||
_ = try artificer.appendGoal(Artificer.Goal{
|
||||
.craft = .{
|
||||
.item = store.items.getId("copper").?,
|
||||
.quantity = 2
|
||||
.equip = .{
|
||||
.slot = .weapon,
|
||||
.item = store.items.getId("copper_dagger").?
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -102,10 +102,10 @@ pub fn main() anyerror!void {
|
||||
const cwd_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||
defer allocator.free(cwd_path);
|
||||
|
||||
const cache_path = try std.fs.path.resolve(allocator, &.{ cwd_path, "./api-store.bin" });
|
||||
const cache_path = try std.fs.path.resolve(allocator, &.{ cwd_path, "./api-store-gui.bin" });
|
||||
defer allocator.free(cache_path);
|
||||
|
||||
try server.prefetchCached(allocator, cache_path);
|
||||
try server.prefetchCached(allocator, cache_path, .{ .images = true });
|
||||
}
|
||||
|
||||
rl.initWindow(800, 450, "Artificer");
|
||||
|
61
lib/equip_goal.zig
Normal file
61
lib/equip_goal.zig
Normal file
@ -0,0 +1,61 @@
|
||||
// zig fmt: off
|
||||
const std = @import("std");
|
||||
const Api = @import("artifacts-api");
|
||||
const Artificer = @import("./root.zig");
|
||||
|
||||
const Goal = @This();
|
||||
|
||||
slot: Api.Character.Equipment.SlotId,
|
||||
item: Api.Store.Id,
|
||||
quantity: u64 = 1,
|
||||
|
||||
pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) void {
|
||||
const store = artificer.server.store;
|
||||
const character = store.characters.get(artificer.character).?;
|
||||
|
||||
const equipment_slot = character.equipment.slots.get(self.slot);
|
||||
if (equipment_slot.item) |equiped_item|{
|
||||
if (equiped_item == self.item and !self.slot.canHoldManyItems()) {
|
||||
artificer.removeGoal(goal_id);
|
||||
} else {
|
||||
artificer.queued_actions.appendAssumeCapacity(.{
|
||||
.goal = goal_id,
|
||||
.action = .{
|
||||
.unequip = .{
|
||||
.slot = self.slot,
|
||||
.quantity = self.quantity
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
artificer.queued_actions.appendAssumeCapacity(.{
|
||||
.goal = goal_id,
|
||||
.action = .{
|
||||
.equip = .{
|
||||
.slot = self.slot,
|
||||
.item = self.item,
|
||||
.quantity = self.quantity
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn requirements(self: Goal, artificer: *Artificer) Artificer.Requirements {
|
||||
_ = artificer;
|
||||
|
||||
var reqs: Artificer.Requirements = .{};
|
||||
reqs.items.addAssumeCapacity(self.item, self.quantity);
|
||||
|
||||
return reqs;
|
||||
}
|
||||
|
||||
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer, result: Artificer.ActionResult) void {
|
||||
_ = self;
|
||||
|
||||
if (result == .equip) {
|
||||
artificer.removeGoal(goal_id);
|
||||
}
|
||||
}
|
56
lib/root.zig
56
lib/root.zig
@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
const GatherGoal = @import("gather_goal.zig");
|
||||
const CraftGoal = @import("craft_goal.zig");
|
||||
const EquipGoal = @import("equip_goal.zig");
|
||||
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.artificer);
|
||||
@ -31,11 +32,13 @@ const server_down_retry_interval = 5; // minutes
|
||||
pub const Goal = union(enum) {
|
||||
gather: GatherGoal,
|
||||
craft: CraftGoal,
|
||||
equip: EquipGoal,
|
||||
|
||||
pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) !void {
|
||||
switch (self.*) {
|
||||
.gather => |*gather| gather.tick(goal_id, artificer),
|
||||
.craft => |*craft| try craft.tick(goal_id, artificer),
|
||||
.equip => |*equip| equip.tick(goal_id, artificer),
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,13 +46,15 @@ pub const Goal = union(enum) {
|
||||
return switch (self) {
|
||||
.gather => |gather| gather.requirements(artificer),
|
||||
.craft => |craft| craft.requirements(artificer),
|
||||
.equip => |equip| equip.requirements(artificer),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
||||
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer, result: Artificer.ActionResult) void {
|
||||
switch (self.*) {
|
||||
.gather => |*gather| gather.onActionCompleted(goal_id, result),
|
||||
.craft => |*craft| craft.onActionCompleted(goal_id, result),
|
||||
.equip => |*equip| equip.onActionCompleted(goal_id, artificer, result),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -66,13 +71,24 @@ pub const Action = union(enum) {
|
||||
craft: struct {
|
||||
item: Api.Store.Id,
|
||||
quantity: u64
|
||||
}
|
||||
},
|
||||
unequip: struct {
|
||||
slot: Api.Equipment.SlotId,
|
||||
quantity: u64
|
||||
},
|
||||
equip: struct {
|
||||
slot: Api.Equipment.SlotId,
|
||||
item: Api.Store.Id,
|
||||
quantity: u64
|
||||
},
|
||||
};
|
||||
|
||||
pub const ActionResult = union(enum) {
|
||||
move: Api.MoveResult,
|
||||
gather: Api.GatherResult,
|
||||
craft: Api.CraftResult,
|
||||
equip: Api.EquipResult,
|
||||
unequip: Api.UnequipResult,
|
||||
};
|
||||
|
||||
const ActionSlot = struct {
|
||||
@ -81,11 +97,7 @@ const ActionSlot = struct {
|
||||
};
|
||||
|
||||
pub const Requirements = struct {
|
||||
pub const Items = Api.SimpleItem.BoundedArray(blk: {
|
||||
var max: usize = 0;
|
||||
max = @max(max, Api.Craft.max_items);
|
||||
break :blk max;
|
||||
});
|
||||
pub const Items = Api.SimpleItem.BoundedArray(Api.Craft.max_items);
|
||||
|
||||
items: Items = .{}
|
||||
};
|
||||
@ -299,21 +311,28 @@ pub fn tick(self: *Artificer) !void {
|
||||
}
|
||||
|
||||
const action_slot = self.queued_actions.orderedRemove(0);
|
||||
const character_name = character.name.slice();
|
||||
const action_result = switch (action_slot.action) {
|
||||
.move => |position| ActionResult{
|
||||
.move = try self.server.move(character.name.slice(), position)
|
||||
.move = try self.server.move(character_name, position)
|
||||
},
|
||||
.gather => ActionResult{
|
||||
.gather = try self.server.gather(character.name.slice())
|
||||
.gather = try self.server.gather(character_name)
|
||||
},
|
||||
.craft => |craft| ActionResult{
|
||||
.craft = try self.server.craft(character.name.slice(), store.items.getName(craft.item).?, craft.quantity)
|
||||
.craft = try self.server.craft(character_name, store.items.getName(craft.item).?, craft.quantity)
|
||||
},
|
||||
.equip => |equip| ActionResult{
|
||||
.equip = try self.server.equip(character_name, equip.slot, store.items.getName(equip.item).?, equip.quantity)
|
||||
},
|
||||
.unequip => |unequip| ActionResult{
|
||||
.unequip = try self.server.unequip(character_name, unequip.slot, unequip.quantity)
|
||||
}
|
||||
};
|
||||
|
||||
if (self.getGoal(action_slot.goal)) |goal_slot| {
|
||||
const goal = &goal_slot.goal.?;
|
||||
goal.onActionCompleted(action_slot.goal, action_result);
|
||||
goal.onActionCompleted(action_slot.goal, self, action_result);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -337,11 +356,24 @@ pub fn tick(self: *Artificer) !void {
|
||||
for (reqs.items.slice()) |req_item| {
|
||||
const inventory_quantity = character.inventory.getQuantity(req_item.id);
|
||||
if (inventory_quantity < req_item.quantity) {
|
||||
const missing_quantity = req_item.quantity - inventory_quantity;
|
||||
const item = store.items.get(req_item.id).?;
|
||||
|
||||
if (self.findBestResourceWithItem(req_item.id) != null) {
|
||||
const subgoal_id = try self.appendGoal(.{
|
||||
.gather = .{
|
||||
.item = req_item.id,
|
||||
.quantity = req_item.quantity - inventory_quantity,
|
||||
.quantity = missing_quantity
|
||||
}
|
||||
});
|
||||
|
||||
const subgoal = self.getGoal(subgoal_id).?;
|
||||
subgoal.parent_goal = goal_id;
|
||||
} else if (item.craft != null) {
|
||||
const subgoal_id = try self.appendGoal(.{
|
||||
.craft = .{
|
||||
.item = req_item.id,
|
||||
.quantity = missing_quantity
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user