Adding barracks

This commit is contained in:
hz
2026-05-19 04:42:57 -05:00
parent 34d406e993
commit 78513603ab
10 changed files with 556 additions and 152 deletions
@@ -15,6 +15,10 @@ public class LocationService
private readonly int _mineOrePerMinute;
private readonly int _defaultLogCampBuildSeconds;
private readonly int _defaultMineBuildSeconds;
private readonly int _defaultBarracksBuildSeconds;
private readonly int _barracksGoldCost;
private readonly int _barracksWoodCost;
private readonly int _barracksOreCost;
public LocationService(IConfiguration cfg, ResourceService resources, GameSettingsService settings)
{
@@ -40,6 +44,18 @@ public class LocationService
_defaultMineBuildSeconds = int.TryParse(cfg["Buildings:MineBuildSeconds"], out var mineBuildSeconds)
? Math.Max(1, mineBuildSeconds)
: 60;
_defaultBarracksBuildSeconds = int.TryParse(cfg["Buildings:BarracksBuildSeconds"], out var barracksBuildSeconds)
? Math.Max(1, barracksBuildSeconds)
: 60;
_barracksGoldCost = int.TryParse(cfg["Buildings:BarracksGoldCost"], out var barracksGoldCost)
? Math.Max(0, barracksGoldCost)
: 500;
_barracksWoodCost = int.TryParse(cfg["Buildings:BarracksWoodCost"], out var barracksWoodCost)
? Math.Max(0, barracksWoodCost)
: 100;
_barracksOreCost = int.TryParse(cfg["Buildings:BarracksOreCost"], out var barracksOreCost)
? Math.Max(0, barracksOreCost)
: 100;
var coordinateIndex = Builders<Location>.IndexKeys
.Ascending(x => x.Q)
@@ -149,8 +165,8 @@ public class LocationService
throw new InvalidOperationException("This location already has a building or construction in progress.");
}
var requiredTerrain = buildingType == "LogCamp" ? "Forest" : "Ore";
if (!string.Equals(location.Terrain, requiredTerrain, StringComparison.OrdinalIgnoreCase))
var requiredTerrain = RequiredTerrainForBuilding(buildingType);
if (requiredTerrain is not null && !string.Equals(location.Terrain, requiredTerrain, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException($"{buildingType} can only be built on {requiredTerrain} territory.");
}
@@ -158,12 +174,8 @@ public class LocationService
await CompleteFinishedBuildingsAsync(username);
var now = DateTime.UtcNow;
var settingKey = buildingType == "LogCamp"
? GameSettingsService.LogCampBuildSeconds
: GameSettingsService.MineBuildSeconds;
var defaultBuildSeconds = buildingType == "LogCamp"
? _defaultLogCampBuildSeconds
: _defaultMineBuildSeconds;
var settingKey = BuildSecondsSettingKey(buildingType);
var defaultBuildSeconds = DefaultBuildSeconds(buildingType);
var buildSeconds = await _settings.GetIntAsync(settingKey, defaultBuildSeconds);
var update = Builders<Location>.Update
.Set(x => x.BuildingType, buildingType)
@@ -173,7 +185,7 @@ public class LocationService
.Set(x => x.UpdatedAtUtc, now);
var updated = await _locations.FindOneAndUpdateAsync(
x => x.Id == location.Id && x.OwnerUsername == username && x.BuildingType == null,
x => x.Id == location.Id && x.OwnerUsername == username && (x.BuildingType == null || x.BuildingType == ""),
update,
new FindOneAndUpdateOptions<Location>
{
@@ -185,6 +197,27 @@ public class LocationService
throw new InvalidOperationException("This location already has a building or construction in progress.");
}
if (buildingType == "Barracks")
{
var spent = await _resources.TrySpendResourcesAsync(username, _barracksGoldCost, _barracksWoodCost, _barracksOreCost);
if (!spent)
{
var rollback = Builders<Location>.Update
.Unset(x => x.BuildingType)
.Unset(x => x.BuildingStatus)
.Unset(x => x.BuildingStartedAtUtc)
.Unset(x => x.BuildingCompletesAtUtc)
.Unset(x => x.BuildingBuiltAtUtc)
.Set(x => x.UpdatedAtUtc, DateTime.UtcNow);
await _locations.UpdateOneAsync(
x => x.Id == updated.Id && x.BuildingType == "Barracks" && x.BuildingStatus == "Building" && x.BuildingStartedAtUtc == now,
rollback);
throw new InvalidOperationException($"Not enough resources to build Barracks. Required: {_barracksGoldCost} gold, {_barracksWoodCost} wood, {_barracksOreCost} ore.");
}
}
return updated;
}
@@ -193,7 +226,7 @@ public class LocationService
var now = DateTime.UtcNow;
var readyBuildings = await _locations.Find(x =>
x.OwnerUsername == username &&
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine") &&
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Barracks") &&
x.BuildingStatus == "Building" &&
x.BuildingCompletesAtUtc <= now)
.ToListAsync();
@@ -353,6 +386,15 @@ public class LocationService
return ownedLocations.Any(owned => HexDistance(owned.Q, owned.R, q, r) <= _visibilityDepth);
}
public async Task<bool> IsAdjacentToOwnedAsync(string username, int q, int r)
{
var neighbors = NeighborCoordinates(q, r).ToList();
return await _locations.Find(x =>
x.OwnerUsername == username &&
neighbors.Any(n => n.Q == x.Q && n.R == x.R))
.AnyAsync();
}
private async Task<Location?> TryCreateHomeAsync(string username, int q, int r)
{
var now = DateTime.UtcNow;
@@ -582,7 +624,35 @@ public class LocationService
{
"logcamp" or "log camp" => "LogCamp",
"mine" => "Mine",
"barracks" => "Barracks",
_ => null
};
}
private static string? RequiredTerrainForBuilding(string buildingType) =>
buildingType switch
{
"LogCamp" => "Forest",
"Mine" => "Ore",
"Barracks" => null,
_ => null
};
private static string BuildSecondsSettingKey(string buildingType) =>
buildingType switch
{
"LogCamp" => GameSettingsService.LogCampBuildSeconds,
"Mine" => GameSettingsService.MineBuildSeconds,
"Barracks" => GameSettingsService.BarracksBuildSeconds,
_ => GameSettingsService.LogCampBuildSeconds
};
private int DefaultBuildSeconds(string buildingType) =>
buildingType switch
{
"LogCamp" => _defaultLogCampBuildSeconds,
"Mine" => _defaultMineBuildSeconds,
"Barracks" => _defaultBarracksBuildSeconds,
_ => 60
};
}