add creation of sub goals through requirements
This commit is contained in:
parent
df56eceab6
commit
87c09f1e27
@ -23,6 +23,7 @@ pub const Equipment = @import("./schemas/equipment.zig");
|
|||||||
pub const Craft = @import("./schemas/craft.zig");
|
pub const Craft = @import("./schemas/craft.zig");
|
||||||
pub const Resource = @import("./schemas/resource.zig");
|
pub const Resource = @import("./schemas/resource.zig");
|
||||||
pub const MoveResult = @import("./schemas/move_result.zig");
|
pub const MoveResult = @import("./schemas/move_result.zig");
|
||||||
|
pub const SimpleItem = @import("./schemas/simple_item.zig");
|
||||||
const SkillUsageResult = @import("./schemas/skill_usage_result.zig");
|
const SkillUsageResult = @import("./schemas/skill_usage_result.zig");
|
||||||
pub const GatherResult = SkillUsageResult;
|
pub const GatherResult = SkillUsageResult;
|
||||||
pub const CraftResult = SkillUsageResult;
|
pub const CraftResult = SkillUsageResult;
|
||||||
|
@ -30,10 +30,10 @@ pub fn BoundedArray(comptime slot_count: u32) type {
|
|||||||
const Items = std.BoundedArray(SimpleItem, slot_count);
|
const Items = std.BoundedArray(SimpleItem, slot_count);
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
items: Items,
|
items: Items = .{ .len = 0 },
|
||||||
|
|
||||||
pub fn init() @This() {
|
pub fn init() @This() {
|
||||||
return @This(){ .items = Items.init(0) catch unreachable };
|
return @This(){};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(store: *Store, slots_array: std.json.Array) !@This() {
|
pub fn parse(store: *Store, slots_array: std.json.Array) !@This() {
|
||||||
@ -89,6 +89,16 @@ pub fn BoundedArray(comptime slot_count: u32) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addAssumeCapacity(self: *@This(), id: Store.Id, quantity: u64) void {
|
||||||
|
if (quantity == 0) return;
|
||||||
|
|
||||||
|
if (self.findSlot(id)) |slot| {
|
||||||
|
slot.quantity += quantity;
|
||||||
|
} else {
|
||||||
|
self.items.appendAssumeCapacity(SimpleItem.init(id, quantity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addSlice(self: *@This(), items: []const SimpleItem) void {
|
pub fn addSlice(self: *@This(), items: []const SimpleItem) void {
|
||||||
for (items) |item| {
|
for (items) |item| {
|
||||||
self.add(item.id, item.quantity);
|
self.add(item.id, item.quantity);
|
||||||
@ -117,7 +127,7 @@ pub fn BoundedArray(comptime slot_count: u32) type {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice(self: *@This()) []SimpleItem {
|
pub fn slice(self: @This()) []const SimpleItem {
|
||||||
return self.items.slice();
|
return self.items.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ pub fn main() !void {
|
|||||||
_ = try artificer.appendGoal(Artificer.Goal{
|
_ = try artificer.appendGoal(Artificer.Goal{
|
||||||
.craft = .{
|
.craft = .{
|
||||||
.item = store.items.getId("copper").?,
|
.item = store.items.getId("copper").?,
|
||||||
.quantity = 3
|
.quantity = 2
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,12 +1,20 @@
|
|||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
const Api = @import("artifacts-api");
|
const Api = @import("artifacts-api");
|
||||||
const Artificer = @import("./root.zig");
|
const Artificer = @import("./root.zig");
|
||||||
|
const Requirements = Artificer.Requirements;
|
||||||
|
|
||||||
const Goal = @This();
|
const Goal = @This();
|
||||||
|
|
||||||
item: Api.Store.Id,
|
item: Api.Store.Id,
|
||||||
quantity: u64,
|
quantity: u64,
|
||||||
|
|
||||||
|
fn getCraftMultiples(self: Goal, craft: Api.Craft) u64 {
|
||||||
|
return @intFromFloat(@ceil(
|
||||||
|
@as(f32, @floatFromInt(self.quantity)) /
|
||||||
|
@as(f32, @floatFromInt(craft.quantity))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) !void {
|
pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) !void {
|
||||||
const store = artificer.server.store;
|
const store = artificer.server.store;
|
||||||
const character = store.characters.get(artificer.character).?;
|
const character = store.characters.get(artificer.character).?;
|
||||||
@ -24,18 +32,6 @@ pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) !void
|
|||||||
return error.SkillTooLow;
|
return error.SkillTooLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
const craft_multiples: u64 = @intFromFloat(@ceil(
|
|
||||||
@as(f32, @floatFromInt(self.quantity)) /
|
|
||||||
@as(f32, @floatFromInt(craft.quantity))
|
|
||||||
));
|
|
||||||
|
|
||||||
for (craft.items.items.slice()) |craft_item| {
|
|
||||||
const inventory_item_quantity = character.inventory.getQuantity(craft_item.id);
|
|
||||||
if (inventory_item_quantity < craft_item.quantity * craft_multiples) {
|
|
||||||
return error.NotEnoughItems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const workshop_position = artificer.findNearestWorkstation(craft.skill).?;
|
const workshop_position = artificer.findNearestWorkstation(craft.skill).?;
|
||||||
if (!workshop_position.eql(character.position)) {
|
if (!workshop_position.eql(character.position)) {
|
||||||
artificer.queued_actions.appendAssumeCapacity(.{
|
artificer.queued_actions.appendAssumeCapacity(.{
|
||||||
@ -51,6 +47,21 @@ pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) !void
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn requirements(self: Goal, artificer: *Artificer) Artificer.Requirements {
|
||||||
|
var reqs: Artificer.Requirements = .{};
|
||||||
|
|
||||||
|
const store = artificer.server.store;
|
||||||
|
const item = store.items.get(self.item).?;
|
||||||
|
const craft = item.craft.?;
|
||||||
|
const craft_multiples = self.getCraftMultiples(craft);
|
||||||
|
|
||||||
|
for (craft.items.slice()) |craft_item| {
|
||||||
|
reqs.items.addAssumeCapacity(craft_item.id, craft_item.quantity * craft_multiples);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reqs;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
||||||
_ = goal_id;
|
_ = goal_id;
|
||||||
|
|
||||||
|
@ -34,6 +34,15 @@ pub fn tick(self: *Goal, goal_id: Artificer.GoalId, artificer: *Artificer) void
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn requirements(self: Goal, artificer: *Artificer) Artificer.Requirements {
|
||||||
|
_ = self;
|
||||||
|
_ = artificer;
|
||||||
|
|
||||||
|
const reqs: Artificer.Requirements = .{};
|
||||||
|
// TODO: add skill requirement
|
||||||
|
return reqs;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
||||||
_ = goal_id;
|
_ = goal_id;
|
||||||
|
|
||||||
|
64
lib/root.zig
64
lib/root.zig
@ -16,7 +16,11 @@ pub const GoalId = packed struct {
|
|||||||
const Index = u11;
|
const Index = u11;
|
||||||
|
|
||||||
generation: Generation,
|
generation: Generation,
|
||||||
index: Index
|
index: Index,
|
||||||
|
|
||||||
|
pub fn eql(self: GoalId, other: GoalId) bool {
|
||||||
|
return self.index == other.index and self.generation == other.generation;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const max_goals = std.math.maxInt(GoalId.Index);
|
const max_goals = std.math.maxInt(GoalId.Index);
|
||||||
@ -35,6 +39,13 @@ pub const Goal = union(enum) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn requirements(self: Goal, artificer: *Artificer) Requirements {
|
||||||
|
return switch (self) {
|
||||||
|
.gather => |gather| gather.requirements(artificer),
|
||||||
|
.craft => |craft| craft.requirements(artificer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
pub fn onActionCompleted(self: *Goal, goal_id: Artificer.GoalId, result: Artificer.ActionResult) void {
|
||||||
switch (self.*) {
|
switch (self.*) {
|
||||||
.gather => |*gather| gather.onActionCompleted(goal_id, result),
|
.gather => |*gather| gather.onActionCompleted(goal_id, result),
|
||||||
@ -45,6 +56,7 @@ pub const Goal = union(enum) {
|
|||||||
|
|
||||||
const GoalSlot = struct {
|
const GoalSlot = struct {
|
||||||
generation: GoalId.Generation = 0,
|
generation: GoalId.Generation = 0,
|
||||||
|
parent_goal: ?GoalId = null,
|
||||||
goal: ?Goal = null,
|
goal: ?Goal = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,6 +80,16 @@ const ActionSlot = struct {
|
|||||||
action: Action,
|
action: Action,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
items: Items = .{}
|
||||||
|
};
|
||||||
|
|
||||||
const QueuedActions = std.ArrayListUnmanaged(ActionSlot);
|
const QueuedActions = std.ArrayListUnmanaged(ActionSlot);
|
||||||
|
|
||||||
server: *Api.Server,
|
server: *Api.Server,
|
||||||
@ -256,8 +278,19 @@ fn getGoalCount(self: *Artificer) u32 {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hasSubGoals(self: *Artificer, goal_id: GoalId) bool {
|
||||||
|
for (self.goal_slots) |goal_slot| {
|
||||||
|
if (goal_slot.goal != null and goal_slot.parent_goal != null and goal_slot.parent_goal.?.eql(goal_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tick(self: *Artificer) !void {
|
pub fn tick(self: *Artificer) !void {
|
||||||
const store = self.server.store;
|
const store = self.server.store;
|
||||||
|
const character = store.characters.get(self.character).?;
|
||||||
|
|
||||||
if (self.queued_actions.items.len > 0) {
|
if (self.queued_actions.items.len > 0) {
|
||||||
const expires_in = self.timeUntilCooldownExpires();
|
const expires_in = self.timeUntilCooldownExpires();
|
||||||
@ -265,7 +298,6 @@ pub fn tick(self: *Artificer) !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const character = store.characters.get(self.character).?;
|
|
||||||
const action_slot = self.queued_actions.orderedRemove(0);
|
const action_slot = self.queued_actions.orderedRemove(0);
|
||||||
const action_result = switch (action_slot.action) {
|
const action_result = switch (action_slot.action) {
|
||||||
.move => |position| ActionResult{
|
.move => |position| ActionResult{
|
||||||
@ -297,6 +329,34 @@ pub fn tick(self: *Artificer) !void {
|
|||||||
.generation = goal_slot.generation
|
.generation = goal_slot.generation
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (self.hasSubGoals(goal_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reqs = goal.requirements(self);
|
||||||
|
for (reqs.items.slice()) |req_item| {
|
||||||
|
const inventory_quantity = character.inventory.getQuantity(req_item.id);
|
||||||
|
if (inventory_quantity < req_item.quantity) {
|
||||||
|
if (self.findBestResourceWithItem(req_item.id) != null) {
|
||||||
|
const subgoal_id = try self.appendGoal(.{
|
||||||
|
.gather = .{
|
||||||
|
.item = req_item.id,
|
||||||
|
.quantity = req_item.quantity - inventory_quantity,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const subgoal = self.getGoal(subgoal_id).?;
|
||||||
|
subgoal.parent_goal = goal_id;
|
||||||
|
} else {
|
||||||
|
@panic("Not all requirements were handled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.hasSubGoals(goal_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try goal.tick(goal_id, self);
|
try goal.tick(goal_id, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user