territory claiming modification
This commit is contained in:
@@ -677,7 +677,7 @@ func _confirm_scout_claim() -> void:
|
||||
if pending_move_q == 9999:
|
||||
return
|
||||
if not _can_claim_tile(pending_move_q, pending_move_r):
|
||||
coordinate_label.text = "Scouts can only claim visible unclaimed territory adjacent to controlled territory."
|
||||
coordinate_label.text = "Scouts can only claim visible neutral or enemy territory adjacent to controlled territory."
|
||||
return
|
||||
selected_q = pending_move_q
|
||||
selected_r = pending_move_r
|
||||
@@ -804,8 +804,9 @@ func _can_claim_tile(q: int, r: int) -> bool:
|
||||
if location.is_empty():
|
||||
return false
|
||||
|
||||
var username: String = str(session.get("username", ""))
|
||||
var owner_username: String = _nullable_string(location.get("ownerUsername", ""))
|
||||
return owner_username.is_empty() and grid_view.has_owned_neighbor(q, r)
|
||||
return owner_username != username and grid_view.has_owned_neighbor(q, r)
|
||||
|
||||
|
||||
func _update_action_buttons() -> void:
|
||||
|
||||
@@ -100,19 +100,22 @@ public class LocationsController : ControllerBase
|
||||
{
|
||||
return Ok(LocationResponse.FromLocation(existingLocation));
|
||||
}
|
||||
}
|
||||
|
||||
return Conflict("Location is already controlled by another player.");
|
||||
if (!User.IsInRole("SUPER") && !await _locations.CanScoutClaimAsync(username, request.Q, request.R))
|
||||
{
|
||||
return BadRequest("Scouts can only claim neutral territory or empty enemy territory without units or buildings.");
|
||||
}
|
||||
|
||||
if (!User.IsInRole("SUPER") && !await _units.TryConsumeCompletedScoutAsync(username))
|
||||
{
|
||||
return BadRequest("A completed scout is required to claim unclaimed territory.");
|
||||
return BadRequest("A completed scout is required to claim territory.");
|
||||
}
|
||||
|
||||
var location = await _locations.ClaimAsync(request.Q, request.R, username);
|
||||
if (location is null)
|
||||
{
|
||||
return Conflict("Location is already controlled by another player.");
|
||||
return Conflict("Location cannot be claimed while occupied or built up.");
|
||||
}
|
||||
|
||||
return Ok(LocationResponse.FromLocation(location));
|
||||
|
||||
@@ -145,8 +145,12 @@ public class LocationService
|
||||
var existing = await GetAsync(q, r);
|
||||
if (existing is not null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(existing.OwnerUsername) &&
|
||||
!string.Equals(existing.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(existing.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return existing;
|
||||
}
|
||||
|
||||
if (!await CanScoutClaimAsync(username, q, r))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -164,6 +168,26 @@ public class LocationService
|
||||
return await UpsertAsync(new UpsertLocationRequest { Q = q, R = r, Terrain = "Field" }, username);
|
||||
}
|
||||
|
||||
public async Task<bool> CanScoutClaimAsync(string username, int q, int r)
|
||||
{
|
||||
var existing = await GetAsync(q, r);
|
||||
if (existing is not null)
|
||||
{
|
||||
if (string.Equals(existing.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string.Equals(existing.Kind, "Home", StringComparison.OrdinalIgnoreCase) ||
|
||||
!string.IsNullOrWhiteSpace(existing.BuildingType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !await _units.Find(x => x.Q == q && x.R == r).AnyAsync();
|
||||
}
|
||||
|
||||
public async Task<Location?> BuildAsync(BuildLocationRequest request, string username)
|
||||
{
|
||||
var buildingType = NormalizeBuildingType(request.BuildingType);
|
||||
|
||||
@@ -375,10 +375,6 @@ public class UnitTrainingService
|
||||
.Unset(x => x.MovementCompletesAtUtc)
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
|
||||
if (unit.UnitType == ArcherUnitType)
|
||||
{
|
||||
await ClaimTargetIfEmptyAsync(username, destinationQ, destinationR, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,64 +499,6 @@ public class UnitTrainingService
|
||||
return step == start ? target : step;
|
||||
}
|
||||
|
||||
private async Task ClaimTargetIfEmptyAsync(string username, int q, int r, DateTime now)
|
||||
{
|
||||
var hasOtherUnits = await _units.Find(x => x.Username != username && x.Q == q && x.R == r).AnyAsync();
|
||||
var target = await _locations.Find(x => x.Q == q && x.R == r).FirstOrDefaultAsync();
|
||||
var hasBuilding = target is not null &&
|
||||
(!string.IsNullOrWhiteSpace(target.BuildingType) ||
|
||||
string.Equals(target.Kind, "Home", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (hasOtherUnits || hasBuilding)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (target is null)
|
||||
{
|
||||
var location = new Location
|
||||
{
|
||||
Q = q,
|
||||
R = r,
|
||||
Terrain = "Field",
|
||||
Kind = "Claimed",
|
||||
OwnerUsername = username,
|
||||
Level = 1,
|
||||
CreatedAtUtc = now,
|
||||
UpdatedAtUtc = now
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await _locations.InsertOneAsync(location);
|
||||
}
|
||||
catch (MongoWriteException)
|
||||
{
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(target.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var capturableFilter = Builders<Location>.Filter.And(
|
||||
Builders<Location>.Filter.Eq(x => x.Id, target.Id),
|
||||
Builders<Location>.Filter.Ne(x => x.Kind, "Home"),
|
||||
Builders<Location>.Filter.Or(
|
||||
Builders<Location>.Filter.Eq(x => x.BuildingType, null),
|
||||
Builders<Location>.Filter.Eq(x => x.BuildingType, "")));
|
||||
|
||||
await _locations.UpdateOneAsync(
|
||||
capturableFilter,
|
||||
Builders<Location>.Update
|
||||
.Set(x => x.OwnerUsername, username)
|
||||
.Set(x => x.Kind, "Claimed")
|
||||
.Set(x => x.UpdatedAtUtc, now));
|
||||
}
|
||||
|
||||
private static int HexDistance(int q1, int r1, int q2, int r2)
|
||||
{
|
||||
var s1 = -q1 - r1;
|
||||
|
||||
Reference in New Issue
Block a user