adding delivery
This commit is contained in:
@@ -255,7 +255,7 @@ func _draw_control_layer(control_tiles: Array, control: String, layer_scale: flo
|
|||||||
func _draw_movement_indicators() -> void:
|
func _draw_movement_indicators() -> void:
|
||||||
for unit in unit_instances:
|
for unit in unit_instances:
|
||||||
var status := str(unit.get("status", ""))
|
var status := str(unit.get("status", ""))
|
||||||
if status != "Moving" and status != "MovingToWork":
|
if status != "Moving" and status != "MovingToWork" and status != "DeliveringToTownHall" and status != "ReturningToWork":
|
||||||
continue
|
continue
|
||||||
if unit.get("destinationQ", null) == null or unit.get("destinationR", null) == null:
|
if unit.get("destinationQ", null) == null or unit.get("destinationR", null) == null:
|
||||||
continue
|
continue
|
||||||
@@ -1022,7 +1022,7 @@ func _peasant_count_at(q: int, r: int) -> int:
|
|||||||
var count := 0
|
var count := 0
|
||||||
for unit in unit_instances:
|
for unit in unit_instances:
|
||||||
var status := str(unit.get("status", ""))
|
var status := str(unit.get("status", ""))
|
||||||
if str(unit.get("unitType", "")) != "Peasant" or (status != "Idle" and status != "Moving" and status != "MovingToWork"):
|
if str(unit.get("unitType", "")) != "Peasant" or (status != "Idle" and status != "Moving" and status != "MovingToWork" and status != "DeliveringToTownHall" and status != "ReturningToWork"):
|
||||||
continue
|
continue
|
||||||
if int(unit.get("q", 0)) == q and int(unit.get("r", 0)) == r:
|
if int(unit.get("q", 0)) == q and int(unit.get("r", 0)) == r:
|
||||||
count += 1
|
count += 1
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class Location
|
|||||||
public int StoredResourceAmount { get; set; }
|
public int StoredResourceAmount { get; set; }
|
||||||
public int StoredResourceCapacity { get; set; } = 10;
|
public int StoredResourceCapacity { get; set; } = 10;
|
||||||
public DateTime? LastResourceGeneratedAtUtc { get; set; }
|
public DateTime? LastResourceGeneratedAtUtc { get; set; }
|
||||||
|
public DateTime? DeliveryCycleStartedAtUtc { get; set; }
|
||||||
public DateTime? HomeAssignedAtUtc { get; set; }
|
public DateTime? HomeAssignedAtUtc { get; set; }
|
||||||
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime UpdatedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ public class UnitInstanceResponse
|
|||||||
public int? DestinationQ { get; set; }
|
public int? DestinationQ { get; set; }
|
||||||
public int? DestinationR { get; set; }
|
public int? DestinationR { get; set; }
|
||||||
public bool ClaimOnArrival { get; set; }
|
public bool ClaimOnArrival { get; set; }
|
||||||
|
public int? WorksiteQ { get; set; }
|
||||||
|
public int? WorksiteR { get; set; }
|
||||||
|
public string? CarryingResourceType { get; set; }
|
||||||
|
public int CarryingResourceAmount { get; set; }
|
||||||
public DateTime? MovementStartedAtUtc { get; set; }
|
public DateTime? MovementStartedAtUtc { get; set; }
|
||||||
public DateTime? MovementCompletesAtUtc { get; set; }
|
public DateTime? MovementCompletesAtUtc { get; set; }
|
||||||
public DateTime CreatedAtUtc { get; set; }
|
public DateTime CreatedAtUtc { get; set; }
|
||||||
@@ -96,6 +100,10 @@ public class UnitInstanceResponse
|
|||||||
DestinationQ = unit.DestinationQ,
|
DestinationQ = unit.DestinationQ,
|
||||||
DestinationR = unit.DestinationR,
|
DestinationR = unit.DestinationR,
|
||||||
ClaimOnArrival = unit.ClaimOnArrival,
|
ClaimOnArrival = unit.ClaimOnArrival,
|
||||||
|
WorksiteQ = unit.WorksiteQ,
|
||||||
|
WorksiteR = unit.WorksiteR,
|
||||||
|
CarryingResourceType = unit.CarryingResourceType,
|
||||||
|
CarryingResourceAmount = unit.CarryingResourceAmount,
|
||||||
MovementStartedAtUtc = unit.MovementStartedAtUtc,
|
MovementStartedAtUtc = unit.MovementStartedAtUtc,
|
||||||
MovementCompletesAtUtc = unit.MovementCompletesAtUtc,
|
MovementCompletesAtUtc = unit.MovementCompletesAtUtc,
|
||||||
CreatedAtUtc = unit.CreatedAtUtc,
|
CreatedAtUtc = unit.CreatedAtUtc,
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ public class UnitInstance
|
|||||||
public int? DestinationQ { get; set; }
|
public int? DestinationQ { get; set; }
|
||||||
public int? DestinationR { get; set; }
|
public int? DestinationR { get; set; }
|
||||||
public bool ClaimOnArrival { get; set; }
|
public bool ClaimOnArrival { get; set; }
|
||||||
|
public int? WorksiteQ { get; set; }
|
||||||
|
public int? WorksiteR { get; set; }
|
||||||
|
public string? CarryingResourceType { get; set; }
|
||||||
|
public int CarryingResourceAmount { get; set; }
|
||||||
public DateTime? MovementStartedAtUtc { get; set; }
|
public DateTime? MovementStartedAtUtc { get; set; }
|
||||||
public DateTime? MovementCompletesAtUtc { get; set; }
|
public DateTime? MovementCompletesAtUtc { get; set; }
|
||||||
public string? SourceTrainingId { get; set; }
|
public string? SourceTrainingId { get; set; }
|
||||||
|
|||||||
@@ -337,6 +337,8 @@ public class LocationService
|
|||||||
.Set(x => x.MovementRemaining, 0)
|
.Set(x => x.MovementRemaining, 0)
|
||||||
.Set(x => x.DestinationQ, request.Q)
|
.Set(x => x.DestinationQ, request.Q)
|
||||||
.Set(x => x.DestinationR, request.R)
|
.Set(x => x.DestinationR, request.R)
|
||||||
|
.Set(x => x.WorksiteQ, request.Q)
|
||||||
|
.Set(x => x.WorksiteR, request.R)
|
||||||
.Set(x => x.MovementStartedAtUtc, now)
|
.Set(x => x.MovementStartedAtUtc, now)
|
||||||
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||||
.Set(x => x.UpdatedAtUtc, now));
|
.Set(x => x.UpdatedAtUtc, now));
|
||||||
@@ -360,11 +362,19 @@ public class LocationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _units.UpdateOneAsync(
|
await _units.UpdateOneAsync(
|
||||||
x => x.Id == location.WorkerUnitId && x.Username == username && x.Status == "Working",
|
x => x.Id == location.WorkerUnitId && x.Username == username,
|
||||||
Builders<UnitInstance>.Update
|
Builders<UnitInstance>.Update
|
||||||
.Set(x => x.Q, request.Q)
|
.Set(x => x.Q, request.Q)
|
||||||
.Set(x => x.R, request.R)
|
.Set(x => x.R, request.R)
|
||||||
.Set(x => x.Status, "Idle")
|
.Set(x => x.Status, "Idle")
|
||||||
|
.Unset(x => x.WorksiteQ)
|
||||||
|
.Unset(x => x.WorksiteR)
|
||||||
|
.Unset(x => x.DestinationQ)
|
||||||
|
.Unset(x => x.DestinationR)
|
||||||
|
.Unset(x => x.CarryingResourceType)
|
||||||
|
.Set(x => x.CarryingResourceAmount, 0)
|
||||||
|
.Unset(x => x.MovementStartedAtUtc)
|
||||||
|
.Unset(x => x.MovementCompletesAtUtc)
|
||||||
.Set(x => x.UpdatedAtUtc, now));
|
.Set(x => x.UpdatedAtUtc, now));
|
||||||
|
|
||||||
var updated = await _locations.FindOneAndUpdateAsync(
|
var updated = await _locations.FindOneAndUpdateAsync(
|
||||||
@@ -372,6 +382,7 @@ public class LocationService
|
|||||||
Builders<Location>.Update
|
Builders<Location>.Update
|
||||||
.Unset(x => x.WorkerUnitId)
|
.Unset(x => x.WorkerUnitId)
|
||||||
.Unset(x => x.WorkerUnitType)
|
.Unset(x => x.WorkerUnitType)
|
||||||
|
.Unset(x => x.DeliveryCycleStartedAtUtc)
|
||||||
.Set(x => x.UpdatedAtUtc, now),
|
.Set(x => x.UpdatedAtUtc, now),
|
||||||
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
||||||
|
|
||||||
@@ -404,6 +415,14 @@ public class LocationService
|
|||||||
.Set(x => x.R, r)
|
.Set(x => x.R, r)
|
||||||
.Set(x => x.Status, "Idle")
|
.Set(x => x.Status, "Idle")
|
||||||
.Set(x => x.MovementRemaining, 1)
|
.Set(x => x.MovementRemaining, 1)
|
||||||
|
.Unset(x => x.WorksiteQ)
|
||||||
|
.Unset(x => x.WorksiteR)
|
||||||
|
.Unset(x => x.DestinationQ)
|
||||||
|
.Unset(x => x.DestinationR)
|
||||||
|
.Unset(x => x.CarryingResourceType)
|
||||||
|
.Set(x => x.CarryingResourceAmount, 0)
|
||||||
|
.Unset(x => x.MovementStartedAtUtc)
|
||||||
|
.Unset(x => x.MovementCompletesAtUtc)
|
||||||
.Set(x => x.UpdatedAtUtc, now));
|
.Set(x => x.UpdatedAtUtc, now));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,6 +439,7 @@ public class LocationService
|
|||||||
.Set(x => x.StoredResourceAmount, 0)
|
.Set(x => x.StoredResourceAmount, 0)
|
||||||
.Set(x => x.StoredResourceCapacity, 10)
|
.Set(x => x.StoredResourceCapacity, 10)
|
||||||
.Unset(x => x.LastResourceGeneratedAtUtc)
|
.Unset(x => x.LastResourceGeneratedAtUtc)
|
||||||
|
.Unset(x => x.DeliveryCycleStartedAtUtc)
|
||||||
.Set(x => x.UpdatedAtUtc, now),
|
.Set(x => x.UpdatedAtUtc, now),
|
||||||
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
||||||
|
|
||||||
@@ -649,6 +669,7 @@ public class LocationService
|
|||||||
var currentQ = worker.Q;
|
var currentQ = worker.Q;
|
||||||
var currentR = worker.R;
|
var currentR = worker.R;
|
||||||
var elapsedSteps = Math.Max(1, (int)Math.Floor((now - worker.MovementCompletesAtUtc!.Value).TotalMinutes) + 1);
|
var elapsedSteps = Math.Max(1, (int)Math.Floor((now - worker.MovementCompletesAtUtc!.Value).TotalMinutes) + 1);
|
||||||
|
var usedSteps = 0;
|
||||||
var movementBlocked = false;
|
var movementBlocked = false;
|
||||||
|
|
||||||
while (elapsedSteps > 0 && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
while (elapsedSteps > 0 && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||||
@@ -672,6 +693,7 @@ public class LocationService
|
|||||||
currentQ = nextStep.Value.q;
|
currentQ = nextStep.Value.q;
|
||||||
currentR = nextStep.Value.r;
|
currentR = nextStep.Value.r;
|
||||||
elapsedSteps--;
|
elapsedSteps--;
|
||||||
|
usedSteps++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (movementBlocked)
|
if (movementBlocked)
|
||||||
@@ -689,6 +711,7 @@ public class LocationService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var assignedAt = worker.MovementCompletesAtUtc.Value.AddMinutes(Math.Max(0, usedSteps - 1));
|
||||||
var location = await _locations.FindOneAndUpdateAsync(
|
var location = await _locations.FindOneAndUpdateAsync(
|
||||||
x => x.OwnerUsername == username &&
|
x => x.OwnerUsername == username &&
|
||||||
x.Q == destinationQ &&
|
x.Q == destinationQ &&
|
||||||
@@ -699,7 +722,8 @@ public class LocationService
|
|||||||
Builders<Location>.Update
|
Builders<Location>.Update
|
||||||
.Set(x => x.WorkerUnitId, worker.Id)
|
.Set(x => x.WorkerUnitId, worker.Id)
|
||||||
.Set(x => x.WorkerUnitType, "Peasant")
|
.Set(x => x.WorkerUnitType, "Peasant")
|
||||||
.Set(x => x.LastResourceGeneratedAtUtc, now)
|
.Set(x => x.LastResourceGeneratedAtUtc, assignedAt)
|
||||||
|
.Set(x => x.DeliveryCycleStartedAtUtc, assignedAt)
|
||||||
.Set(x => x.UpdatedAtUtc, now),
|
.Set(x => x.UpdatedAtUtc, now),
|
||||||
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
||||||
|
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ public class ResourceService
|
|||||||
public async Task<PlayerResources> GetAsync(string username)
|
public async Task<PlayerResources> GetAsync(string username)
|
||||||
{
|
{
|
||||||
var resources = await EnsureAsync(username);
|
var resources = await EnsureAsync(username);
|
||||||
resources = await ApplyFoodTickAsync(resources);
|
resources = await ApplyProductionBuildingDeliveryAsync(resources);
|
||||||
return await ApplyProductionBuildingDeliveryAsync(resources, includeFood: false);
|
return await ApplyFoodTickAsync(resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> TrySpendGoldAsync(string username, int amount)
|
public async Task<bool> TrySpendGoldAsync(string username, int amount)
|
||||||
@@ -340,6 +340,7 @@ public class ResourceService
|
|||||||
(x.BuildingStatus == "Built" || x.BuildingStatus == null || x.BuildingStatus == "") &&
|
(x.BuildingStatus == "Built" || x.BuildingStatus == null || x.BuildingStatus == "") &&
|
||||||
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || (includeFood && x.BuildingType == "Farm")))
|
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || (includeFood && x.BuildingType == "Farm")))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
var home = await _locations.Find(x => x.OwnerUsername == resources.Username && x.Kind == "Home").FirstOrDefaultAsync();
|
||||||
|
|
||||||
var wood = Math.Min(resources.Wood, woodCapacity);
|
var wood = Math.Min(resources.Wood, woodCapacity);
|
||||||
var ore = Math.Min(resources.Ore, oreCapacity);
|
var ore = Math.Min(resources.Ore, oreCapacity);
|
||||||
@@ -347,6 +348,11 @@ public class ResourceService
|
|||||||
|
|
||||||
foreach (var building in buildings)
|
foreach (var building in buildings)
|
||||||
{
|
{
|
||||||
|
if (home is null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
var rate = building.BuildingType switch
|
var rate = building.BuildingType switch
|
||||||
{
|
{
|
||||||
"LogCamp" => logCampWoodPerMinute,
|
"LogCamp" => logCampWoodPerMinute,
|
||||||
@@ -355,29 +361,47 @@ public class ResourceService
|
|||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
var lastGenerated = building.LastResourceGeneratedAtUtc ?? building.BuildingBuiltAtUtc ?? now;
|
var lastGenerated = building.LastResourceGeneratedAtUtc ?? building.BuildingBuiltAtUtc ?? now;
|
||||||
|
var route = DirectRoute((building.Q, building.R), (home.Q, home.R));
|
||||||
|
var oneWayMinutes = Math.Max(1, route.Count - 1);
|
||||||
|
var cycleMinutes = Math.Max(1, oneWayMinutes * 2);
|
||||||
|
var cycleStarted = building.DeliveryCycleStartedAtUtc ?? lastGenerated;
|
||||||
var elapsedMinutes = rate <= 0 ? 0 : (int)Math.Floor((now - lastGenerated).TotalMinutes);
|
var elapsedMinutes = rate <= 0 ? 0 : (int)Math.Floor((now - lastGenerated).TotalMinutes);
|
||||||
var stored = Math.Min(buildingCapacity, Math.Max(0, building.StoredResourceAmount) + (elapsedMinutes * rate));
|
var stored = Math.Min(buildingCapacity, Math.Max(0, building.StoredResourceAmount));
|
||||||
|
|
||||||
var delivered = 0;
|
for (var minute = 1; minute <= elapsedMinutes; minute++)
|
||||||
if (building.BuildingType == "LogCamp")
|
|
||||||
{
|
{
|
||||||
delivered = Math.Min(stored, Math.Max(0, woodCapacity - wood));
|
var minuteAt = lastGenerated.AddMinutes(minute);
|
||||||
wood += delivered;
|
stored = Math.Min(buildingCapacity, stored + rate);
|
||||||
}
|
var cycleMinute = (int)Math.Floor((minuteAt - cycleStarted).TotalMinutes);
|
||||||
else if (building.BuildingType == "Mine")
|
if (cycleMinute < oneWayMinutes || (cycleMinute - oneWayMinutes) % cycleMinutes != 0)
|
||||||
{
|
{
|
||||||
delivered = Math.Min(stored, Math.Max(0, oreCapacity - ore));
|
continue;
|
||||||
ore += delivered;
|
}
|
||||||
}
|
|
||||||
else if (building.BuildingType == "Farm")
|
var delivered = 0;
|
||||||
{
|
if (building.BuildingType == "LogCamp")
|
||||||
delivered = Math.Min(stored, Math.Max(0, foodCapacity - food));
|
{
|
||||||
food += delivered;
|
delivered = Math.Min(stored, Math.Max(0, woodCapacity - wood));
|
||||||
|
wood += delivered;
|
||||||
|
}
|
||||||
|
else if (building.BuildingType == "Mine")
|
||||||
|
{
|
||||||
|
delivered = Math.Min(stored, Math.Max(0, oreCapacity - ore));
|
||||||
|
ore += delivered;
|
||||||
|
}
|
||||||
|
else if (building.BuildingType == "Farm")
|
||||||
|
{
|
||||||
|
delivered = Math.Min(stored, Math.Max(0, foodCapacity - food));
|
||||||
|
food += delivered;
|
||||||
|
}
|
||||||
|
|
||||||
|
stored -= delivered;
|
||||||
}
|
}
|
||||||
|
|
||||||
var update = Builders<Location>.Update
|
var update = Builders<Location>.Update
|
||||||
.Set(x => x.StoredResourceAmount, stored - delivered)
|
.Set(x => x.StoredResourceAmount, stored)
|
||||||
.Set(x => x.StoredResourceCapacity, buildingCapacity)
|
.Set(x => x.StoredResourceCapacity, buildingCapacity)
|
||||||
|
.Set(x => x.DeliveryCycleStartedAtUtc, cycleStarted)
|
||||||
.Set(x => x.UpdatedAtUtc, now);
|
.Set(x => x.UpdatedAtUtc, now);
|
||||||
|
|
||||||
if (elapsedMinutes > 0 || building.LastResourceGeneratedAtUtc is null)
|
if (elapsedMinutes > 0 || building.LastResourceGeneratedAtUtc is null)
|
||||||
@@ -386,6 +410,7 @@ public class ResourceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _locations.UpdateOneAsync(x => x.Id == building.Id, update);
|
await _locations.UpdateOneAsync(x => x.Id == building.Id, update);
|
||||||
|
await UpdateDeliveryWorkerStateAsync(resources.Username, building, home, route, cycleStarted, oneWayMinutes, cycleMinutes, stored, buildingCapacity, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _resources.FindOneAndUpdateAsync(
|
return await _resources.FindOneAndUpdateAsync(
|
||||||
@@ -408,6 +433,7 @@ public class ResourceService
|
|||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var unitFoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.UnitFoodPerMinute, _unitFoodPerMinute);
|
var unitFoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.UnitFoodPerMinute, _unitFoodPerMinute);
|
||||||
|
var directFoodProductionPerMinute = await CalculateDirectFoodProductionPerMinuteAsync(resources.Username);
|
||||||
var foodProductionPerMinute = await CalculateFoodProductionPerMinuteAsync(resources.Username);
|
var foodProductionPerMinute = await CalculateFoodProductionPerMinuteAsync(resources.Username);
|
||||||
var units = await GetFoodConsumingUnitsAsync(resources.Username);
|
var units = await GetFoodConsumingUnitsAsync(resources.Username);
|
||||||
var upkeepPerMinute = units.Count * unitFoodPerMinute;
|
var upkeepPerMinute = units.Count * unitFoodPerMinute;
|
||||||
@@ -421,9 +447,9 @@ public class ResourceService
|
|||||||
|
|
||||||
for (var minute = 0; minute < elapsedMinutes; minute++)
|
for (var minute = 0; minute < elapsedMinutes; minute++)
|
||||||
{
|
{
|
||||||
if (foodProductionPerMinute > 0)
|
if (directFoodProductionPerMinute > 0)
|
||||||
{
|
{
|
||||||
food = Math.Min(foodCapacity, food + foodProductionPerMinute);
|
food = Math.Min(foodCapacity, food + directFoodProductionPerMinute);
|
||||||
}
|
}
|
||||||
|
|
||||||
var neededFood = units.Count * unitFoodPerMinute;
|
var neededFood = units.Count * unitFoodPerMinute;
|
||||||
@@ -497,6 +523,82 @@ public class ResourceService
|
|||||||
return units;
|
return units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UpdateDeliveryWorkerStateAsync(
|
||||||
|
string username,
|
||||||
|
Location building,
|
||||||
|
Location home,
|
||||||
|
List<(int q, int r)> route,
|
||||||
|
DateTime cycleStarted,
|
||||||
|
int oneWayMinutes,
|
||||||
|
int cycleMinutes,
|
||||||
|
int remainingStored,
|
||||||
|
int carryCapacity,
|
||||||
|
DateTime now)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(building.WorkerUnitId) || route.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourceType = building.BuildingType switch
|
||||||
|
{
|
||||||
|
"LogCamp" => "Wood",
|
||||||
|
"Mine" => "Ore",
|
||||||
|
"Farm" => "Food",
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
|
if (resourceType == "")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var elapsedCycleMinutes = Math.Max(0, (int)Math.Floor((now - cycleStarted).TotalMinutes));
|
||||||
|
var phase = cycleMinutes <= 0 ? 0 : elapsedCycleMinutes % cycleMinutes;
|
||||||
|
var isDelivering = remainingStored > 0 && phase < oneWayMinutes;
|
||||||
|
var isReturning = phase >= oneWayMinutes;
|
||||||
|
if (!isDelivering && !isReturning)
|
||||||
|
{
|
||||||
|
await _units.UpdateOneAsync(
|
||||||
|
x => x.Id == building.WorkerUnitId && x.Username == username,
|
||||||
|
Builders<UnitInstance>.Update
|
||||||
|
.Set(x => x.Q, building.Q)
|
||||||
|
.Set(x => x.R, building.R)
|
||||||
|
.Set(x => x.Status, "Working")
|
||||||
|
.Set(x => x.WorksiteQ, building.Q)
|
||||||
|
.Set(x => x.WorksiteR, building.R)
|
||||||
|
.Unset(x => x.DestinationQ)
|
||||||
|
.Unset(x => x.DestinationR)
|
||||||
|
.Unset(x => x.CarryingResourceType)
|
||||||
|
.Set(x => x.CarryingResourceAmount, 0)
|
||||||
|
.Unset(x => x.MovementStartedAtUtc)
|
||||||
|
.Unset(x => x.MovementCompletesAtUtc)
|
||||||
|
.Set(x => x.UpdatedAtUtc, now));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var routeIndex = isDelivering
|
||||||
|
? Math.Min(route.Count - 1, phase)
|
||||||
|
: Math.Max(0, route.Count - 1 - Math.Min(route.Count - 1, phase - oneWayMinutes));
|
||||||
|
var position = route[routeIndex];
|
||||||
|
(int q, int r) destination = isDelivering ? (home.Q, home.R) : (building.Q, building.R);
|
||||||
|
|
||||||
|
await _units.UpdateOneAsync(
|
||||||
|
x => x.Id == building.WorkerUnitId && x.Username == username,
|
||||||
|
Builders<UnitInstance>.Update
|
||||||
|
.Set(x => x.Q, position.q)
|
||||||
|
.Set(x => x.R, position.r)
|
||||||
|
.Set(x => x.Status, isDelivering ? "DeliveringToTownHall" : "ReturningToWork")
|
||||||
|
.Set(x => x.WorksiteQ, building.Q)
|
||||||
|
.Set(x => x.WorksiteR, building.R)
|
||||||
|
.Set(x => x.DestinationQ, destination.q)
|
||||||
|
.Set(x => x.DestinationR, destination.r)
|
||||||
|
.Set(x => x.CarryingResourceType, isDelivering ? resourceType : (string?)null)
|
||||||
|
.Set(x => x.CarryingResourceAmount, isDelivering ? Math.Min(carryCapacity, remainingStored) : 0)
|
||||||
|
.Set(x => x.MovementStartedAtUtc, now)
|
||||||
|
.Set(x => x.MovementCompletesAtUtc, now.AddMinutes(1))
|
||||||
|
.Set(x => x.UpdatedAtUtc, now));
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> CalculateFoodProductionPerMinuteAsync(string username)
|
private async Task<int> CalculateFoodProductionPerMinuteAsync(string username)
|
||||||
{
|
{
|
||||||
var townHallFoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallFoodPerMinute, _townHallFoodPerMinute);
|
var townHallFoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallFoodPerMinute, _townHallFoodPerMinute);
|
||||||
@@ -514,6 +616,17 @@ public class ResourceService
|
|||||||
return (hasTownHall ? townHallFoodPerMinute : 0) + checked((int)farms) * farmFoodPerMinute;
|
return (hasTownHall ? townHallFoodPerMinute : 0) + checked((int)farms) * farmFoodPerMinute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> CalculateDirectFoodProductionPerMinuteAsync(string username)
|
||||||
|
{
|
||||||
|
var townHallFoodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallFoodPerMinute, _townHallFoodPerMinute);
|
||||||
|
var hasTownHall = await _locations.Find(x =>
|
||||||
|
x.OwnerUsername == username &&
|
||||||
|
x.Kind == "Home")
|
||||||
|
.AnyAsync();
|
||||||
|
|
||||||
|
return hasTownHall ? townHallFoodPerMinute : 0;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CompletePendingWorkerAssignmentsAsync(string username, DateTime now)
|
private async Task CompletePendingWorkerAssignmentsAsync(string username, DateTime now)
|
||||||
{
|
{
|
||||||
var movingWorkers = await _units.Find(x =>
|
var movingWorkers = await _units.Find(x =>
|
||||||
@@ -543,6 +656,7 @@ public class ResourceService
|
|||||||
var currentQ = worker.Q;
|
var currentQ = worker.Q;
|
||||||
var currentR = worker.R;
|
var currentR = worker.R;
|
||||||
var elapsedSteps = Math.Max(1, (int)Math.Floor((now - worker.MovementCompletesAtUtc!.Value).TotalMinutes) + 1);
|
var elapsedSteps = Math.Max(1, (int)Math.Floor((now - worker.MovementCompletesAtUtc!.Value).TotalMinutes) + 1);
|
||||||
|
var usedSteps = 0;
|
||||||
var movementBlocked = false;
|
var movementBlocked = false;
|
||||||
|
|
||||||
while (elapsedSteps > 0 && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
while (elapsedSteps > 0 && HexDistance(currentQ, currentR, destinationQ, destinationR) > 1)
|
||||||
@@ -566,6 +680,7 @@ public class ResourceService
|
|||||||
currentQ = nextStep.Value.q;
|
currentQ = nextStep.Value.q;
|
||||||
currentR = nextStep.Value.r;
|
currentR = nextStep.Value.r;
|
||||||
elapsedSteps--;
|
elapsedSteps--;
|
||||||
|
usedSteps++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (movementBlocked)
|
if (movementBlocked)
|
||||||
@@ -583,6 +698,7 @@ public class ResourceService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var assignedAt = worker.MovementCompletesAtUtc.Value.AddMinutes(Math.Max(0, usedSteps - 1));
|
||||||
var location = await _locations.FindOneAndUpdateAsync(
|
var location = await _locations.FindOneAndUpdateAsync(
|
||||||
x => x.OwnerUsername == username &&
|
x => x.OwnerUsername == username &&
|
||||||
x.Q == destinationQ &&
|
x.Q == destinationQ &&
|
||||||
@@ -593,7 +709,8 @@ public class ResourceService
|
|||||||
Builders<Location>.Update
|
Builders<Location>.Update
|
||||||
.Set(x => x.WorkerUnitId, worker.Id)
|
.Set(x => x.WorkerUnitId, worker.Id)
|
||||||
.Set(x => x.WorkerUnitType, "Peasant")
|
.Set(x => x.WorkerUnitType, "Peasant")
|
||||||
.Set(x => x.LastResourceGeneratedAtUtc, now)
|
.Set(x => x.LastResourceGeneratedAtUtc, assignedAt)
|
||||||
|
.Set(x => x.DeliveryCycleStartedAtUtc, assignedAt)
|
||||||
.Set(x => x.UpdatedAtUtc, now),
|
.Set(x => x.UpdatedAtUtc, now),
|
||||||
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
new FindOneAndUpdateOptions<Location> { ReturnDocument = ReturnDocument.After });
|
||||||
|
|
||||||
@@ -675,6 +792,25 @@ public class ResourceService
|
|||||||
yield return (q, r + 1);
|
yield return (q, r + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<(int q, int r)> DirectRoute((int q, int r) start, (int q, int r) target)
|
||||||
|
{
|
||||||
|
var route = new List<(int q, int r)> { start };
|
||||||
|
var current = start;
|
||||||
|
var guard = 0;
|
||||||
|
while (current != target && guard < 128)
|
||||||
|
{
|
||||||
|
current = NeighborCoordinates(current.q, current.r)
|
||||||
|
.OrderBy(x => HexDistance(x.q, x.r, target.q, target.r))
|
||||||
|
.ThenBy(x => x.q)
|
||||||
|
.ThenBy(x => x.r)
|
||||||
|
.First();
|
||||||
|
route.Add(current);
|
||||||
|
guard++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
private static int HexDistance(int q1, int r1, int q2, int r2)
|
private static int HexDistance(int q1, int r1, int q2, int r2)
|
||||||
{
|
{
|
||||||
var s1 = -q1 - r1;
|
var s1 = -q1 - r1;
|
||||||
@@ -713,6 +849,7 @@ public class ResourceService
|
|||||||
Builders<Location>.Update
|
Builders<Location>.Update
|
||||||
.Unset(x => x.WorkerUnitId)
|
.Unset(x => x.WorkerUnitId)
|
||||||
.Unset(x => x.WorkerUnitType)
|
.Unset(x => x.WorkerUnitType)
|
||||||
|
.Unset(x => x.DeliveryCycleStartedAtUtc)
|
||||||
.Set(x => x.UpdatedAtUtc, now));
|
.Set(x => x.UpdatedAtUtc, now));
|
||||||
await _units.DeleteManyAsync(x =>
|
await _units.DeleteManyAsync(x =>
|
||||||
x.Username == username &&
|
x.Username == username &&
|
||||||
|
|||||||
Reference in New Issue
Block a user