territory claiming
This commit is contained in:
@@ -11,10 +11,12 @@ namespace LocationsApi.Controllers;
|
||||
public class LocationsController : ControllerBase
|
||||
{
|
||||
private readonly LocationService _locations;
|
||||
private readonly UnitTrainingService _units;
|
||||
|
||||
public LocationsController(LocationService locations)
|
||||
public LocationsController(LocationService locations, UnitTrainingService units)
|
||||
{
|
||||
_locations = locations;
|
||||
_units = units;
|
||||
}
|
||||
|
||||
[Authorize(Roles = "USER,SUPER")]
|
||||
@@ -86,6 +88,22 @@ public class LocationsController : ControllerBase
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var existingLocation = await _locations.GetAsync(request.Q, request.R);
|
||||
if (existingLocation is not null && !string.IsNullOrWhiteSpace(existingLocation.OwnerUsername))
|
||||
{
|
||||
if (string.Equals(existingLocation.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Ok(LocationResponse.FromLocation(existingLocation));
|
||||
}
|
||||
|
||||
return Conflict("Location is already controlled by another player.");
|
||||
}
|
||||
|
||||
if (!User.IsInRole("SUPER") && !await _units.TryConsumeCompletedScoutAsync(username))
|
||||
{
|
||||
return BadRequest("A completed scout is required to claim unclaimed territory.");
|
||||
}
|
||||
|
||||
var location = await _locations.ClaimAsync(request.Q, request.R, username);
|
||||
if (location is null)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ Tracks hex locations for the territory map.
|
||||
- `GET /api/locations` List visible locations for USER/SUPER, all known locations for SUPER.
|
||||
- `GET /api/locations?minQ=-7&maxQ=7&minR=-7&maxR=7` List a coordinate range, constrained by visibility for USER.
|
||||
- `GET /api/locations/{q}/{r}` Fetch one visible location for USER, any known location for SUPER.
|
||||
- `POST /api/locations/claim` Claim a location for the authenticated user.
|
||||
- `POST /api/locations/claim` Claim visible unclaimed territory for the authenticated user. Normal players spend one completed Scout.
|
||||
- `GET /api/locations/home` Get the authenticated user's home location.
|
||||
- `POST /api/locations/home` Assign or return the authenticated user's home location.
|
||||
- `GET /api/locations/visible` Get locations visible to the authenticated user.
|
||||
@@ -33,4 +33,5 @@ minute. Generation is applied lazily when the resource record is read.
|
||||
|
||||
Unit training is stored server-side in the `UnitTraining` collection. The first
|
||||
unit type is `Scout`, which costs 50 gold and takes 60 seconds to train.
|
||||
Finished training is completed lazily when unit state is read.
|
||||
Finished training is completed lazily when unit state is read. Claiming an
|
||||
unclaimed visible location consumes one completed Scout.
|
||||
|
||||
@@ -78,6 +78,33 @@ public class UnitTrainingService
|
||||
return training;
|
||||
}
|
||||
|
||||
public async Task<bool> TryConsumeCompletedScoutAsync(string username)
|
||||
{
|
||||
await CompleteFinishedTrainingAsync(username);
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var update = Builders<UnitTraining>.Update
|
||||
.Set(x => x.Status, "Consumed")
|
||||
.Set(x => x.UpdatedAtUtc, now);
|
||||
|
||||
var consumed = await _training.FindOneAndUpdateAsync(
|
||||
x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Completed",
|
||||
update,
|
||||
new FindOneAndUpdateOptions<UnitTraining>
|
||||
{
|
||||
Sort = Builders<UnitTraining>.Sort.Ascending(x => x.CompletedAtUtc).Ascending(x => x.CreatedAtUtc),
|
||||
ReturnDocument = ReturnDocument.After
|
||||
});
|
||||
|
||||
return consumed is not null;
|
||||
}
|
||||
|
||||
public async Task<bool> HasCompletedScoutAsync(string username)
|
||||
{
|
||||
await CompleteFinishedTrainingAsync(username);
|
||||
return await _training.Find(x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Completed").AnyAsync();
|
||||
}
|
||||
|
||||
private async Task CompleteFinishedTrainingAsync(string username)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
Reference in New Issue
Block a user