territory claiming modification
This commit is contained in:
@@ -677,7 +677,7 @@ func _confirm_scout_claim() -> void:
|
|||||||
if pending_move_q == 9999:
|
if pending_move_q == 9999:
|
||||||
return
|
return
|
||||||
if not _can_claim_tile(pending_move_q, pending_move_r):
|
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
|
return
|
||||||
selected_q = pending_move_q
|
selected_q = pending_move_q
|
||||||
selected_r = pending_move_r
|
selected_r = pending_move_r
|
||||||
@@ -804,8 +804,9 @@ func _can_claim_tile(q: int, r: int) -> bool:
|
|||||||
if location.is_empty():
|
if location.is_empty():
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
var username: String = str(session.get("username", ""))
|
||||||
var owner_username: String = _nullable_string(location.get("ownerUsername", ""))
|
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:
|
func _update_action_buttons() -> void:
|
||||||
|
|||||||
@@ -100,19 +100,22 @@ public class LocationsController : ControllerBase
|
|||||||
{
|
{
|
||||||
return Ok(LocationResponse.FromLocation(existingLocation));
|
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))
|
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);
|
var location = await _locations.ClaimAsync(request.Q, request.R, username);
|
||||||
if (location is null)
|
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));
|
return Ok(LocationResponse.FromLocation(location));
|
||||||
|
|||||||
@@ -145,8 +145,12 @@ public class LocationService
|
|||||||
var existing = await GetAsync(q, r);
|
var existing = await GetAsync(q, r);
|
||||||
if (existing is not null)
|
if (existing is not null)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(existing.OwnerUsername) &&
|
if (string.Equals(existing.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
||||||
!string.Equals(existing.OwnerUsername, username, StringComparison.OrdinalIgnoreCase))
|
{
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await CanScoutClaimAsync(username, q, r))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -164,6 +168,26 @@ public class LocationService
|
|||||||
return await UpsertAsync(new UpsertLocationRequest { Q = q, R = r, Terrain = "Field" }, username);
|
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)
|
public async Task<Location?> BuildAsync(BuildLocationRequest request, string username)
|
||||||
{
|
{
|
||||||
var buildingType = NormalizeBuildingType(request.BuildingType);
|
var buildingType = NormalizeBuildingType(request.BuildingType);
|
||||||
|
|||||||
@@ -375,10 +375,6 @@ public class UnitTrainingService
|
|||||||
.Unset(x => x.MovementCompletesAtUtc)
|
.Unset(x => x.MovementCompletesAtUtc)
|
||||||
.Set(x => x.UpdatedAtUtc, now));
|
.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;
|
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)
|
private static int HexDistance(int q1, int r1, int q2, int r2)
|
||||||
{
|
{
|
||||||
var s1 = -q1 - r1;
|
var s1 = -q1 - r1;
|
||||||
|
|||||||
Reference in New Issue
Block a user