move minionlogic to separate funciton
This commit is contained in:
parent
7e3c8b4a75
commit
0cf55b3ef1
466
src/app.zig
466
src/app.zig
@ -160,6 +160,7 @@ const Entity = struct {
|
||||
minion_chop_cooldown: Nanoseconds = 0,
|
||||
minion_chop_damage: u32 = 2,
|
||||
minion_burn_speed: f32 = 1,
|
||||
minion_carried_wood: ?EntityId = null,
|
||||
|
||||
tree_health: u32 = 0,
|
||||
tree_max_health: u32 = 0,
|
||||
@ -168,6 +169,8 @@ const Entity = struct {
|
||||
station_spawn_tree_cooldown: Nanoseconds = 0,
|
||||
station_owned_tree: ?EntityId = null,
|
||||
|
||||
wood_carried_by: ?EntityId = null,
|
||||
|
||||
pos: Vec2 = .init(0, 0),
|
||||
vel: Vec2 = .init(0, 0),
|
||||
acc: Vec2 = .init(0, 0),
|
||||
@ -264,19 +267,19 @@ pub fn init(self: *App, plt: Platform.Init) !?u8 {
|
||||
.font = font
|
||||
};
|
||||
|
||||
try self.spawnMinion(.init(0, 0));
|
||||
self.spawnMinion(.init(0, 0));
|
||||
// try self.spawnMinion(.init(32, 0));
|
||||
|
||||
try self.spawnStation(-100, .chop);
|
||||
try self.spawnStation(-150, .chop);
|
||||
try self.spawnStation(100, .burn);
|
||||
try self.spawnStation(150, .burn);
|
||||
self.spawnStation(-100, .chop);
|
||||
self.spawnStation(-150, .chop);
|
||||
self.spawnStation(100, .burn);
|
||||
self.spawnStation(150, .burn);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn spawnMinion(self: *App, pos: Vec2) !void {
|
||||
_ = try self.entities.insert(Entity{
|
||||
pub fn spawnMinion(self: *App, pos: Vec2) void {
|
||||
_ = self.entities.insert(Entity{
|
||||
.type = .minion,
|
||||
.flags = .{
|
||||
.has_animation = true,
|
||||
@ -289,19 +292,25 @@ pub fn spawnMinion(self: *App, pos: Vec2) !void {
|
||||
.max_walk_speed = 300,
|
||||
|
||||
.animation = .idle,
|
||||
});
|
||||
}) catch {
|
||||
log.warn("Failed to spawn minion, entity limit reached", .{});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn spawnStation(self: *App, pos: f32, subtype: Entity.StationSubtype) !void {
|
||||
_ = try self.entities.insert(Entity{
|
||||
pub fn spawnStation(self: *App, pos: f32, subtype: Entity.StationSubtype) void {
|
||||
_ = self.entities.insert(Entity{
|
||||
.type = .station,
|
||||
.station_subtype = subtype,
|
||||
|
||||
.pos = .init(pos, 0),
|
||||
});
|
||||
}) catch {
|
||||
log.warn("Failed to spawn station, entity limit reached", .{});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn spawnTree(self: *App, station_id: EntityId) !void {
|
||||
fn spawnTree(self: *App, station_id: EntityId) void {
|
||||
const station = self.entities.get(station_id) orelse return;
|
||||
assert(station.type == .station);
|
||||
if (station.station_owned_tree != null) {
|
||||
@ -309,16 +318,38 @@ fn spawnTree(self: *App, station_id: EntityId) !void {
|
||||
}
|
||||
|
||||
const health = 10;
|
||||
const id = try self.entities.insert(Entity{
|
||||
const id = self.entities.insert(Entity{
|
||||
.type = .tree,
|
||||
.tree_health = health,
|
||||
.tree_max_health = health,
|
||||
|
||||
.pos = station.pos
|
||||
});
|
||||
}) catch {
|
||||
log.warn("Failed to spawn tree, entity limit reached", .{});
|
||||
return;
|
||||
};
|
||||
station.station_owned_tree = id;
|
||||
}
|
||||
|
||||
fn destroyTree(self: *App, tree_id: EntityId) void {
|
||||
const tree = self.entities.get(tree_id) orelse return;
|
||||
assert(tree.type == .tree);
|
||||
|
||||
self.spawnWood(tree.pos);
|
||||
|
||||
self.entities.removeAssumeExists(tree_id);
|
||||
}
|
||||
|
||||
fn spawnWood(self: *App, pos: Vec2) void {
|
||||
_ = self.entities.insert(Entity{
|
||||
.type = .wood,
|
||||
.pos = pos
|
||||
}) catch {
|
||||
log.warn("Failed to spawn wood, entity limit reached", .{});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn getNearestFreeStation(self: *App, from: Vec2, subtype: Entity.StationSubtype) ?EntityId {
|
||||
var result: ?EntityId = null;
|
||||
var result_distance: f32 = 0;
|
||||
@ -347,14 +378,14 @@ fn getNearestFreeStation(self: *App, from: Vec2, subtype: Entity.StationSubtype)
|
||||
return result;
|
||||
}
|
||||
|
||||
fn getNearestFreeTree(self: *App, from: Vec2) ?EntityId {
|
||||
fn getNearestFreeEntity(self: *App, from: Vec2, entity_type: Entity.Type) ?EntityId {
|
||||
var result: ?EntityId = null;
|
||||
var result_distance: f32 = 0;
|
||||
|
||||
var station_iter = self.entities.iterator();
|
||||
while (station_iter.next()) |id| {
|
||||
const station = self.entities.getAssumeExists(id);
|
||||
if (station.type != .tree) {
|
||||
if (station.type != entity_type) {
|
||||
continue;
|
||||
}
|
||||
if (station.targeted_by_entity != null) {
|
||||
@ -400,6 +431,141 @@ fn drawProgressBar(progress: f32, center: Vec2, size: Vec2, color: Color) void {
|
||||
Gfx.drawLine(from, from.add(.init(size.x * progress, 0)), color, size.y);
|
||||
}
|
||||
|
||||
fn minionLogic(self: *App, plt: Platform.Frame, minion_id: EntityId) !void {
|
||||
const minion = self.entities.getAssumeExists(minion_id);
|
||||
assert(minion.type == .minion);
|
||||
|
||||
const goal_distance_threshold = 10;
|
||||
var walk_goal: ?Vec2 = null;
|
||||
var station_goal: ?Entity.StationSubtype = null;
|
||||
|
||||
if (minion.minion_state == .goto_tree_station) {
|
||||
// if (minion.minion_carried_wood == null) {
|
||||
// if (self.getNearestFreeEntity(minion.pos, .tree)) |tree_id| {
|
||||
// _ = tree_id; // autofix
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
switch (minion.minion_state) {
|
||||
.goto_tree_station => {
|
||||
// TODO: Steal tree if it is nearer to you compared to the current minion that has it reserved.
|
||||
if (self.getNearestFreeEntity(minion.pos, .tree)) |tree_id| {
|
||||
self.setEntityTarget(minion_id, tree_id);
|
||||
minion.minion_state = .chop_tree;
|
||||
} else {
|
||||
station_goal = .chop;
|
||||
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
if (station.type != .station) {
|
||||
self.unsetEntityTarget(minion_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.chop_tree => {
|
||||
if (minion.target_entity) |tree_id| {
|
||||
if (self.entities.getAssumeExists(tree_id).type != .tree) {
|
||||
self.unsetEntityTarget(minion_id);
|
||||
minion.minion_state = .goto_tree_station;
|
||||
}
|
||||
}
|
||||
|
||||
var is_at_tree = false;
|
||||
if (minion.target_entity) |tree_id| {
|
||||
const tree = self.entities.getAssumeExists(tree_id);
|
||||
|
||||
is_at_tree = minion.pos.distance(tree.pos) < goal_distance_threshold;
|
||||
if (is_at_tree) {
|
||||
minion.minion_chop_cooldown = @max(minion.minion_chop_cooldown - plt.dt, 0);
|
||||
if (minion.minion_chop_cooldown == 0) {
|
||||
minion.minion_chop_cooldown = std.time.ns_per_ms * 500;
|
||||
tree.tree_health -= minion.minion_chop_damage;
|
||||
}
|
||||
|
||||
if (tree.tree_health <= 0) {
|
||||
minion.minion_state = .burn;
|
||||
|
||||
self.unsetEntityTarget(minion_id);
|
||||
self.destroyTree(tree_id);
|
||||
}
|
||||
} else {
|
||||
walk_goal = tree.pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_at_tree) {
|
||||
minion.minion_work_progress = 0;
|
||||
}
|
||||
},
|
||||
.pickup_wood => {
|
||||
},
|
||||
.burn => {
|
||||
station_goal = .burn;
|
||||
|
||||
var is_at_station = false;
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
if (station.pos.distance(minion.pos) < goal_distance_threshold) {
|
||||
is_at_station = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_at_station) {
|
||||
minion.minion_work_progress = 0;
|
||||
}
|
||||
|
||||
if (is_at_station) {
|
||||
minion.minion_work_progress += minion.minion_burn_speed * plt.deltaTime();
|
||||
}
|
||||
|
||||
minion.minion_work_progress = std.math.clamp(minion.minion_work_progress, 0, 1);
|
||||
if (minion.minion_work_progress == 1) {
|
||||
minion.minion_state = .goto_tree_station;
|
||||
minion.minion_work_progress = 0;
|
||||
self.heat += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if (station_goal) |station_type| {
|
||||
if (minion.target_entity) |entity_id| {
|
||||
if (self.entities.get(entity_id)) |station| {
|
||||
if (station.type != .station) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
if (station.station_subtype != station_type) {
|
||||
self.unsetEntityTarget(minion_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (minion.target_entity == null) {
|
||||
if (self.getNearestFreeStation(minion.pos, station_type)) |station_id| {
|
||||
self.setEntityTarget(minion_id, station_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
walk_goal = station.pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (walk_goal) |pos| {
|
||||
const diff = minion.pos.x - pos.x;
|
||||
if (diff < -goal_distance_threshold) {
|
||||
minion.acc = .init(minion.max_walk_speed, 0);
|
||||
} else if (diff > goal_distance_threshold) {
|
||||
minion.acc = .init(-minion.max_walk_speed, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
const input = plt.input;
|
||||
_ = input; // autofix
|
||||
@ -440,7 +606,7 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
if (station.station_subtype == .chop) {
|
||||
station.station_spawn_tree_cooldown = @max(station.station_spawn_tree_cooldown - plt.dt, 0);
|
||||
if (station.station_spawn_tree_cooldown == 0 and station.station_owned_tree == null) {
|
||||
try self.spawnTree(station_id);
|
||||
self.spawnTree(station_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -481,127 +647,7 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
continue;
|
||||
}
|
||||
|
||||
const goal_distance_threshold = 10;
|
||||
var walk_goal: ?Vec2 = null;
|
||||
var station_goal: ?Entity.StationSubtype = null;
|
||||
|
||||
switch (minion.minion_state) {
|
||||
.goto_tree_station => {
|
||||
// TODO: Steal tree is it is nearer to you compared to the current minion that has it reserved.
|
||||
if (self.getNearestFreeTree(minion.pos)) |tree_id| {
|
||||
self.setEntityTarget(minion_id, tree_id);
|
||||
minion.minion_state = .chop_tree;
|
||||
} else {
|
||||
station_goal = .chop;
|
||||
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
if (station.type != .station) {
|
||||
self.unsetEntityTarget(minion_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.chop_tree => {
|
||||
if (minion.target_entity) |tree_id| {
|
||||
if (self.entities.getAssumeExists(tree_id).type != .tree) {
|
||||
self.unsetEntityTarget(minion_id);
|
||||
minion.minion_state = .goto_tree_station;
|
||||
}
|
||||
}
|
||||
|
||||
var is_at_tree = false;
|
||||
if (minion.target_entity) |tree_id| {
|
||||
const tree = self.entities.getAssumeExists(tree_id);
|
||||
|
||||
is_at_tree = minion.pos.distance(tree.pos) < goal_distance_threshold;
|
||||
if (is_at_tree) {
|
||||
minion.minion_chop_cooldown = @max(minion.minion_chop_cooldown - plt.dt, 0);
|
||||
if (minion.minion_chop_cooldown == 0) {
|
||||
minion.minion_chop_cooldown = std.time.ns_per_ms * 500;
|
||||
tree.tree_health -= minion.minion_chop_damage;
|
||||
}
|
||||
|
||||
if (tree.tree_health <= 0) {
|
||||
minion.minion_state = .burn;
|
||||
|
||||
self.unsetEntityTarget(minion_id);
|
||||
self.entities.removeAssumeExists(tree_id);
|
||||
}
|
||||
} else {
|
||||
walk_goal = tree.pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_at_tree) {
|
||||
minion.minion_work_progress = 0;
|
||||
}
|
||||
},
|
||||
.pickup_wood => {
|
||||
},
|
||||
.burn => {
|
||||
station_goal = .burn;
|
||||
|
||||
var is_at_station = false;
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
if (station.pos.distance(minion.pos) < goal_distance_threshold) {
|
||||
is_at_station = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_at_station) {
|
||||
minion.minion_work_progress = 0;
|
||||
}
|
||||
|
||||
if (is_at_station) {
|
||||
minion.minion_work_progress += minion.minion_burn_speed * dt;
|
||||
}
|
||||
|
||||
minion.minion_work_progress = std.math.clamp(minion.minion_work_progress, 0, 1);
|
||||
if (minion.minion_work_progress == 1) {
|
||||
minion.minion_state = .goto_tree_station;
|
||||
minion.minion_work_progress = 0;
|
||||
self.heat += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if (station_goal) |station_type| {
|
||||
if (minion.target_entity) |entity_id| {
|
||||
if (self.entities.get(entity_id)) |station| {
|
||||
if (station.type != .station) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
if (station.station_subtype != station_type) {
|
||||
self.unsetEntityTarget(minion_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (minion.target_entity == null) {
|
||||
if (self.getNearestFreeStation(minion.pos, station_type)) |station_id| {
|
||||
self.setEntityTarget(minion_id, station_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (minion.target_entity) |station_id| {
|
||||
const station = self.entities.getAssumeExists(station_id);
|
||||
walk_goal = station.pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (walk_goal) |pos| {
|
||||
const diff = minion.pos.x - pos.x;
|
||||
if (diff < -goal_distance_threshold) {
|
||||
minion.acc = .init(minion.max_walk_speed, 0);
|
||||
} else if (diff > goal_distance_threshold) {
|
||||
minion.acc = .init(-minion.max_walk_speed, 0);
|
||||
}
|
||||
}
|
||||
try self.minionLogic(plt, minion_id);
|
||||
|
||||
if (minion.acc.x > 0) {
|
||||
minion.animation = .walk;
|
||||
@ -630,82 +676,96 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
}
|
||||
}
|
||||
|
||||
var entity_iter = self.entities.iterator();
|
||||
while (entity_iter.next()) |id| {
|
||||
const e = self.entities.getAssumeExists(id);
|
||||
{
|
||||
var entity_iter = self.entities.iterator();
|
||||
while (entity_iter.next()) |id| {
|
||||
const e = self.entities.getAssumeExists(id);
|
||||
|
||||
if (e.flags.has_kinematics) {
|
||||
e.vel = e.vel.add(e.acc.multiplyScalar(dt));
|
||||
e.vel = e.vel.limitLength(e.max_velocity);
|
||||
e.pos = e.pos.add(e.vel.multiplyScalar(dt));
|
||||
if (e.flags.has_kinematics) {
|
||||
e.vel = e.vel.add(e.acc.multiplyScalar(dt));
|
||||
e.vel = e.vel.limitLength(e.max_velocity);
|
||||
e.pos = e.pos.add(e.vel.multiplyScalar(dt));
|
||||
|
||||
const friction_force = std.math.pow(f32, 1 - e.friction, dt);
|
||||
e.vel = e.vel.multiplyScalar(friction_force);
|
||||
const friction_force = std.math.pow(f32, 1 - e.friction, dt);
|
||||
e.vel = e.vel.multiplyScalar(friction_force);
|
||||
|
||||
e.acc = .init(0, 0);
|
||||
}
|
||||
e.acc = .init(0, 0);
|
||||
}
|
||||
|
||||
if (e.flags.has_animation) {
|
||||
const animations = switch (e.animation) {
|
||||
.idle => self.idle_animations,
|
||||
.walk => self.walk_animations,
|
||||
.death => self.death_animations
|
||||
};
|
||||
var flip_animation = false;
|
||||
const animation = switch (e.animation_dir) {
|
||||
.right => animations.right,
|
||||
.up => animations.up,
|
||||
.down => animations.down,
|
||||
.left => blk: {
|
||||
flip_animation = true;
|
||||
break :blk animations.right;
|
||||
if (e.flags.has_animation) {
|
||||
const animations = switch (e.animation) {
|
||||
.idle => self.idle_animations,
|
||||
.walk => self.walk_animations,
|
||||
.death => self.death_animations
|
||||
};
|
||||
var flip_animation = false;
|
||||
const animation = switch (e.animation_dir) {
|
||||
.right => animations.right,
|
||||
.up => animations.up,
|
||||
.down => animations.down,
|
||||
.left => blk: {
|
||||
flip_animation = true;
|
||||
break :blk animations.right;
|
||||
}
|
||||
};
|
||||
|
||||
e.animation_timer += plt.dt;
|
||||
while (e.animation_timer >= animation.frame_duration) {
|
||||
e.animation_timer -= animation.frame_duration;
|
||||
e.animation_index += 1;
|
||||
}
|
||||
};
|
||||
|
||||
e.animation_timer += plt.dt;
|
||||
while (e.animation_timer >= animation.frame_duration) {
|
||||
e.animation_timer -= animation.frame_duration;
|
||||
e.animation_index += 1;
|
||||
e.animation_index = e.animation_index % @as(u32, @intCast(animation.frames.len));
|
||||
const sprite = animation.frames[e.animation_index];
|
||||
|
||||
var size = character_size;
|
||||
var pos = e.pos;
|
||||
pos.y -= character_size.y*0.7;
|
||||
if (flip_animation) {
|
||||
size.x *= -1;
|
||||
pos.x += character_size.x/2;
|
||||
} else {
|
||||
pos.x -= character_size.x/2;
|
||||
}
|
||||
|
||||
Gfx.drawRectangle(
|
||||
e.pos.sub(.init(5, 5)),
|
||||
.init(10, 10),
|
||||
.white
|
||||
);
|
||||
Gfx.drawSprite(sprite, pos, size, .white);
|
||||
|
||||
const is_working = e.minion_state == .chop_tree or e.minion_state == .burn;
|
||||
if (e.type == .minion and is_working and e.minion_work_progress > 0) {
|
||||
drawProgressBar(e.minion_work_progress, e.pos.add(.init(0, 20)), .init(100, 10), .rgb(0, 200, 20));
|
||||
}
|
||||
}
|
||||
|
||||
e.animation_index = e.animation_index % @as(u32, @intCast(animation.frames.len));
|
||||
const sprite = animation.frames[e.animation_index];
|
||||
|
||||
var size = character_size;
|
||||
var pos = e.pos;
|
||||
pos.y -= character_size.y*0.7;
|
||||
if (flip_animation) {
|
||||
size.x *= -1;
|
||||
pos.x += character_size.x/2;
|
||||
} else {
|
||||
pos.x -= character_size.x/2;
|
||||
}
|
||||
|
||||
Gfx.drawRectangle(
|
||||
e.pos.sub(.init(5, 5)),
|
||||
.init(10, 10),
|
||||
.white
|
||||
);
|
||||
Gfx.drawSprite(sprite, pos, size, .white);
|
||||
|
||||
const is_working = e.minion_state == .chop_tree or e.minion_state == .burn;
|
||||
if (e.type == .minion and is_working and e.minion_work_progress > 0) {
|
||||
drawProgressBar(e.minion_work_progress, e.pos.add(.init(0, 20)), .init(100, 10), .rgb(0, 200, 20));
|
||||
if (e.type == .station) {
|
||||
if (e.station_subtype == .chop) {
|
||||
Gfx.drawRectangle(e.pos.sub(.init(5, 5)), .init(10, 10), .rgb(20, 200, 20));
|
||||
} else {
|
||||
Gfx.drawRectangle(e.pos.sub(.init(5, 5)), .init(10, 10), .rgb(200, 20, 20));
|
||||
}
|
||||
} else if (e.type == .minion) {
|
||||
Gfx.drawText(self.font, .{
|
||||
.pos = e.pos.sub(.init(20, 50)),
|
||||
.height = 16,
|
||||
.text = try std.fmt.allocPrint(plt.arena, "{}", .{e.minion_state})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.type == .station) {
|
||||
if (e.station_subtype == .chop) {
|
||||
Gfx.drawRectangle(e.pos.sub(.init(5, 5)), .init(10, 10), .rgb(20, 200, 20));
|
||||
} else {
|
||||
Gfx.drawRectangle(e.pos.sub(.init(5, 5)), .init(10, 10), .rgb(200, 20, 20));
|
||||
{
|
||||
var wood_iter = self.entities.iterator();
|
||||
while (wood_iter.next()) |id| {
|
||||
const wood = self.entities.getAssumeExists(id);
|
||||
if (wood.type != .wood) {
|
||||
continue;
|
||||
}
|
||||
} else if (e.type == .minion) {
|
||||
Gfx.drawText(self.font, .{
|
||||
.pos = e.pos.sub(.init(20, 50)),
|
||||
.height = 16,
|
||||
.text = try std.fmt.allocPrint(plt.arena, "{}", .{e.minion_state})
|
||||
});
|
||||
|
||||
Gfx.drawRectangle(wood.pos.sub(.init(10, 10)), .init(20, 20), .rgb(100, 100, 20));
|
||||
}
|
||||
}
|
||||
|
||||
@ -719,7 +779,7 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
||||
defer ImGUI.endWindow();
|
||||
|
||||
if (ImGUI.button("spawn")) {
|
||||
try self.spawnMinion(.init(32, 0));
|
||||
self.spawnMinion(.init(32, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user