adding farms
This commit is contained in:
@@ -28,7 +28,7 @@ var escape_panel: PanelContainer
|
|||||||
var gold_label: Label
|
var gold_label: Label
|
||||||
var tick_bar: ProgressBar
|
var tick_bar: ProgressBar
|
||||||
var tick_label: Label
|
var tick_label: Label
|
||||||
var resource_text := "Gold: --\nWood: --\nOre: --"
|
var resource_text := "Gold: --\nWood: --\nOre: --\nFood: --"
|
||||||
var gold_tick_anchor_unix := 0.0
|
var gold_tick_anchor_unix := 0.0
|
||||||
var gold_tick_seconds := 60.0
|
var gold_tick_seconds := 60.0
|
||||||
var train_button: Button
|
var train_button: Button
|
||||||
@@ -53,6 +53,7 @@ var active_training_label := "Training"
|
|||||||
var claim_button: Button
|
var claim_button: Button
|
||||||
var build_log_camp_button: Button
|
var build_log_camp_button: Button
|
||||||
var build_mine_button: Button
|
var build_mine_button: Button
|
||||||
|
var build_farm_button: Button
|
||||||
var build_barracks_button: Button
|
var build_barracks_button: Button
|
||||||
var unit_action_popup: PopupPanel
|
var unit_action_popup: PopupPanel
|
||||||
var unit_action_move_button: Button
|
var unit_action_move_button: Button
|
||||||
@@ -61,6 +62,7 @@ var selected_r := 0
|
|||||||
var selected_can_claim := false
|
var selected_can_claim := false
|
||||||
var selected_can_build_log_camp := false
|
var selected_can_build_log_camp := false
|
||||||
var selected_can_build_mine := false
|
var selected_can_build_mine := false
|
||||||
|
var selected_can_build_farm := false
|
||||||
var selected_can_build_barracks := false
|
var selected_can_build_barracks := false
|
||||||
var selected_can_train_archer := false
|
var selected_can_train_archer := false
|
||||||
var selected_is_home := false
|
var selected_is_home := false
|
||||||
@@ -236,6 +238,11 @@ func _build_ui() -> void:
|
|||||||
build_mine_button.pressed.connect(_build_mine)
|
build_mine_button.pressed.connect(_build_mine)
|
||||||
action_buttons.add_child(build_mine_button)
|
action_buttons.add_child(build_mine_button)
|
||||||
|
|
||||||
|
build_farm_button = _small_button("Build Farm")
|
||||||
|
build_farm_button.visible = false
|
||||||
|
build_farm_button.pressed.connect(_build_farm)
|
||||||
|
action_buttons.add_child(build_farm_button)
|
||||||
|
|
||||||
build_barracks_button = _small_button("Build Barracks")
|
build_barracks_button = _small_button("Build Barracks")
|
||||||
build_barracks_button.visible = false
|
build_barracks_button.visible = false
|
||||||
build_barracks_button.pressed.connect(_build_barracks)
|
build_barracks_button.pressed.connect(_build_barracks)
|
||||||
@@ -455,6 +462,7 @@ func _on_tile_selected(q: int, r: int, terrain: String) -> void:
|
|||||||
selected_is_home = _selected_tile_is_home()
|
selected_is_home = _selected_tile_is_home()
|
||||||
selected_can_build_log_camp = _can_build_log_camp_on_selected_tile()
|
selected_can_build_log_camp = _can_build_log_camp_on_selected_tile()
|
||||||
selected_can_build_mine = _can_build_mine_on_selected_tile()
|
selected_can_build_mine = _can_build_mine_on_selected_tile()
|
||||||
|
selected_can_build_farm = _can_build_farm_on_selected_tile()
|
||||||
selected_can_build_barracks = _can_build_barracks_on_selected_tile()
|
selected_can_build_barracks = _can_build_barracks_on_selected_tile()
|
||||||
selected_can_train_archer = _selected_tile_has_built_barracks()
|
selected_can_train_archer = _selected_tile_has_built_barracks()
|
||||||
_update_action_buttons()
|
_update_action_buttons()
|
||||||
@@ -532,6 +540,10 @@ func _can_build_mine_on_selected_tile() -> bool:
|
|||||||
return _can_build_on_selected_tile("Ore")
|
return _can_build_on_selected_tile("Ore")
|
||||||
|
|
||||||
|
|
||||||
|
func _can_build_farm_on_selected_tile() -> bool:
|
||||||
|
return _can_build_on_selected_tile("Field")
|
||||||
|
|
||||||
|
|
||||||
func _can_build_barracks_on_selected_tile() -> bool:
|
func _can_build_barracks_on_selected_tile() -> bool:
|
||||||
if not _can_build_on_selected_tile(""):
|
if not _can_build_on_selected_tile(""):
|
||||||
return false
|
return false
|
||||||
@@ -577,6 +589,9 @@ func _update_action_buttons() -> void:
|
|||||||
if build_mine_button:
|
if build_mine_button:
|
||||||
build_mine_button.visible = selected_can_build_mine
|
build_mine_button.visible = selected_can_build_mine
|
||||||
build_mine_button.disabled = false
|
build_mine_button.disabled = false
|
||||||
|
if build_farm_button:
|
||||||
|
build_farm_button.visible = selected_can_build_farm
|
||||||
|
build_farm_button.disabled = false
|
||||||
if build_barracks_button:
|
if build_barracks_button:
|
||||||
build_barracks_button.visible = selected_can_build_barracks
|
build_barracks_button.visible = selected_can_build_barracks
|
||||||
build_barracks_button.disabled = false
|
build_barracks_button.disabled = false
|
||||||
@@ -832,7 +847,7 @@ func _refresh_player_state() -> void:
|
|||||||
func _load_resources() -> void:
|
func _load_resources() -> void:
|
||||||
var access_token: String = str(session.get("accessToken", ""))
|
var access_token: String = str(session.get("accessToken", ""))
|
||||||
if access_token.is_empty():
|
if access_token.is_empty():
|
||||||
resource_text = "Gold: --\nWood: --\nOre: --"
|
resource_text = "Gold: --\nWood: --\nOre: --\nFood: --"
|
||||||
gold_label.text = resource_text
|
gold_label.text = resource_text
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -873,7 +888,10 @@ func _on_resources_request_completed(result: int, response_code: int, _headers:
|
|||||||
var ore: int = int(resources.get("ore", 0))
|
var ore: int = int(resources.get("ore", 0))
|
||||||
var ore_per_minute: int = int(resources.get("orePerMinute", 0))
|
var ore_per_minute: int = int(resources.get("orePerMinute", 0))
|
||||||
var ore_capacity: int = int(resources.get("oreCapacity", 100))
|
var ore_capacity: int = int(resources.get("oreCapacity", 100))
|
||||||
resource_text = "Gold: %d/%d (+%d/min)\nWood: %d/%d (+%d/min)\nOre: %d/%d (+%d/min)" % [
|
var food: int = int(resources.get("food", 0))
|
||||||
|
var food_per_minute: int = int(resources.get("foodPerMinute", 0))
|
||||||
|
var food_capacity: int = int(resources.get("foodCapacity", 100))
|
||||||
|
resource_text = "Gold: %d/%d (+%d/min)\nWood: %d/%d (+%d/min)\nOre: %d/%d (+%d/min)\nFood: %d/%d (+%d/min)" % [
|
||||||
gold,
|
gold,
|
||||||
gold_capacity,
|
gold_capacity,
|
||||||
gold_per_minute,
|
gold_per_minute,
|
||||||
@@ -882,7 +900,10 @@ func _on_resources_request_completed(result: int, response_code: int, _headers:
|
|||||||
wood_per_minute,
|
wood_per_minute,
|
||||||
ore,
|
ore,
|
||||||
ore_capacity,
|
ore_capacity,
|
||||||
ore_per_minute
|
ore_per_minute,
|
||||||
|
food,
|
||||||
|
food_capacity,
|
||||||
|
food_per_minute
|
||||||
]
|
]
|
||||||
gold_label.text = resource_text
|
gold_label.text = resource_text
|
||||||
|
|
||||||
@@ -1156,6 +1177,14 @@ func _build_mine() -> void:
|
|||||||
_request_building("Mine")
|
_request_building("Mine")
|
||||||
|
|
||||||
|
|
||||||
|
func _build_farm() -> void:
|
||||||
|
if not selected_can_build_farm:
|
||||||
|
coordinate_label.text = "Select controlled Field territory without a building."
|
||||||
|
return
|
||||||
|
|
||||||
|
_request_building("Farm")
|
||||||
|
|
||||||
|
|
||||||
func _build_barracks() -> void:
|
func _build_barracks() -> void:
|
||||||
if not selected_can_build_barracks:
|
if not selected_can_build_barracks:
|
||||||
coordinate_label.text = "Select controlled territory without a building."
|
coordinate_label.text = "Select controlled territory without a building."
|
||||||
@@ -1176,6 +1205,8 @@ func _request_building(building_type: String) -> void:
|
|||||||
match building_type:
|
match building_type:
|
||||||
"Mine":
|
"Mine":
|
||||||
build_mine_button.disabled = true
|
build_mine_button.disabled = true
|
||||||
|
"Farm":
|
||||||
|
build_farm_button.disabled = true
|
||||||
"Barracks":
|
"Barracks":
|
||||||
build_barracks_button.disabled = true
|
build_barracks_button.disabled = true
|
||||||
_:
|
_:
|
||||||
@@ -1348,6 +1379,8 @@ func _building_display_name(building_type: String) -> String:
|
|||||||
return "Log Camp"
|
return "Log Camp"
|
||||||
"Mine":
|
"Mine":
|
||||||
return "Mine"
|
return "Mine"
|
||||||
|
"Farm":
|
||||||
|
return "Farm"
|
||||||
"Barracks":
|
"Barracks":
|
||||||
return "Barracks"
|
return "Barracks"
|
||||||
_:
|
_:
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ func _draw_tile(tile: Dictionary) -> void:
|
|||||||
_draw_log_camp_marker(center, height)
|
_draw_log_camp_marker(center, height)
|
||||||
elif building_type == "Mine" and (building_status == "Built" or building_status.is_empty()):
|
elif building_type == "Mine" and (building_status == "Built" or building_status.is_empty()):
|
||||||
_draw_mine_marker(center, height)
|
_draw_mine_marker(center, height)
|
||||||
|
elif building_type == "Farm" and (building_status == "Built" or building_status.is_empty()):
|
||||||
|
_draw_farm_marker(center, height)
|
||||||
elif building_type == "Barracks" and (building_status == "Built" or building_status.is_empty()):
|
elif building_type == "Barracks" and (building_status == "Built" or building_status.is_empty()):
|
||||||
_draw_barracks_marker(center, height)
|
_draw_barracks_marker(center, height)
|
||||||
elif not building_type.is_empty():
|
elif not building_type.is_empty():
|
||||||
@@ -356,6 +358,33 @@ func _draw_mine_marker(center: Vector2, height: float) -> void:
|
|||||||
draw_circle(marker_center + Vector2(width * 0.34, -marker_height * 0.1), 2.0 * zoom, ore_color)
|
draw_circle(marker_center + Vector2(width * 0.34, -marker_height * 0.1), 2.0 * zoom, ore_color)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_farm_marker(center: Vector2, height: float) -> void:
|
||||||
|
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 2.0)
|
||||||
|
var width: float = 22.0 * zoom
|
||||||
|
var crop_color := Color(0.76, 0.67, 0.28)
|
||||||
|
var soil_color := Color(0.34, 0.22, 0.12)
|
||||||
|
var fence_color := Color(0.70, 0.52, 0.30)
|
||||||
|
var shadow_color := Color(0.08, 0.06, 0.04)
|
||||||
|
|
||||||
|
var plot := PackedVector2Array([
|
||||||
|
marker_center + Vector2(-width * 0.55, width * 0.18),
|
||||||
|
marker_center + Vector2(-width * 0.18, -width * 0.24),
|
||||||
|
marker_center + Vector2(width * 0.55, -width * 0.03),
|
||||||
|
marker_center + Vector2(width * 0.18, width * 0.34)
|
||||||
|
])
|
||||||
|
draw_colored_polygon(plot, soil_color)
|
||||||
|
draw_polyline(_closed_points(plot), fence_color, 1.5 * zoom)
|
||||||
|
for offset in [-0.28, 0.0, 0.28]:
|
||||||
|
draw_line(
|
||||||
|
marker_center + Vector2((-0.36 + offset) * width, width * 0.13),
|
||||||
|
marker_center + Vector2((-0.08 + offset) * width, -width * 0.16),
|
||||||
|
crop_color,
|
||||||
|
1.8 * zoom
|
||||||
|
)
|
||||||
|
draw_circle(marker_center + Vector2(width * 0.26, -width * 0.16), 2.2 * zoom, crop_color.lightened(0.18))
|
||||||
|
draw_line(marker_center + Vector2(-width * 0.52, width * 0.25), marker_center + Vector2(width * 0.5, width * 0.0), shadow_color, 1.0 * zoom)
|
||||||
|
|
||||||
|
|
||||||
func _draw_barracks_marker(center: Vector2, height: float) -> void:
|
func _draw_barracks_marker(center: Vector2, height: float) -> void:
|
||||||
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 3.0)
|
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 3.0)
|
||||||
var width: float = 22.0 * zoom
|
var width: float = 22.0 * zoom
|
||||||
@@ -667,6 +696,8 @@ func _tile_display_label(key: String, data: Dictionary) -> String:
|
|||||||
building_label = " | Log Camp" if building_status == "Built" or building_status.is_empty() else " | Log Camp building"
|
building_label = " | Log Camp" if building_status == "Built" or building_status.is_empty() else " | Log Camp building"
|
||||||
elif building_type == "Mine":
|
elif building_type == "Mine":
|
||||||
building_label = " | Mine" if building_status == "Built" or building_status.is_empty() else " | Mine building"
|
building_label = " | Mine" if building_status == "Built" or building_status.is_empty() else " | Mine building"
|
||||||
|
elif building_type == "Farm":
|
||||||
|
building_label = " | Farm" if building_status == "Built" or building_status.is_empty() else " | Farm building"
|
||||||
elif building_type == "Barracks":
|
elif building_type == "Barracks":
|
||||||
building_label = " | Barracks" if building_status == "Built" or building_status.is_empty() else " | Barracks building"
|
building_label = " | Barracks" if building_status == "Built" or building_status.is_empty() else " | Barracks building"
|
||||||
var archer_count := _archer_count_at(int(data.get("q", 0)), int(data.get("r", 0)))
|
var archer_count := _archer_count_at(int(data.get("q", 0)), int(data.get("r", 0)))
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class LocationResponse
|
|||||||
Label = location.Label,
|
Label = location.Label,
|
||||||
Level = location.Level,
|
Level = location.Level,
|
||||||
BuildingType = revealDetails ? location.BuildingType : null,
|
BuildingType = revealDetails ? location.BuildingType : null,
|
||||||
BuildingStatus = revealDetails && (location.BuildingType == "LogCamp" || location.BuildingType == "Mine" || location.BuildingType == "Barracks") && string.IsNullOrWhiteSpace(location.BuildingStatus)
|
BuildingStatus = revealDetails && (location.BuildingType == "LogCamp" || location.BuildingType == "Mine" || location.BuildingType == "Barracks" || location.BuildingType == "Farm") && string.IsNullOrWhiteSpace(location.BuildingStatus)
|
||||||
? "Built"
|
? "Built"
|
||||||
: revealDetails ? location.BuildingStatus : null,
|
: revealDetails ? location.BuildingStatus : null,
|
||||||
BuildingStartedAtUtc = revealDetails ? location.BuildingStartedAtUtc : null,
|
BuildingStartedAtUtc = revealDetails ? location.BuildingStartedAtUtc : null,
|
||||||
@@ -74,7 +74,7 @@ public class LocationResponse
|
|||||||
Label = intel.Label,
|
Label = intel.Label,
|
||||||
Level = intel.Level,
|
Level = intel.Level,
|
||||||
BuildingType = intel.BuildingType,
|
BuildingType = intel.BuildingType,
|
||||||
BuildingStatus = (intel.BuildingType == "LogCamp" || intel.BuildingType == "Mine" || intel.BuildingType == "Barracks") && string.IsNullOrWhiteSpace(intel.BuildingStatus)
|
BuildingStatus = (intel.BuildingType == "LogCamp" || intel.BuildingType == "Mine" || intel.BuildingType == "Barracks" || intel.BuildingType == "Farm") && string.IsNullOrWhiteSpace(intel.BuildingStatus)
|
||||||
? "Built"
|
? "Built"
|
||||||
: intel.BuildingStatus,
|
: intel.BuildingStatus,
|
||||||
BuildingStartedAtUtc = intel.BuildingStartedAtUtc,
|
BuildingStartedAtUtc = intel.BuildingStartedAtUtc,
|
||||||
|
|||||||
@@ -19,9 +19,13 @@ public class PlayerResources
|
|||||||
public int Ore { get; set; }
|
public int Ore { get; set; }
|
||||||
public int OrePerMinute { get; set; }
|
public int OrePerMinute { get; set; }
|
||||||
public int OreCapacity { get; set; } = 100;
|
public int OreCapacity { get; set; } = 100;
|
||||||
|
public int Food { get; set; }
|
||||||
|
public int FoodPerMinute { get; set; }
|
||||||
|
public int FoodCapacity { get; set; } = 100;
|
||||||
public DateTime LastGoldGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime LastGoldGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime LastWoodGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime LastWoodGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime LastOreGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime LastOreGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime LastFoodGeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime UpdatedAtUtc { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedAtUtc { get; set; } = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,13 @@ public class PlayerResourcesResponse
|
|||||||
public int Ore { get; set; }
|
public int Ore { get; set; }
|
||||||
public int OrePerMinute { get; set; }
|
public int OrePerMinute { get; set; }
|
||||||
public int OreCapacity { get; set; }
|
public int OreCapacity { get; set; }
|
||||||
|
public int Food { get; set; }
|
||||||
|
public int FoodPerMinute { get; set; }
|
||||||
|
public int FoodCapacity { get; set; }
|
||||||
public DateTime LastGoldGeneratedAtUtc { get; set; }
|
public DateTime LastGoldGeneratedAtUtc { get; set; }
|
||||||
public DateTime LastWoodGeneratedAtUtc { get; set; }
|
public DateTime LastWoodGeneratedAtUtc { get; set; }
|
||||||
public DateTime LastOreGeneratedAtUtc { get; set; }
|
public DateTime LastOreGeneratedAtUtc { get; set; }
|
||||||
|
public DateTime LastFoodGeneratedAtUtc { get; set; }
|
||||||
public DateTime UpdatedAtUtc { get; set; }
|
public DateTime UpdatedAtUtc { get; set; }
|
||||||
|
|
||||||
public static PlayerResourcesResponse FromResources(PlayerResources resources) => new()
|
public static PlayerResourcesResponse FromResources(PlayerResources resources) => new()
|
||||||
@@ -29,9 +33,13 @@ public class PlayerResourcesResponse
|
|||||||
Ore = resources.Ore,
|
Ore = resources.Ore,
|
||||||
OrePerMinute = resources.OrePerMinute,
|
OrePerMinute = resources.OrePerMinute,
|
||||||
OreCapacity = resources.OreCapacity,
|
OreCapacity = resources.OreCapacity,
|
||||||
|
Food = resources.Food,
|
||||||
|
FoodPerMinute = resources.FoodPerMinute,
|
||||||
|
FoodCapacity = resources.FoodCapacity,
|
||||||
LastGoldGeneratedAtUtc = resources.LastGoldGeneratedAtUtc,
|
LastGoldGeneratedAtUtc = resources.LastGoldGeneratedAtUtc,
|
||||||
LastWoodGeneratedAtUtc = resources.LastWoodGeneratedAtUtc,
|
LastWoodGeneratedAtUtc = resources.LastWoodGeneratedAtUtc,
|
||||||
LastOreGeneratedAtUtc = resources.LastOreGeneratedAtUtc,
|
LastOreGeneratedAtUtc = resources.LastOreGeneratedAtUtc,
|
||||||
|
LastFoodGeneratedAtUtc = resources.LastFoodGeneratedAtUtc,
|
||||||
UpdatedAtUtc = resources.UpdatedAtUtc
|
UpdatedAtUtc = resources.UpdatedAtUtc
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,25 @@ public class GameSettingsService
|
|||||||
{
|
{
|
||||||
public const string ScoutTrainingSeconds = "ScoutTrainingSeconds";
|
public const string ScoutTrainingSeconds = "ScoutTrainingSeconds";
|
||||||
public const string ArcherTrainingSeconds = "ArcherTrainingSeconds";
|
public const string ArcherTrainingSeconds = "ArcherTrainingSeconds";
|
||||||
|
public const string ScoutGoldCost = "ScoutGoldCost";
|
||||||
|
public const string ArcherGoldCost = "ArcherGoldCost";
|
||||||
|
public const string ArcherWoodCost = "ArcherWoodCost";
|
||||||
public const string LogCampBuildSeconds = "LogCampBuildSeconds";
|
public const string LogCampBuildSeconds = "LogCampBuildSeconds";
|
||||||
public const string MineBuildSeconds = "MineBuildSeconds";
|
public const string MineBuildSeconds = "MineBuildSeconds";
|
||||||
public const string BarracksBuildSeconds = "BarracksBuildSeconds";
|
public const string BarracksBuildSeconds = "BarracksBuildSeconds";
|
||||||
|
public const string FarmBuildSeconds = "FarmBuildSeconds";
|
||||||
|
public const string BarracksGoldCost = "BarracksGoldCost";
|
||||||
|
public const string BarracksWoodCost = "BarracksWoodCost";
|
||||||
|
public const string BarracksOreCost = "BarracksOreCost";
|
||||||
|
public const string LogCampWoodPerMinute = "LogCampWoodPerMinute";
|
||||||
|
public const string MineOrePerMinute = "MineOrePerMinute";
|
||||||
|
public const string FarmFoodPerMinute = "FarmFoodPerMinute";
|
||||||
|
public const string StartingGold = "StartingGold";
|
||||||
|
public const string HeadquartersGoldPerMinute = "HeadquartersGoldPerMinute";
|
||||||
|
public const string TownHallGoldCapacity = "TownHallGoldCapacity";
|
||||||
|
public const string TownHallWoodCapacity = "TownHallWoodCapacity";
|
||||||
|
public const string TownHallOreCapacity = "TownHallOreCapacity";
|
||||||
|
public const string TownHallFoodCapacity = "TownHallFoodCapacity";
|
||||||
|
|
||||||
private readonly IMongoCollection<GameSetting> _settings;
|
private readonly IMongoCollection<GameSetting> _settings;
|
||||||
|
|
||||||
@@ -44,4 +60,23 @@ public class GameSettingsService
|
|||||||
|
|
||||||
return Math.Max(1, setting.IntValue);
|
return Math.Max(1, setting.IntValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetNonNegativeIntAsync(string key, int defaultValue)
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var setting = await _settings.FindOneAndUpdateAsync(
|
||||||
|
x => x.Key == key,
|
||||||
|
Builders<GameSetting>.Update
|
||||||
|
.SetOnInsert(x => x.Key, key)
|
||||||
|
.SetOnInsert(x => x.IntValue, defaultValue)
|
||||||
|
.SetOnInsert(x => x.CreatedAtUtc, now)
|
||||||
|
.Set(x => x.UpdatedAtUtc, now),
|
||||||
|
new FindOneAndUpdateOptions<GameSetting>
|
||||||
|
{
|
||||||
|
IsUpsert = true,
|
||||||
|
ReturnDocument = ReturnDocument.After
|
||||||
|
});
|
||||||
|
|
||||||
|
return Math.Max(0, setting.IntValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ public class LocationService
|
|||||||
private readonly int _visibilityDepth;
|
private readonly int _visibilityDepth;
|
||||||
private readonly int _logCampWoodPerMinute;
|
private readonly int _logCampWoodPerMinute;
|
||||||
private readonly int _mineOrePerMinute;
|
private readonly int _mineOrePerMinute;
|
||||||
|
private readonly int _farmFoodPerMinute;
|
||||||
private readonly int _defaultLogCampBuildSeconds;
|
private readonly int _defaultLogCampBuildSeconds;
|
||||||
private readonly int _defaultMineBuildSeconds;
|
private readonly int _defaultMineBuildSeconds;
|
||||||
private readonly int _defaultBarracksBuildSeconds;
|
private readonly int _defaultBarracksBuildSeconds;
|
||||||
|
private readonly int _defaultFarmBuildSeconds;
|
||||||
private readonly int _barracksGoldCost;
|
private readonly int _barracksGoldCost;
|
||||||
private readonly int _barracksWoodCost;
|
private readonly int _barracksWoodCost;
|
||||||
private readonly int _barracksOreCost;
|
private readonly int _barracksOreCost;
|
||||||
@@ -42,6 +44,9 @@ public class LocationService
|
|||||||
_mineOrePerMinute = int.TryParse(cfg["Buildings:MineOrePerMinute"], out var mineOrePerMinute)
|
_mineOrePerMinute = int.TryParse(cfg["Buildings:MineOrePerMinute"], out var mineOrePerMinute)
|
||||||
? Math.Max(1, mineOrePerMinute)
|
? Math.Max(1, mineOrePerMinute)
|
||||||
: 5;
|
: 5;
|
||||||
|
_farmFoodPerMinute = int.TryParse(cfg["Buildings:FarmFoodPerMinute"], out var farmFoodPerMinute)
|
||||||
|
? Math.Max(1, farmFoodPerMinute)
|
||||||
|
: 5;
|
||||||
_defaultLogCampBuildSeconds = int.TryParse(cfg["Buildings:LogCampBuildSeconds"], out var logCampBuildSeconds)
|
_defaultLogCampBuildSeconds = int.TryParse(cfg["Buildings:LogCampBuildSeconds"], out var logCampBuildSeconds)
|
||||||
? Math.Max(1, logCampBuildSeconds)
|
? Math.Max(1, logCampBuildSeconds)
|
||||||
: 60;
|
: 60;
|
||||||
@@ -51,6 +56,9 @@ public class LocationService
|
|||||||
_defaultBarracksBuildSeconds = int.TryParse(cfg["Buildings:BarracksBuildSeconds"], out var barracksBuildSeconds)
|
_defaultBarracksBuildSeconds = int.TryParse(cfg["Buildings:BarracksBuildSeconds"], out var barracksBuildSeconds)
|
||||||
? Math.Max(1, barracksBuildSeconds)
|
? Math.Max(1, barracksBuildSeconds)
|
||||||
: 60;
|
: 60;
|
||||||
|
_defaultFarmBuildSeconds = int.TryParse(cfg["Buildings:FarmBuildSeconds"], out var farmBuildSeconds)
|
||||||
|
? Math.Max(1, farmBuildSeconds)
|
||||||
|
: 60;
|
||||||
_barracksGoldCost = int.TryParse(cfg["Buildings:BarracksGoldCost"], out var barracksGoldCost)
|
_barracksGoldCost = int.TryParse(cfg["Buildings:BarracksGoldCost"], out var barracksGoldCost)
|
||||||
? Math.Max(0, barracksGoldCost)
|
? Math.Max(0, barracksGoldCost)
|
||||||
: 500;
|
: 500;
|
||||||
@@ -215,7 +223,10 @@ public class LocationService
|
|||||||
|
|
||||||
if (buildingType == "Barracks")
|
if (buildingType == "Barracks")
|
||||||
{
|
{
|
||||||
var spent = await _resources.TrySpendResourcesAsync(username, _barracksGoldCost, _barracksWoodCost, _barracksOreCost);
|
var barracksGoldCost = await _settings.GetNonNegativeIntAsync(GameSettingsService.BarracksGoldCost, _barracksGoldCost);
|
||||||
|
var barracksWoodCost = await _settings.GetNonNegativeIntAsync(GameSettingsService.BarracksWoodCost, _barracksWoodCost);
|
||||||
|
var barracksOreCost = await _settings.GetNonNegativeIntAsync(GameSettingsService.BarracksOreCost, _barracksOreCost);
|
||||||
|
var spent = await _resources.TrySpendResourcesAsync(username, barracksGoldCost, barracksWoodCost, barracksOreCost);
|
||||||
if (!spent)
|
if (!spent)
|
||||||
{
|
{
|
||||||
var rollback = Builders<Location>.Update
|
var rollback = Builders<Location>.Update
|
||||||
@@ -230,7 +241,7 @@ public class LocationService
|
|||||||
x => x.Id == updated.Id && x.BuildingType == "Barracks" && x.BuildingStatus == "Building" && x.BuildingStartedAtUtc == now,
|
x => x.Id == updated.Id && x.BuildingType == "Barracks" && x.BuildingStatus == "Building" && x.BuildingStartedAtUtc == now,
|
||||||
rollback);
|
rollback);
|
||||||
|
|
||||||
throw new InvalidOperationException($"Not enough resources to build Barracks. Required: {_barracksGoldCost} gold, {_barracksWoodCost} wood, {_barracksOreCost} ore.");
|
throw new InvalidOperationException($"Not enough resources to build Barracks. Required: {barracksGoldCost} gold, {barracksWoodCost} wood, {barracksOreCost} ore.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +253,7 @@ public class LocationService
|
|||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var readyBuildings = await _locations.Find(x =>
|
var readyBuildings = await _locations.Find(x =>
|
||||||
x.OwnerUsername == username &&
|
x.OwnerUsername == username &&
|
||||||
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Barracks") &&
|
(x.BuildingType == "LogCamp" || x.BuildingType == "Mine" || x.BuildingType == "Barracks" || x.BuildingType == "Farm") &&
|
||||||
x.BuildingStatus == "Building" &&
|
x.BuildingStatus == "Building" &&
|
||||||
x.BuildingCompletesAtUtc <= now)
|
x.BuildingCompletesAtUtc <= now)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -266,11 +277,18 @@ public class LocationService
|
|||||||
{
|
{
|
||||||
if (updated.BuildingType == "LogCamp")
|
if (updated.BuildingType == "LogCamp")
|
||||||
{
|
{
|
||||||
await _resources.AddWoodGenerationAsync(username, _logCampWoodPerMinute);
|
var woodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.LogCampWoodPerMinute, _logCampWoodPerMinute);
|
||||||
|
await _resources.AddWoodGenerationAsync(username, woodPerMinute);
|
||||||
}
|
}
|
||||||
else if (updated.BuildingType == "Mine")
|
else if (updated.BuildingType == "Mine")
|
||||||
{
|
{
|
||||||
await _resources.AddOreGenerationAsync(username, _mineOrePerMinute);
|
var orePerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.MineOrePerMinute, _mineOrePerMinute);
|
||||||
|
await _resources.AddOreGenerationAsync(username, orePerMinute);
|
||||||
|
}
|
||||||
|
else if (updated.BuildingType == "Farm")
|
||||||
|
{
|
||||||
|
var foodPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.FarmFoodPerMinute, _farmFoodPerMinute);
|
||||||
|
await _resources.AddFoodGenerationAsync(username, foodPerMinute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -758,6 +776,7 @@ public class LocationService
|
|||||||
"logcamp" or "log camp" => "LogCamp",
|
"logcamp" or "log camp" => "LogCamp",
|
||||||
"mine" => "Mine",
|
"mine" => "Mine",
|
||||||
"barracks" => "Barracks",
|
"barracks" => "Barracks",
|
||||||
|
"farm" => "Farm",
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -767,6 +786,7 @@ public class LocationService
|
|||||||
{
|
{
|
||||||
"LogCamp" => "Forest",
|
"LogCamp" => "Forest",
|
||||||
"Mine" => "Ore",
|
"Mine" => "Ore",
|
||||||
|
"Farm" => "Field",
|
||||||
"Barracks" => null,
|
"Barracks" => null,
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
@@ -777,6 +797,7 @@ public class LocationService
|
|||||||
"LogCamp" => GameSettingsService.LogCampBuildSeconds,
|
"LogCamp" => GameSettingsService.LogCampBuildSeconds,
|
||||||
"Mine" => GameSettingsService.MineBuildSeconds,
|
"Mine" => GameSettingsService.MineBuildSeconds,
|
||||||
"Barracks" => GameSettingsService.BarracksBuildSeconds,
|
"Barracks" => GameSettingsService.BarracksBuildSeconds,
|
||||||
|
"Farm" => GameSettingsService.FarmBuildSeconds,
|
||||||
_ => GameSettingsService.LogCampBuildSeconds
|
_ => GameSettingsService.LogCampBuildSeconds
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -786,6 +807,7 @@ public class LocationService
|
|||||||
"LogCamp" => _defaultLogCampBuildSeconds,
|
"LogCamp" => _defaultLogCampBuildSeconds,
|
||||||
"Mine" => _defaultMineBuildSeconds,
|
"Mine" => _defaultMineBuildSeconds,
|
||||||
"Barracks" => _defaultBarracksBuildSeconds,
|
"Barracks" => _defaultBarracksBuildSeconds,
|
||||||
|
"Farm" => _defaultFarmBuildSeconds,
|
||||||
_ => 60
|
_ => 60
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,22 @@ namespace LocationsApi.Services;
|
|||||||
public class ResourceService
|
public class ResourceService
|
||||||
{
|
{
|
||||||
private readonly IMongoCollection<PlayerResources> _resources;
|
private readonly IMongoCollection<PlayerResources> _resources;
|
||||||
|
private readonly GameSettingsService _settings;
|
||||||
private readonly int _startingGold;
|
private readonly int _startingGold;
|
||||||
private readonly int _headquartersGoldPerMinute;
|
private readonly int _headquartersGoldPerMinute;
|
||||||
private readonly int _townHallGoldCapacity;
|
private readonly int _townHallGoldCapacity;
|
||||||
private readonly int _townHallWoodCapacity;
|
private readonly int _townHallWoodCapacity;
|
||||||
private readonly int _townHallOreCapacity;
|
private readonly int _townHallOreCapacity;
|
||||||
|
private readonly int _townHallFoodCapacity;
|
||||||
|
|
||||||
public ResourceService(IConfiguration cfg)
|
public ResourceService(IConfiguration cfg, GameSettingsService settings)
|
||||||
{
|
{
|
||||||
var connectionString = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
|
var connectionString = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
|
||||||
var databaseName = cfg["MongoDB:DatabaseName"] ?? "territory-autobattler";
|
var databaseName = cfg["MongoDB:DatabaseName"] ?? "territory-autobattler";
|
||||||
var client = new MongoClient(connectionString);
|
var client = new MongoClient(connectionString);
|
||||||
var database = client.GetDatabase(databaseName);
|
var database = client.GetDatabase(databaseName);
|
||||||
_resources = database.GetCollection<PlayerResources>("PlayerResources");
|
_resources = database.GetCollection<PlayerResources>("PlayerResources");
|
||||||
|
_settings = settings;
|
||||||
_startingGold = int.TryParse(cfg["Resources:StartingGold"], out var startingGold) ? Math.Max(0, startingGold) : 100;
|
_startingGold = int.TryParse(cfg["Resources:StartingGold"], out var startingGold) ? Math.Max(0, startingGold) : 100;
|
||||||
_headquartersGoldPerMinute = int.TryParse(cfg["Resources:HeadquartersGoldPerMinute"], out var goldPerMinute)
|
_headquartersGoldPerMinute = int.TryParse(cfg["Resources:HeadquartersGoldPerMinute"], out var goldPerMinute)
|
||||||
? Math.Max(0, goldPerMinute)
|
? Math.Max(0, goldPerMinute)
|
||||||
@@ -32,6 +35,9 @@ public class ResourceService
|
|||||||
_townHallOreCapacity = int.TryParse(cfg["Resources:TownHallOreCapacity"], out var oreCapacity)
|
_townHallOreCapacity = int.TryParse(cfg["Resources:TownHallOreCapacity"], out var oreCapacity)
|
||||||
? Math.Max(0, oreCapacity)
|
? Math.Max(0, oreCapacity)
|
||||||
: 100;
|
: 100;
|
||||||
|
_townHallFoodCapacity = int.TryParse(cfg["Resources:TownHallFoodCapacity"], out var foodCapacity)
|
||||||
|
? Math.Max(0, foodCapacity)
|
||||||
|
: 100;
|
||||||
|
|
||||||
_resources.Indexes.CreateOne(new CreateIndexModel<PlayerResources>(
|
_resources.Indexes.CreateOne(new CreateIndexModel<PlayerResources>(
|
||||||
Builders<PlayerResources>.IndexKeys.Ascending(x => x.Username),
|
Builders<PlayerResources>.IndexKeys.Ascending(x => x.Username),
|
||||||
@@ -41,19 +47,28 @@ public class ResourceService
|
|||||||
public async Task<PlayerResources> EnsureAsync(string username)
|
public async Task<PlayerResources> EnsureAsync(string username)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
var startingGold = await _settings.GetNonNegativeIntAsync(GameSettingsService.StartingGold, _startingGold);
|
||||||
|
var goldPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.HeadquartersGoldPerMinute, _headquartersGoldPerMinute);
|
||||||
|
var goldCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallGoldCapacity, _townHallGoldCapacity);
|
||||||
|
var woodCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallWoodCapacity, _townHallWoodCapacity);
|
||||||
|
var oreCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallOreCapacity, _townHallOreCapacity);
|
||||||
|
var foodCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallFoodCapacity, _townHallFoodCapacity);
|
||||||
var update = Builders<PlayerResources>.Update
|
var update = Builders<PlayerResources>.Update
|
||||||
.SetOnInsert(x => x.Username, username)
|
.SetOnInsert(x => x.Username, username)
|
||||||
.SetOnInsert(x => x.Gold, Math.Min(_startingGold, _townHallGoldCapacity))
|
.SetOnInsert(x => x.Gold, Math.Min(startingGold, goldCapacity))
|
||||||
.SetOnInsert(x => x.Wood, 0)
|
.SetOnInsert(x => x.Wood, 0)
|
||||||
.SetOnInsert(x => x.Ore, 0)
|
.SetOnInsert(x => x.Ore, 0)
|
||||||
|
.SetOnInsert(x => x.Food, 0)
|
||||||
.SetOnInsert(x => x.CreatedAtUtc, now)
|
.SetOnInsert(x => x.CreatedAtUtc, now)
|
||||||
.SetOnInsert(x => x.LastGoldGeneratedAtUtc, now)
|
.SetOnInsert(x => x.LastGoldGeneratedAtUtc, now)
|
||||||
.SetOnInsert(x => x.LastWoodGeneratedAtUtc, now)
|
.SetOnInsert(x => x.LastWoodGeneratedAtUtc, now)
|
||||||
.SetOnInsert(x => x.LastOreGeneratedAtUtc, now)
|
.SetOnInsert(x => x.LastOreGeneratedAtUtc, now)
|
||||||
.Set(x => x.GoldPerMinute, _headquartersGoldPerMinute)
|
.SetOnInsert(x => x.LastFoodGeneratedAtUtc, now)
|
||||||
.Set(x => x.GoldCapacity, _townHallGoldCapacity)
|
.Set(x => x.GoldPerMinute, goldPerMinute)
|
||||||
.Set(x => x.WoodCapacity, _townHallWoodCapacity)
|
.Set(x => x.GoldCapacity, goldCapacity)
|
||||||
.Set(x => x.OreCapacity, _townHallOreCapacity)
|
.Set(x => x.WoodCapacity, woodCapacity)
|
||||||
|
.Set(x => x.OreCapacity, oreCapacity)
|
||||||
|
.Set(x => x.FoodCapacity, foodCapacity)
|
||||||
.Set(x => x.UpdatedAtUtc, now);
|
.Set(x => x.UpdatedAtUtc, now);
|
||||||
|
|
||||||
var resources = await _resources.FindOneAndUpdateAsync(
|
var resources = await _resources.FindOneAndUpdateAsync(
|
||||||
@@ -65,7 +80,7 @@ public class ResourceService
|
|||||||
ReturnDocument = ReturnDocument.After
|
ReturnDocument = ReturnDocument.After
|
||||||
});
|
});
|
||||||
|
|
||||||
return await ApplyGoldGenerationAsync(resources);
|
return await ApplyResourceGenerationAsync(resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PlayerResources> GetAsync(string username)
|
public async Task<PlayerResources> GetAsync(string username)
|
||||||
@@ -170,10 +185,37 @@ public class ResourceService
|
|||||||
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<PlayerResources> ApplyGoldGenerationAsync(PlayerResources resources)
|
public async Task AddFoodGenerationAsync(string username, int foodPerMinute)
|
||||||
|
{
|
||||||
|
if (foodPerMinute <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources = await EnsureAsync(username);
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var update = Builders<PlayerResources>.Update
|
||||||
|
.Inc(x => x.FoodPerMinute, foodPerMinute)
|
||||||
|
.Set(x => x.UpdatedAtUtc, now);
|
||||||
|
|
||||||
|
if (resources.FoodPerMinute <= 0 || resources.LastFoodGeneratedAtUtc.Year < 2000)
|
||||||
|
{
|
||||||
|
update = update.Set(x => x.LastFoodGeneratedAtUtc, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<PlayerResources> ApplyResourceGenerationAsync(PlayerResources resources)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var goldElapsedMinutes = resources.GoldPerMinute <= 0
|
var goldPerMinute = await _settings.GetNonNegativeIntAsync(GameSettingsService.HeadquartersGoldPerMinute, _headquartersGoldPerMinute);
|
||||||
|
var goldCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallGoldCapacity, _townHallGoldCapacity);
|
||||||
|
var woodCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallWoodCapacity, _townHallWoodCapacity);
|
||||||
|
var oreCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallOreCapacity, _townHallOreCapacity);
|
||||||
|
var foodCapacity = await _settings.GetNonNegativeIntAsync(GameSettingsService.TownHallFoodCapacity, _townHallFoodCapacity);
|
||||||
|
var goldElapsedMinutes = goldPerMinute <= 0
|
||||||
? 0
|
? 0
|
||||||
: (int)Math.Floor((now - resources.LastGoldGeneratedAtUtc).TotalMinutes);
|
: (int)Math.Floor((now - resources.LastGoldGeneratedAtUtc).TotalMinutes);
|
||||||
var woodElapsedMinutes = resources.WoodPerMinute <= 0 || resources.LastWoodGeneratedAtUtc.Year < 2000
|
var woodElapsedMinutes = resources.WoodPerMinute <= 0 || resources.LastWoodGeneratedAtUtc.Year < 2000
|
||||||
@@ -182,21 +224,26 @@ public class ResourceService
|
|||||||
var oreElapsedMinutes = resources.OrePerMinute <= 0 || resources.LastOreGeneratedAtUtc.Year < 2000
|
var oreElapsedMinutes = resources.OrePerMinute <= 0 || resources.LastOreGeneratedAtUtc.Year < 2000
|
||||||
? 0
|
? 0
|
||||||
: (int)Math.Floor((now - resources.LastOreGeneratedAtUtc).TotalMinutes);
|
: (int)Math.Floor((now - resources.LastOreGeneratedAtUtc).TotalMinutes);
|
||||||
var cappedGold = Math.Min(resources.Gold, _townHallGoldCapacity);
|
var foodElapsedMinutes = resources.FoodPerMinute <= 0 || resources.LastFoodGeneratedAtUtc.Year < 2000
|
||||||
var cappedWood = Math.Min(resources.Wood, _townHallWoodCapacity);
|
? 0
|
||||||
var cappedOre = Math.Min(resources.Ore, _townHallOreCapacity);
|
: (int)Math.Floor((now - resources.LastFoodGeneratedAtUtc).TotalMinutes);
|
||||||
var isOverCapacity = resources.Gold != cappedGold || resources.Wood != cappedWood || resources.Ore != cappedOre;
|
var cappedGold = Math.Min(resources.Gold, goldCapacity);
|
||||||
|
var cappedWood = Math.Min(resources.Wood, woodCapacity);
|
||||||
|
var cappedOre = Math.Min(resources.Ore, oreCapacity);
|
||||||
|
var cappedFood = Math.Min(resources.Food, foodCapacity);
|
||||||
|
var isOverCapacity = resources.Gold != cappedGold || resources.Wood != cappedWood || resources.Ore != cappedOre || resources.Food != cappedFood;
|
||||||
|
|
||||||
if (goldElapsedMinutes <= 0 && woodElapsedMinutes <= 0 && oreElapsedMinutes <= 0 && !isOverCapacity)
|
if (goldElapsedMinutes <= 0 && woodElapsedMinutes <= 0 && oreElapsedMinutes <= 0 && foodElapsedMinutes <= 0 && !isOverCapacity)
|
||||||
{
|
{
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
var update = Builders<PlayerResources>.Update
|
var update = Builders<PlayerResources>.Update
|
||||||
.Set(x => x.GoldPerMinute, _headquartersGoldPerMinute)
|
.Set(x => x.GoldPerMinute, goldPerMinute)
|
||||||
.Set(x => x.GoldCapacity, _townHallGoldCapacity)
|
.Set(x => x.GoldCapacity, goldCapacity)
|
||||||
.Set(x => x.WoodCapacity, _townHallWoodCapacity)
|
.Set(x => x.WoodCapacity, woodCapacity)
|
||||||
.Set(x => x.OreCapacity, _townHallOreCapacity)
|
.Set(x => x.OreCapacity, oreCapacity)
|
||||||
|
.Set(x => x.FoodCapacity, foodCapacity)
|
||||||
.Set(x => x.UpdatedAtUtc, now);
|
.Set(x => x.UpdatedAtUtc, now);
|
||||||
|
|
||||||
if (isOverCapacity)
|
if (isOverCapacity)
|
||||||
@@ -204,12 +251,13 @@ public class ResourceService
|
|||||||
update = update
|
update = update
|
||||||
.Set(x => x.Gold, cappedGold)
|
.Set(x => x.Gold, cappedGold)
|
||||||
.Set(x => x.Wood, cappedWood)
|
.Set(x => x.Wood, cappedWood)
|
||||||
.Set(x => x.Ore, cappedOre);
|
.Set(x => x.Ore, cappedOre)
|
||||||
|
.Set(x => x.Food, cappedFood);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (goldElapsedMinutes > 0)
|
if (goldElapsedMinutes > 0)
|
||||||
{
|
{
|
||||||
var generatedGold = Math.Min(_townHallGoldCapacity, cappedGold + (goldElapsedMinutes * resources.GoldPerMinute));
|
var generatedGold = Math.Min(goldCapacity, cappedGold + (goldElapsedMinutes * goldPerMinute));
|
||||||
update = update
|
update = update
|
||||||
.Set(x => x.Gold, generatedGold)
|
.Set(x => x.Gold, generatedGold)
|
||||||
.Set(x => x.LastGoldGeneratedAtUtc, resources.LastGoldGeneratedAtUtc.AddMinutes(goldElapsedMinutes));
|
.Set(x => x.LastGoldGeneratedAtUtc, resources.LastGoldGeneratedAtUtc.AddMinutes(goldElapsedMinutes));
|
||||||
@@ -217,7 +265,7 @@ public class ResourceService
|
|||||||
|
|
||||||
if (woodElapsedMinutes > 0)
|
if (woodElapsedMinutes > 0)
|
||||||
{
|
{
|
||||||
var generatedWood = Math.Min(_townHallWoodCapacity, cappedWood + (woodElapsedMinutes * resources.WoodPerMinute));
|
var generatedWood = Math.Min(woodCapacity, cappedWood + (woodElapsedMinutes * resources.WoodPerMinute));
|
||||||
update = update
|
update = update
|
||||||
.Set(x => x.Wood, generatedWood)
|
.Set(x => x.Wood, generatedWood)
|
||||||
.Set(x => x.LastWoodGeneratedAtUtc, resources.LastWoodGeneratedAtUtc.AddMinutes(woodElapsedMinutes));
|
.Set(x => x.LastWoodGeneratedAtUtc, resources.LastWoodGeneratedAtUtc.AddMinutes(woodElapsedMinutes));
|
||||||
@@ -225,12 +273,20 @@ public class ResourceService
|
|||||||
|
|
||||||
if (oreElapsedMinutes > 0)
|
if (oreElapsedMinutes > 0)
|
||||||
{
|
{
|
||||||
var generatedOre = Math.Min(_townHallOreCapacity, cappedOre + (oreElapsedMinutes * resources.OrePerMinute));
|
var generatedOre = Math.Min(oreCapacity, cappedOre + (oreElapsedMinutes * resources.OrePerMinute));
|
||||||
update = update
|
update = update
|
||||||
.Set(x => x.Ore, generatedOre)
|
.Set(x => x.Ore, generatedOre)
|
||||||
.Set(x => x.LastOreGeneratedAtUtc, resources.LastOreGeneratedAtUtc.AddMinutes(oreElapsedMinutes));
|
.Set(x => x.LastOreGeneratedAtUtc, resources.LastOreGeneratedAtUtc.AddMinutes(oreElapsedMinutes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (foodElapsedMinutes > 0)
|
||||||
|
{
|
||||||
|
var generatedFood = Math.Min(foodCapacity, cappedFood + (foodElapsedMinutes * resources.FoodPerMinute));
|
||||||
|
update = update
|
||||||
|
.Set(x => x.Food, generatedFood)
|
||||||
|
.Set(x => x.LastFoodGeneratedAtUtc, resources.LastFoodGeneratedAtUtc.AddMinutes(foodElapsedMinutes));
|
||||||
|
}
|
||||||
|
|
||||||
return await _resources.FindOneAndUpdateAsync(
|
return await _resources.FindOneAndUpdateAsync(
|
||||||
x => x.Username == resources.Username,
|
x => x.Username == resources.Username,
|
||||||
update,
|
update,
|
||||||
|
|||||||
@@ -107,8 +107,12 @@ public class UnitTrainingService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var goldCost = normalizedUnitType == ArcherUnitType ? _archerGoldCost : _scoutGoldCost;
|
var goldCost = normalizedUnitType == ArcherUnitType
|
||||||
var woodCost = normalizedUnitType == ArcherUnitType ? _archerWoodCost : 0;
|
? await _settings.GetNonNegativeIntAsync(GameSettingsService.ArcherGoldCost, _archerGoldCost)
|
||||||
|
: await _settings.GetNonNegativeIntAsync(GameSettingsService.ScoutGoldCost, _scoutGoldCost);
|
||||||
|
var woodCost = normalizedUnitType == ArcherUnitType
|
||||||
|
? await _settings.GetNonNegativeIntAsync(GameSettingsService.ArcherWoodCost, _archerWoodCost)
|
||||||
|
: 0;
|
||||||
var spent = normalizedUnitType == ArcherUnitType
|
var spent = normalizedUnitType == ArcherUnitType
|
||||||
? await _resources.TrySpendResourcesAsync(username, goldCost, woodCost, 0)
|
? await _resources.TrySpendResourcesAsync(username, goldCost, woodCost, 0)
|
||||||
: await _resources.TrySpendGoldAsync(username, goldCost);
|
: await _resources.TrySpendGoldAsync(username, goldCost);
|
||||||
@@ -241,7 +245,9 @@ public class UnitTrainingService
|
|||||||
{
|
{
|
||||||
var hasOtherUnits = await _units.Find(x => x.Username != username && x.Q == q && x.R == r).AnyAsync();
|
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 target = await _locations.Find(x => x.Q == q && x.R == r).FirstOrDefaultAsync();
|
||||||
var hasBuilding = target is not null && !string.IsNullOrWhiteSpace(target.BuildingType);
|
var hasBuilding = target is not null &&
|
||||||
|
(!string.IsNullOrWhiteSpace(target.BuildingType) ||
|
||||||
|
string.Equals(target.Kind, "Home", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (hasOtherUnits || hasBuilding)
|
if (hasOtherUnits || hasBuilding)
|
||||||
{
|
{
|
||||||
@@ -278,14 +284,15 @@ public class UnitTrainingService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var emptyBuildingFilter = Builders<Location>.Filter.And(
|
var capturableFilter = Builders<Location>.Filter.And(
|
||||||
Builders<Location>.Filter.Eq(x => x.Id, target.Id),
|
Builders<Location>.Filter.Eq(x => x.Id, target.Id),
|
||||||
|
Builders<Location>.Filter.Ne(x => x.Kind, "Home"),
|
||||||
Builders<Location>.Filter.Or(
|
Builders<Location>.Filter.Or(
|
||||||
Builders<Location>.Filter.Eq(x => x.BuildingType, null),
|
Builders<Location>.Filter.Eq(x => x.BuildingType, null),
|
||||||
Builders<Location>.Filter.Eq(x => x.BuildingType, "")));
|
Builders<Location>.Filter.Eq(x => x.BuildingType, "")));
|
||||||
|
|
||||||
await _locations.UpdateOneAsync(
|
await _locations.UpdateOneAsync(
|
||||||
emptyBuildingFilter,
|
capturableFilter,
|
||||||
Builders<Location>.Update
|
Builders<Location>.Update
|
||||||
.Set(x => x.OwnerUsername, username)
|
.Set(x => x.OwnerUsername, username)
|
||||||
.Set(x => x.Kind, "Claimed")
|
.Set(x => x.Kind, "Claimed")
|
||||||
|
|||||||
@@ -24,7 +24,8 @@
|
|||||||
"HeadquartersGoldPerMinute": 10,
|
"HeadquartersGoldPerMinute": 10,
|
||||||
"TownHallGoldCapacity": 500,
|
"TownHallGoldCapacity": 500,
|
||||||
"TownHallWoodCapacity": 100,
|
"TownHallWoodCapacity": 100,
|
||||||
"TownHallOreCapacity": 100
|
"TownHallOreCapacity": 100,
|
||||||
|
"TownHallFoodCapacity": 100
|
||||||
},
|
},
|
||||||
"Units": {
|
"Units": {
|
||||||
"ScoutGoldCost": 50,
|
"ScoutGoldCost": 50,
|
||||||
@@ -38,7 +39,9 @@
|
|||||||
"LogCampBuildSeconds": 60,
|
"LogCampBuildSeconds": 60,
|
||||||
"MineOrePerMinute": 5,
|
"MineOrePerMinute": 5,
|
||||||
"MineBuildSeconds": 60,
|
"MineBuildSeconds": 60,
|
||||||
|
"FarmFoodPerMinute": 5,
|
||||||
"BarracksBuildSeconds": 60,
|
"BarracksBuildSeconds": 60,
|
||||||
|
"FarmBuildSeconds": 60,
|
||||||
"BarracksGoldCost": 500,
|
"BarracksGoldCost": 500,
|
||||||
"BarracksWoodCost": 100,
|
"BarracksWoodCost": 100,
|
||||||
"BarracksOreCost": 100
|
"BarracksOreCost": 100
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ data:
|
|||||||
Resources__TownHallGoldCapacity: "500"
|
Resources__TownHallGoldCapacity: "500"
|
||||||
Resources__TownHallWoodCapacity: "100"
|
Resources__TownHallWoodCapacity: "100"
|
||||||
Resources__TownHallOreCapacity: "100"
|
Resources__TownHallOreCapacity: "100"
|
||||||
|
Resources__TownHallFoodCapacity: "100"
|
||||||
Units__ScoutGoldCost: "50"
|
Units__ScoutGoldCost: "50"
|
||||||
Units__ScoutTrainingSeconds: "60"
|
Units__ScoutTrainingSeconds: "60"
|
||||||
Units__ArcherGoldCost: "100"
|
Units__ArcherGoldCost: "100"
|
||||||
@@ -25,7 +26,9 @@ data:
|
|||||||
Buildings__LogCampBuildSeconds: "60"
|
Buildings__LogCampBuildSeconds: "60"
|
||||||
Buildings__MineOrePerMinute: "5"
|
Buildings__MineOrePerMinute: "5"
|
||||||
Buildings__MineBuildSeconds: "60"
|
Buildings__MineBuildSeconds: "60"
|
||||||
|
Buildings__FarmFoodPerMinute: "5"
|
||||||
Buildings__BarracksBuildSeconds: "60"
|
Buildings__BarracksBuildSeconds: "60"
|
||||||
|
Buildings__FarmBuildSeconds: "60"
|
||||||
Buildings__BarracksGoldCost: "500"
|
Buildings__BarracksGoldCost: "500"
|
||||||
Buildings__BarracksWoodCost: "100"
|
Buildings__BarracksWoodCost: "100"
|
||||||
Buildings__BarracksOreCost: "100"
|
Buildings__BarracksOreCost: "100"
|
||||||
|
|||||||
Reference in New Issue
Block a user