basic combat loop
This commit is contained in:
parent
69089a4fb5
commit
d7032977a2
@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
const json = std.json;
|
const json = std.json;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
@ -116,6 +117,37 @@ pub const Character = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Inventory = struct {
|
||||||
|
const slots_count = 20;
|
||||||
|
|
||||||
|
pub const InventorySlot = struct {
|
||||||
|
code: []const u8,
|
||||||
|
quantity: i64,
|
||||||
|
|
||||||
|
fn parse(allocator: Allocator, slot_obj: json.ObjectMap) !InventorySlot {
|
||||||
|
return InventorySlot{
|
||||||
|
.code = (try dupeJsonString(allocator, slot_obj, "code")) orelse return error.MissingProperty,
|
||||||
|
.quantity = getJsonInteger(slot_obj, "quantity") orelse return error.MissingProperty,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
slots: [slots_count]InventorySlot,
|
||||||
|
|
||||||
|
fn parse(allocator: Allocator, slots_array: json.Array) !Inventory {
|
||||||
|
assert(slots_array.items.len == Inventory.slots_count);
|
||||||
|
|
||||||
|
var inventory: Inventory = undefined;
|
||||||
|
|
||||||
|
for (0.., slots_array.items) |i, slot_value| {
|
||||||
|
const slot_obj = asJsonObject(slot_value) orelse return error.InvalidType;
|
||||||
|
inventory.slots[i] = try InventorySlot.parse(allocator, slot_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
|
||||||
name: []u8,
|
name: []u8,
|
||||||
@ -146,6 +178,9 @@ pub const Character = struct {
|
|||||||
|
|
||||||
equipment: Equipment,
|
equipment: Equipment,
|
||||||
|
|
||||||
|
inventory_max_items: i64,
|
||||||
|
inventory: Inventory,
|
||||||
|
|
||||||
fn parse(child_allocator: Allocator, obj: json.ObjectMap) !Character {
|
fn parse(child_allocator: Allocator, obj: json.ObjectMap) !Character {
|
||||||
var arena = try child_allocator.create(std.heap.ArenaAllocator);
|
var arena = try child_allocator.create(std.heap.ArenaAllocator);
|
||||||
errdefer child_allocator.destroy(arena);
|
errdefer child_allocator.destroy(arena);
|
||||||
@ -155,6 +190,8 @@ pub const Character = struct {
|
|||||||
|
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
const inventory = getJsonArray(obj, "inventory") orelse return error.MissingProperty;
|
||||||
|
|
||||||
return Character{
|
return Character{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.account = try dupeJsonString(allocator, obj, "account"),
|
.account = try dupeJsonString(allocator, obj, "account"),
|
||||||
@ -184,7 +221,10 @@ pub const Character = struct {
|
|||||||
.earth = try CombatStats.parse(obj, "attack_earth", "dmg_earth", "res_earth"),
|
.earth = try CombatStats.parse(obj, "attack_earth", "dmg_earth", "res_earth"),
|
||||||
.air = try CombatStats.parse(obj, "attack_air", "dmg_air", "res_air"),
|
.air = try CombatStats.parse(obj, "attack_air", "dmg_air", "res_air"),
|
||||||
|
|
||||||
.equipment = try Equipment.parse(allocator, obj)
|
.equipment = try Equipment.parse(allocator, obj),
|
||||||
|
|
||||||
|
.inventory_max_items = getJsonInteger(obj, "inventory_max_items") orelse return error.MissingProperty,
|
||||||
|
.inventory = try Inventory.parse(allocator, inventory)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +233,14 @@ pub const Character = struct {
|
|||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
child_allocator.destroy(self.arena);
|
child_allocator.destroy(self.arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getItemCount(self: *const Character) u32 {
|
||||||
|
var count: u32 = 0;
|
||||||
|
for (self.inventory.slots) |slot| {
|
||||||
|
count += @intCast(slot.quantity);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CharacterList = struct {
|
pub const CharacterList = struct {
|
||||||
@ -267,8 +315,8 @@ pub const Cooldown = struct {
|
|||||||
const reason = getJsonString(obj, "reason") orelse return error.MissingProperty;
|
const reason = getJsonString(obj, "reason") orelse return error.MissingProperty;
|
||||||
return Cooldown{
|
return Cooldown{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.total_seconds = getJsonInteger(obj, "totalSeconds") orelse return error.MissingProperty,
|
.total_seconds = getJsonInteger(obj, "total_seconds") orelse return error.MissingProperty,
|
||||||
.remaining_seconds = getJsonInteger(obj, "remainingSeconds") orelse return error.MissingProperty,
|
.remaining_seconds = getJsonInteger(obj, "remaining_seconds") orelse return error.MissingProperty,
|
||||||
.expiration = (try dupeJsonString(allocator, obj, "expiration")) orelse return error.MissingProperty,
|
.expiration = (try dupeJsonString(allocator, obj, "expiration")) orelse return error.MissingProperty,
|
||||||
.reason = Reason.parse(reason) orelse return error.UnknownReason
|
.reason = Reason.parse(reason) orelse return error.UnknownReason
|
||||||
};
|
};
|
||||||
@ -281,21 +329,73 @@ pub const Cooldown = struct {
|
|||||||
|
|
||||||
pub const FightResult = struct {
|
pub const FightResult = struct {
|
||||||
cooldown: Cooldown,
|
cooldown: Cooldown,
|
||||||
|
character: Character,
|
||||||
|
|
||||||
fn parse(allocator: Allocator, obj: json.ObjectMap) !FightResult {
|
fn parse(allocator: Allocator, obj: json.ObjectMap) !FightResult {
|
||||||
const cooldown = getJsonObject(obj, "cooldown") orelse return error.MissingProperty;
|
const cooldown = getJsonObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||||
|
const character = getJsonObject(obj, "character") orelse return error.MissingProperty;
|
||||||
|
|
||||||
return FightResult{
|
return FightResult{
|
||||||
|
.cooldown = try Cooldown.parse(allocator, cooldown),
|
||||||
|
.character = try Character.parse(allocator, character)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *FightResult) void {
|
||||||
|
self.cooldown.deinit();
|
||||||
|
self.character.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const MoveResult = struct {
|
||||||
|
cooldown: Cooldown,
|
||||||
|
|
||||||
|
fn parse(allocator: Allocator, obj: json.ObjectMap) !MoveResult {
|
||||||
|
const cooldown = getJsonObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||||
|
|
||||||
|
return MoveResult{
|
||||||
.cooldown = try Cooldown.parse(allocator, cooldown)
|
.cooldown = try Cooldown.parse(allocator, cooldown)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: FightResult) void {
|
pub fn deinit(self: MoveResult) void {
|
||||||
self.cooldown.deinit();
|
self.cooldown.deinit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const ArtifactsFetchResult = struct {
|
pub const GoldTransactionResult = struct {
|
||||||
|
cooldown: Cooldown,
|
||||||
|
|
||||||
|
fn parse(allocator: Allocator, obj: json.ObjectMap) !GoldTransactionResult {
|
||||||
|
const cooldown = getJsonObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||||
|
|
||||||
|
return GoldTransactionResult{
|
||||||
|
.cooldown = try Cooldown.parse(allocator, cooldown)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: GoldTransactionResult) void {
|
||||||
|
self.cooldown.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ItemTransactionResult = struct {
|
||||||
|
cooldown: Cooldown,
|
||||||
|
|
||||||
|
fn parse(allocator: Allocator, obj: json.ObjectMap) !ItemTransactionResult {
|
||||||
|
const cooldown = getJsonObject(obj, "cooldown") orelse return error.MissingProperty;
|
||||||
|
|
||||||
|
return ItemTransactionResult{
|
||||||
|
.cooldown = try Cooldown.parse(allocator, cooldown)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: ItemTransactionResult) void {
|
||||||
|
self.cooldown.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ArtifactsFetchResult = struct {
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
status: std.http.Status,
|
status: std.http.Status,
|
||||||
body: ?json.Value = null,
|
body: ?json.Value = null,
|
||||||
@ -325,7 +425,7 @@ pub fn init(allocator: Allocator) !ArtifactsAPI {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(self: *ArtifactsAPI, method: std.http.Method, path: []const u8) !ArtifactsFetchResult {
|
fn fetch(self: *ArtifactsAPI, method: std.http.Method, path: []const u8, payload: ?[]const u8) !ArtifactsFetchResult {
|
||||||
var uri = self.server_uri;
|
var uri = self.server_uri;
|
||||||
uri.path = .{ .raw = path };
|
uri.path = .{ .raw = path };
|
||||||
|
|
||||||
@ -337,7 +437,8 @@ fn fetch(self: *ArtifactsAPI, method: std.http.Method, path: []const u8) !Artifa
|
|||||||
var opts = std.http.Client.FetchOptions{
|
var opts = std.http.Client.FetchOptions{
|
||||||
.method = method,
|
.method = method,
|
||||||
.location = .{ .uri = uri },
|
.location = .{ .uri = uri },
|
||||||
.response_storage = .{ .dynamic = &response_storage }
|
.payload = payload,
|
||||||
|
.response_storage = .{ .dynamic = &response_storage },
|
||||||
};
|
};
|
||||||
|
|
||||||
var authorization_header: ?[]u8 = null;
|
var authorization_header: ?[]u8 = null;
|
||||||
@ -349,16 +450,16 @@ fn fetch(self: *ArtifactsAPI, method: std.http.Method, path: []const u8) !Artifa
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = try self.client.fetch(opts);
|
const result = try self.client.fetch(opts);
|
||||||
|
const response_body = response_storage.items;
|
||||||
|
|
||||||
if (result.status != .ok) {
|
if (result.status != .ok) {
|
||||||
|
std.log.debug("Request {} {s} failed with code {}: {s}", .{method, path, result.status, response_body});
|
||||||
return ArtifactsFetchResult{
|
return ArtifactsFetchResult{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.status = result.status
|
.status = result.status
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const response_body = response_storage.items;
|
|
||||||
|
|
||||||
const parsed = try json.parseFromSliceLeaky(json.Value, arena.allocator(), response_body, .{ .allocate = .alloc_if_needed });
|
const parsed = try json.parseFromSliceLeaky(json.Value, arena.allocator(), response_body, .{ .allocate = .alloc_if_needed });
|
||||||
if (parsed != json.Value.object) {
|
if (parsed != json.Value.object) {
|
||||||
return APIErrors.ParseFailed;
|
return APIErrors.ParseFailed;
|
||||||
@ -371,6 +472,21 @@ fn fetch(self: *ArtifactsAPI, method: std.http.Method, path: []const u8) !Artifa
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetchAndParseObject(self: *ArtifactsAPI, Result: type, method: std.http.Method, path: []const u8, payload: ?[]const u8) !Result {
|
||||||
|
const result = try self.fetch(method, path, payload);
|
||||||
|
defer result.deinit();
|
||||||
|
|
||||||
|
if (result.status != .ok) {
|
||||||
|
return APIErrors.RequestFailed;
|
||||||
|
}
|
||||||
|
if (result.body == null) {
|
||||||
|
return APIErrors.ParseFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = asJsonObject(result.body.?) orelse return APIErrors.ParseFailed;
|
||||||
|
return Result.parse(self.allocator, body) catch return APIErrors.ParseFailed;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setServer(self: *ArtifactsAPI, url: []const u8) !void {
|
pub fn setServer(self: *ArtifactsAPI, url: []const u8) !void {
|
||||||
const url_dupe = self.allocator.dupe(u8, url);
|
const url_dupe = self.allocator.dupe(u8, url);
|
||||||
errdefer self.allocator.free(url_dupe);
|
errdefer self.allocator.free(url_dupe);
|
||||||
@ -448,44 +564,31 @@ fn getJsonObject(object: json.ObjectMap, name: []const u8) ?json.ObjectMap {
|
|||||||
return asJsonObject(value.?);
|
return asJsonObject(value.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getJsonArray(object: json.ObjectMap, name: []const u8) ?json.Array {
|
||||||
|
const value = object.get(name);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return asJsonArray(value.?);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getServerStatus(self: *ArtifactsAPI) !ServerStatus {
|
pub fn getServerStatus(self: *ArtifactsAPI) !ServerStatus {
|
||||||
const result = try self.fetch(.GET, "/");
|
return try self.fetchAndParseObject(ServerStatus, .GET, "/", null);
|
||||||
defer result.deinit();
|
|
||||||
|
|
||||||
if (result.status != .ok) {
|
|
||||||
return APIErrors.RequestFailed;
|
|
||||||
}
|
|
||||||
if (result.body == null) {
|
|
||||||
return APIErrors.ParseFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = asJsonObject(result.body.?) orelse return APIErrors.ParseFailed;
|
|
||||||
return ServerStatus.parse(self.allocator, body) catch return APIErrors.ParseFailed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getCharacter(self: *ArtifactsAPI, name: []const u8) !Character {
|
pub fn getCharacter(self: *ArtifactsAPI, name: []const u8) !Character {
|
||||||
const path = try std.fmt.allocPrint(self.allocator, "/characters/{s}", .{name});
|
const path = try std.fmt.allocPrint(self.allocator, "/characters/{s}", .{name});
|
||||||
defer self.allocator.free(path);
|
defer self.allocator.free(path);
|
||||||
|
|
||||||
const result = try self.fetch(.GET, path);
|
return try self.fetchAndParseObject(Character, .GET, path, null);
|
||||||
defer result.deinit();
|
|
||||||
|
|
||||||
if (result.status != .ok) {
|
|
||||||
return APIErrors.RequestFailed;
|
|
||||||
}
|
|
||||||
if (result.body == null) {
|
|
||||||
return APIErrors.ParseFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = asJsonObject(result.body.?) orelse return APIErrors.ParseFailed;
|
|
||||||
return Character.parse(self.allocator, body) catch return APIErrors.ParseFailed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listMyCharacters(self: *ArtifactsAPI) !CharacterList {
|
pub fn listMyCharacters(self: *ArtifactsAPI) !CharacterList {
|
||||||
const path = try std.fmt.allocPrint(self.allocator, "/my/characters", .{});
|
const path = try std.fmt.allocPrint(self.allocator, "/my/characters", .{});
|
||||||
defer self.allocator.free(path);
|
defer self.allocator.free(path);
|
||||||
|
|
||||||
const result = try self.fetch(.GET, path);
|
const result = try self.fetch(.GET, path, null);
|
||||||
defer result.deinit();
|
defer result.deinit();
|
||||||
|
|
||||||
if (result.status != .ok) {
|
if (result.status != .ok) {
|
||||||
@ -523,18 +626,37 @@ pub fn actionFight(self: *ArtifactsAPI, name: []const u8) !FightResult {
|
|||||||
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/fight", .{name});
|
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/fight", .{name});
|
||||||
defer self.allocator.free(path);
|
defer self.allocator.free(path);
|
||||||
|
|
||||||
const result = try self.fetch(.POST, path);
|
return try self.fetchAndParseObject(FightResult, .POST, path, null);
|
||||||
defer result.deinit();
|
}
|
||||||
|
|
||||||
if (result.status != .ok) {
|
pub fn actionMove(self: *ArtifactsAPI, name: []const u8, x: i64, y: i64) !MoveResult {
|
||||||
return APIErrors.RequestFailed;
|
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/move", .{name});
|
||||||
}
|
defer self.allocator.free(path);
|
||||||
if (result.body == null) {
|
|
||||||
return APIErrors.ParseFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = asJsonObject(result.body.?) orelse return APIErrors.ParseFailed;
|
const payload = try std.fmt.allocPrint(self.allocator, "{{ \"x\":{},\"y\":{} }}", .{x, y});
|
||||||
return FightResult.parse(self.allocator, body) catch return APIErrors.ParseFailed;
|
defer self.allocator.free(payload);
|
||||||
|
|
||||||
|
return try self.fetchAndParseObject(MoveResult, .POST, path, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn actionBankDepositGold(self: *ArtifactsAPI, name: []const u8, quantity: u64) !GoldTransactionResult {
|
||||||
|
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/bank/deposit/gold", .{name});
|
||||||
|
defer self.allocator.free(path);
|
||||||
|
|
||||||
|
const payload = try std.fmt.allocPrint(self.allocator, "{{ \"quantity\":{} }}", .{quantity});
|
||||||
|
defer self.allocator.free(payload);
|
||||||
|
|
||||||
|
return try self.fetchAndParseObject(GoldTransactionResult, .POST, path, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn actionBankDeposit(self: *ArtifactsAPI, name: []const u8, code: []const u8, quantity: u64) !ItemTransactionResult {
|
||||||
|
const path = try std.fmt.allocPrint(self.allocator, "/my/{s}/action/bank/deposit", .{name});
|
||||||
|
defer self.allocator.free(path);
|
||||||
|
|
||||||
|
const payload = try std.fmt.allocPrint(self.allocator, "{{ \"code\":\"{s}\",\"quantity\":{} }}", .{code, quantity});
|
||||||
|
defer self.allocator.free(payload);
|
||||||
|
|
||||||
|
return try self.fetchAndParseObject(ItemTransactionResult, .POST, path, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *ArtifactsAPI) void {
|
pub fn deinit(self: *ArtifactsAPI) void {
|
||||||
|
112
src/main.zig
112
src/main.zig
@ -1,6 +1,43 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
const ArtifactsAPI = @import("artifacts.zig");
|
const ArtifactsAPI = @import("artifacts.zig");
|
||||||
|
|
||||||
|
fn waitForCooldown(remaining_seconds: i64) void {
|
||||||
|
if (remaining_seconds > 0) {
|
||||||
|
std.log.debug("Waiting for cooldown {}", .{remaining_seconds});
|
||||||
|
std.time.sleep(std.time.ns_per_s * (@as(u64, @intCast(remaining_seconds)) + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn depositIfNeeded(api: *ArtifactsAPI, char: *ArtifactsAPI.Character) !void {
|
||||||
|
if (char.getItemCount() == char.inventory_max_items) return;
|
||||||
|
|
||||||
|
{
|
||||||
|
const move_result = try api.actionMove(char.name, 4, 1);
|
||||||
|
defer move_result.deinit();
|
||||||
|
waitForCooldown(move_result.cooldown.remaining_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deposit_gold = try api.actionBankDepositGold(char.name, @intCast(char.gold));
|
||||||
|
defer deposit_gold.deinit();
|
||||||
|
waitForCooldown(deposit_gold.cooldown.remaining_seconds);
|
||||||
|
|
||||||
|
for (char.inventory.slots) |slot| {
|
||||||
|
if (slot.quantity == 0) continue;
|
||||||
|
|
||||||
|
const deposit_item = try api.actionBankDeposit(char.name, slot.code, @intCast(slot.quantity));
|
||||||
|
defer deposit_item.deinit();
|
||||||
|
waitForCooldown(deposit_item.cooldown.remaining_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const move_result = try api.actionMove(char.name, 0, 1);
|
||||||
|
defer move_result.deinit();
|
||||||
|
waitForCooldown(move_result.cooldown.remaining_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
@ -9,18 +46,75 @@ pub fn main() !void {
|
|||||||
var api = try ArtifactsAPI.init(allocator);
|
var api = try ArtifactsAPI.init(allocator);
|
||||||
defer api.deinit();
|
defer api.deinit();
|
||||||
|
|
||||||
{ // Set auth token from environment variable
|
const args = try std.process.argsAlloc(allocator);
|
||||||
var env = try std.process.getEnvMap(allocator);
|
defer std.process.argsFree(allocator, args);
|
||||||
defer env.deinit();
|
|
||||||
|
|
||||||
const token = env.get("ARTIFACTS_TOKEN");
|
if (args.len >= 2) {
|
||||||
try api.setToken(token);
|
const filename = args[1];
|
||||||
|
const cwd = std.fs.cwd();
|
||||||
|
|
||||||
|
var token_buffer: [256]u8 = undefined;
|
||||||
|
const token = try cwd.readFile(filename, &token_buffer);
|
||||||
|
try api.setToken(std.mem.trim(u8,token,"\n\t "));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
if (api.token == null) {
|
||||||
const result = try api.actionFight("Daisy");
|
return error.MissingToken;
|
||||||
defer result.deinit();
|
}
|
||||||
|
|
||||||
std.time.sleep(std.time.ns_per_s * (@as(u64, @intCast(result.cooldown.remaining_seconds)) + 1));
|
const characters = try api.listMyCharacters();
|
||||||
|
defer characters.deinit();
|
||||||
|
|
||||||
|
{
|
||||||
|
var longest_cooldown: i64 = 0;
|
||||||
|
|
||||||
|
for (characters.items) |char| {
|
||||||
|
if (char.x == 0 and char.y == 1) continue;
|
||||||
|
|
||||||
|
const result = try api.actionMove(char.name, 0, 1);
|
||||||
|
defer result.deinit();
|
||||||
|
|
||||||
|
longest_cooldown = @max(longest_cooldown, result.cooldown.remaining_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (longest_cooldown > 0) {
|
||||||
|
std.log.debug("Waiting for cooldown {}", .{longest_cooldown});
|
||||||
|
|
||||||
|
std.time.sleep(std.time.ns_per_s * (@as(u64, @intCast(longest_cooldown)) + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std.log.info("Started main loop", .{});
|
||||||
|
while (true) {
|
||||||
|
var results = std.ArrayList(ArtifactsAPI.FightResult).init(allocator);
|
||||||
|
defer {
|
||||||
|
for (results.items) |*result| {
|
||||||
|
result.deinit();
|
||||||
|
}
|
||||||
|
results.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (characters.items) |char| {
|
||||||
|
var result = try api.actionFight(char.name);
|
||||||
|
errdefer result.deinit();
|
||||||
|
|
||||||
|
try results.append(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var longest_cooldown: i64 = 0;
|
||||||
|
for (results.items) |result| {
|
||||||
|
longest_cooldown = @max(longest_cooldown, result.cooldown.remaining_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (longest_cooldown > 0) {
|
||||||
|
std.log.debug("Waiting for cooldown {}", .{longest_cooldown});
|
||||||
|
std.time.sleep(std.time.ns_per_s * (@as(u64, @intCast(longest_cooldown)) + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (results.items) |*result| {
|
||||||
|
try depositIfNeeded(&api, &result.character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user