updates
This commit is contained in:
@@ -87,6 +87,10 @@ public class LocationsController : ControllerBase
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!User.IsInRole("SUPER"))
|
||||
{
|
||||
return BadRequest("Use a Scout move order to claim territory on arrival.");
|
||||
}
|
||||
|
||||
if (!User.IsInRole("SUPER") && !await _locations.IsAdjacentToOwnedAsync(username, request.Q, request.R))
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ public class MoveUnitSquadRequest
|
||||
public int FromR { get; set; }
|
||||
public int ToQ { get; set; }
|
||||
public int ToR { get; set; }
|
||||
public bool ClaimOnArrival { get; set; }
|
||||
}
|
||||
|
||||
public class DismissUnitSquadRequest
|
||||
@@ -75,6 +76,7 @@ public class UnitInstanceResponse
|
||||
public DateTime LastMovementRefillAtUtc { get; set; }
|
||||
public int? DestinationQ { get; set; }
|
||||
public int? DestinationR { get; set; }
|
||||
public bool ClaimOnArrival { get; set; }
|
||||
public DateTime? MovementStartedAtUtc { get; set; }
|
||||
public DateTime? MovementCompletesAtUtc { get; set; }
|
||||
public DateTime CreatedAtUtc { get; set; }
|
||||
@@ -93,6 +95,7 @@ public class UnitInstanceResponse
|
||||
LastMovementRefillAtUtc = unit.LastMovementRefillAtUtc,
|
||||
DestinationQ = unit.DestinationQ,
|
||||
DestinationR = unit.DestinationR,
|
||||
ClaimOnArrival = unit.ClaimOnArrival,
|
||||
MovementStartedAtUtc = unit.MovementStartedAtUtc,
|
||||
MovementCompletesAtUtc = unit.MovementCompletesAtUtc,
|
||||
CreatedAtUtc = unit.CreatedAtUtc,
|
||||
|
||||
@@ -19,6 +19,7 @@ public class UnitInstance
|
||||
public DateTime LastMovementRefillAtUtc { get; set; } = DateTime.UtcNow;
|
||||
public int? DestinationQ { get; set; }
|
||||
public int? DestinationR { get; set; }
|
||||
public bool ClaimOnArrival { get; set; }
|
||||
public DateTime? MovementStartedAtUtc { get; set; }
|
||||
public DateTime? MovementCompletesAtUtc { get; set; }
|
||||
public string? SourceTrainingId { get; set; }
|
||||
|
||||
@@ -190,6 +190,10 @@ public class UnitTrainingService
|
||||
{
|
||||
throw new ArgumentException("Only Scouts, Archers, and Peasants can be moved right now.", nameof(request.UnitType));
|
||||
}
|
||||
if (request.ClaimOnArrival && normalizedUnitType != ScoutUnitType)
|
||||
{
|
||||
throw new ArgumentException("Only Scouts can claim territory.", nameof(request.ClaimOnArrival));
|
||||
}
|
||||
|
||||
if (request.FromQ == request.ToQ && request.FromR == request.ToR)
|
||||
{
|
||||
@@ -206,6 +210,10 @@ public class UnitTrainingService
|
||||
{
|
||||
throw new InvalidOperationException("Peasants can only move within your controlled territory.");
|
||||
}
|
||||
if (request.ClaimOnArrival && !await IsAdjacentToOwnedAsync(username, request.ToQ, request.ToR))
|
||||
{
|
||||
throw new InvalidOperationException("Scout claims must target territory adjacent to controlled territory.");
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var unitFilter = Builders<UnitInstance>.Filter.And(
|
||||
@@ -234,26 +242,24 @@ public class UnitTrainingService
|
||||
throw new InvalidOperationException("That squad has no movement remaining this tick.");
|
||||
}
|
||||
|
||||
var movingUnitIds = request.ClaimOnArrival
|
||||
? units.OrderBy(x => x.Id).Take(1).Select(x => x.Id).ToList()
|
||||
: units.Select(x => x.Id).ToList();
|
||||
var movementCompletesAt = now.AddMinutes(1);
|
||||
await _units.UpdateManyAsync(
|
||||
unitFilter,
|
||||
Builders<UnitInstance>.Filter.In(x => x.Id, movingUnitIds),
|
||||
Builders<UnitInstance>.Update
|
||||
.Set(x => x.Status, "Moving")
|
||||
.Inc(x => x.MovementRemaining, -1)
|
||||
.Set(x => x.DestinationQ, request.ToQ)
|
||||
.Set(x => x.DestinationR, request.ToR)
|
||||
.Set(x => x.ClaimOnArrival, request.ClaimOnArrival)
|
||||
.Set(x => x.MovementStartedAtUtc, now)
|
||||
.Set(x => x.MovementCompletesAtUtc, movementCompletesAt)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
|
||||
return await _units.Find(x =>
|
||||
x.Username == username &&
|
||||
x.UnitType == normalizedUnitType &&
|
||||
x.Status == "Moving" &&
|
||||
x.Q == request.FromQ &&
|
||||
x.R == request.FromR &&
|
||||
x.DestinationQ == request.ToQ &&
|
||||
x.DestinationR == request.ToR)
|
||||
movingUnitIds.Contains(x.Id))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
@@ -310,6 +316,7 @@ public class UnitTrainingService
|
||||
.Set(x => x.Status, "Idle")
|
||||
.Set(x => x.MovementPerTick, movementPerTick)
|
||||
.Set(x => x.MovementRemaining, movementPerTick)
|
||||
.Set(x => x.ClaimOnArrival, false)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
@@ -331,6 +338,7 @@ public class UnitTrainingService
|
||||
.Set(x => x.MovementRemaining, movementPerTick)
|
||||
.Unset(x => x.DestinationQ)
|
||||
.Unset(x => x.DestinationR)
|
||||
.Set(x => x.ClaimOnArrival, false)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
@@ -371,10 +379,16 @@ public class UnitTrainingService
|
||||
.Set(x => x.LastMovementRefillAtUtc, now)
|
||||
.Unset(x => x.DestinationQ)
|
||||
.Unset(x => x.DestinationR)
|
||||
.Set(x => x.ClaimOnArrival, false)
|
||||
.Unset(x => x.MovementStartedAtUtc)
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
|
||||
if (unit.UnitType == ScoutUnitType && unit.ClaimOnArrival)
|
||||
{
|
||||
await TryClaimWithArrivedScoutAsync(unit, destinationQ, destinationR, now);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,6 +423,84 @@ public class UnitTrainingService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsAdjacentToOwnedAsync(string username, int q, int r)
|
||||
{
|
||||
var owned = await _locations.Find(x => x.OwnerUsername == username).ToListAsync();
|
||||
return owned.Any(location => HexDistance(location.Q, location.R, q, r) == 1);
|
||||
}
|
||||
|
||||
private async Task TryClaimWithArrivedScoutAsync(UnitInstance scout, int q, int r, DateTime now)
|
||||
{
|
||||
var target = await _locations.Find(x => x.Q == q && x.R == r).FirstOrDefaultAsync();
|
||||
if (target is not null)
|
||||
{
|
||||
if (string.Equals(target.OwnerUsername, scout.Username, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(target.Kind, "Home", StringComparison.OrdinalIgnoreCase) ||
|
||||
!string.IsNullOrWhiteSpace(target.BuildingType))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var hasBlockingUnit = await _units.Find(x =>
|
||||
x.Id != scout.Id &&
|
||||
x.Q == q &&
|
||||
x.R == r)
|
||||
.AnyAsync();
|
||||
if (hasBlockingUnit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await IsAdjacentToOwnedAsync(scout.Username, q, r))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var claimed = false;
|
||||
if (target is null)
|
||||
{
|
||||
var location = new Location
|
||||
{
|
||||
Q = q,
|
||||
R = r,
|
||||
Terrain = "Field",
|
||||
Kind = "Claimed",
|
||||
OwnerUsername = scout.Username,
|
||||
Level = 1,
|
||||
CreatedAtUtc = now,
|
||||
UpdatedAtUtc = now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await _locations.InsertOneAsync(location);
|
||||
claimed = true;
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await _locations.UpdateOneAsync(
|
||||
x => x.Id == target.Id &&
|
||||
x.Kind != "Home" &&
|
||||
(x.BuildingType == null || x.BuildingType == "") &&
|
||||
x.OwnerUsername != scout.Username,
|
||||
Builders<Location>.Update
|
||||
.Set(x => x.OwnerUsername, scout.Username)
|
||||
.Set(x => x.Kind, "Claimed")
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
claimed = result.ModifiedCount > 0;
|
||||
}
|
||||
|
||||
if (claimed)
|
||||
{
|
||||
await _units.DeleteOneAsync(x => x.Id == scout.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CompleteFinishedBuildingsAsync(string username)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
Reference in New Issue
Block a user