adding mines
This commit is contained in:
@@ -36,12 +36,17 @@ var training_completion_refresh_requested := false
|
|||||||
var building_started_unix := 0.0
|
var building_started_unix := 0.0
|
||||||
var building_completes_unix := 0.0
|
var building_completes_unix := 0.0
|
||||||
var building_completion_refresh_requested := false
|
var building_completion_refresh_requested := false
|
||||||
|
var active_building_label := "Build"
|
||||||
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 selected_q := 0
|
var selected_q := 0
|
||||||
var selected_r := 0
|
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_is_home := false
|
||||||
|
var completed_scout_count := 0
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@@ -239,6 +244,7 @@ func _build_ui() -> void:
|
|||||||
building_box.add_child(building_bar)
|
building_box.add_child(building_bar)
|
||||||
|
|
||||||
train_button = _small_button("Train Scout 50g")
|
train_button = _small_button("Train Scout 50g")
|
||||||
|
train_button.visible = false
|
||||||
train_button.pressed.connect(_train_scout)
|
train_button.pressed.connect(_train_scout)
|
||||||
bottom_content.add_child(train_button)
|
bottom_content.add_child(train_button)
|
||||||
|
|
||||||
@@ -252,6 +258,11 @@ func _build_ui() -> void:
|
|||||||
build_log_camp_button.pressed.connect(_build_log_camp)
|
build_log_camp_button.pressed.connect(_build_log_camp)
|
||||||
bottom_content.add_child(build_log_camp_button)
|
bottom_content.add_child(build_log_camp_button)
|
||||||
|
|
||||||
|
build_mine_button = _small_button("Build Mine")
|
||||||
|
build_mine_button.disabled = true
|
||||||
|
build_mine_button.pressed.connect(_build_mine)
|
||||||
|
bottom_content.add_child(build_mine_button)
|
||||||
|
|
||||||
http_request = HTTPRequest.new()
|
http_request = HTTPRequest.new()
|
||||||
http_request.request_completed.connect(_on_home_request_completed)
|
http_request.request_completed.connect(_on_home_request_completed)
|
||||||
add_child(http_request)
|
add_child(http_request)
|
||||||
@@ -298,15 +309,63 @@ func _on_tile_selected(q: int, r: int, terrain: String) -> void:
|
|||||||
selected_q = q
|
selected_q = q
|
||||||
selected_r = r
|
selected_r = r
|
||||||
selected_can_claim = terrain.contains("Unclaimed")
|
selected_can_claim = terrain.contains("Unclaimed")
|
||||||
selected_can_build_log_camp = terrain.contains("Forest") and terrain.contains("Your territory") and not terrain.contains("Log Camp")
|
selected_is_home = _selected_tile_is_home()
|
||||||
|
selected_can_build_log_camp = _can_build_log_camp_on_selected_tile()
|
||||||
|
selected_can_build_mine = _can_build_mine_on_selected_tile()
|
||||||
|
if train_button:
|
||||||
|
train_button.visible = selected_is_home
|
||||||
if claim_button:
|
if claim_button:
|
||||||
claim_button.disabled = not selected_can_claim
|
claim_button.disabled = not _can_claim_selected_tile()
|
||||||
if build_log_camp_button:
|
if build_log_camp_button:
|
||||||
build_log_camp_button.disabled = not selected_can_build_log_camp
|
build_log_camp_button.disabled = not selected_can_build_log_camp
|
||||||
|
if build_mine_button:
|
||||||
|
build_mine_button.disabled = not selected_can_build_mine
|
||||||
if coordinate_label:
|
if coordinate_label:
|
||||||
coordinate_label.text = "Selected q:%d r:%d | %s territory" % [q, r, terrain]
|
coordinate_label.text = "Selected q:%d r:%d | %s territory" % [q, r, terrain]
|
||||||
|
|
||||||
|
|
||||||
|
func _can_build_log_camp_on_selected_tile() -> bool:
|
||||||
|
return _can_build_on_selected_tile("Forest")
|
||||||
|
|
||||||
|
|
||||||
|
func _can_build_mine_on_selected_tile() -> bool:
|
||||||
|
return _can_build_on_selected_tile("Ore")
|
||||||
|
|
||||||
|
|
||||||
|
func _can_build_on_selected_tile(required_terrain: String) -> bool:
|
||||||
|
if not grid_view:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var location: Dictionary = grid_view.get_visible_location(selected_q, selected_r)
|
||||||
|
if location.is_empty():
|
||||||
|
return false
|
||||||
|
|
||||||
|
var username: String = str(session.get("username", ""))
|
||||||
|
var owner_username: String = str(location.get("ownerUsername", ""))
|
||||||
|
var terrain: String = str(location.get("terrain", ""))
|
||||||
|
var building_type: String = str(location.get("buildingType", ""))
|
||||||
|
|
||||||
|
return owner_username == username and terrain == required_terrain and building_type.is_empty()
|
||||||
|
|
||||||
|
|
||||||
|
func _can_claim_selected_tile() -> bool:
|
||||||
|
return selected_can_claim and completed_scout_count > 0
|
||||||
|
|
||||||
|
|
||||||
|
func _selected_tile_is_home() -> bool:
|
||||||
|
if not grid_view:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var location: Dictionary = grid_view.get_visible_location(selected_q, selected_r)
|
||||||
|
if location.is_empty():
|
||||||
|
return false
|
||||||
|
|
||||||
|
var username: String = str(session.get("username", ""))
|
||||||
|
var owner_username: String = str(location.get("ownerUsername", ""))
|
||||||
|
var kind: String = str(location.get("kind", ""))
|
||||||
|
return owner_username == username and kind == "Home"
|
||||||
|
|
||||||
|
|
||||||
func _session_name() -> String:
|
func _session_name() -> String:
|
||||||
if not session.is_empty():
|
if not session.is_empty():
|
||||||
var session_username: String = str(session.get("username", "Signed in"))
|
var session_username: String = str(session.get("username", "Signed in"))
|
||||||
@@ -457,7 +516,9 @@ func _on_resources_request_completed(result: int, response_code: int, _headers:
|
|||||||
var gold_per_minute: int = int(resources.get("goldPerMinute", 0))
|
var gold_per_minute: int = int(resources.get("goldPerMinute", 0))
|
||||||
var wood: int = int(resources.get("wood", 0))
|
var wood: int = int(resources.get("wood", 0))
|
||||||
var wood_per_minute: int = int(resources.get("woodPerMinute", 0))
|
var wood_per_minute: int = int(resources.get("woodPerMinute", 0))
|
||||||
gold_label.text = "Gold: %d (+%d/min) | Wood: %d (+%d/min)" % [gold, gold_per_minute, wood, wood_per_minute]
|
var ore: int = int(resources.get("ore", 0))
|
||||||
|
var ore_per_minute: int = int(resources.get("orePerMinute", 0))
|
||||||
|
gold_label.text = "Gold: %d (+%d/min) | Wood: %d (+%d/min) | Ore: %d (+%d/min)" % [gold, gold_per_minute, wood, wood_per_minute, ore, ore_per_minute]
|
||||||
|
|
||||||
var anchor_text: String = str(resources.get("lastGoldGeneratedAtUtc", ""))
|
var anchor_text: String = str(resources.get("lastGoldGeneratedAtUtc", ""))
|
||||||
gold_tick_anchor_unix = _parse_utc_timestamp(anchor_text)
|
gold_tick_anchor_unix = _parse_utc_timestamp(anchor_text)
|
||||||
@@ -502,7 +563,10 @@ func _on_units_request_completed(result: int, response_code: int, _headers: Pack
|
|||||||
if typeof(raw_training) == TYPE_ARRAY:
|
if typeof(raw_training) == TYPE_ARRAY:
|
||||||
training = raw_training
|
training = raw_training
|
||||||
|
|
||||||
unit_label.text = "Scouts: %d | Queue: %d" % [int(units.get("completedScouts", 0)), training.size()]
|
completed_scout_count = int(units.get("completedScouts", 0))
|
||||||
|
unit_label.text = "Scouts: %d | Queue: %d" % [completed_scout_count, training.size()]
|
||||||
|
if claim_button:
|
||||||
|
claim_button.disabled = not _can_claim_selected_tile()
|
||||||
|
|
||||||
if training.is_empty():
|
if training.is_empty():
|
||||||
training_started_unix = 0.0
|
training_started_unix = 0.0
|
||||||
@@ -573,6 +637,9 @@ func _claim_selected_tile() -> void:
|
|||||||
if not selected_can_claim:
|
if not selected_can_claim:
|
||||||
coordinate_label.text = "Select a visible unclaimed tile to send a scout."
|
coordinate_label.text = "Select a visible unclaimed tile to send a scout."
|
||||||
return
|
return
|
||||||
|
if completed_scout_count <= 0:
|
||||||
|
coordinate_label.text = "Train a scout before claiming territory."
|
||||||
|
return
|
||||||
|
|
||||||
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():
|
||||||
@@ -623,16 +690,32 @@ func _build_log_camp() -> void:
|
|||||||
coordinate_label.text = "Select controlled Forest territory without a building."
|
coordinate_label.text = "Select controlled Forest territory without a building."
|
||||||
return
|
return
|
||||||
|
|
||||||
|
_request_building("LogCamp")
|
||||||
|
|
||||||
|
|
||||||
|
func _build_mine() -> void:
|
||||||
|
if not selected_can_build_mine:
|
||||||
|
coordinate_label.text = "Select controlled Ore territory without a building."
|
||||||
|
return
|
||||||
|
|
||||||
|
_request_building("Mine")
|
||||||
|
|
||||||
|
|
||||||
|
func _request_building(building_type: String) -> 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():
|
||||||
coordinate_label.text = "No auth token available. Log Camp was not built."
|
coordinate_label.text = "No auth token available. %s was not built." % building_type
|
||||||
return
|
return
|
||||||
|
|
||||||
if build_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
if build_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||||
return
|
return
|
||||||
|
|
||||||
build_log_camp_button.disabled = true
|
if building_type == "Mine":
|
||||||
coordinate_label.text = "Building Log Camp at q:%d r:%d..." % [selected_q, selected_r]
|
build_mine_button.disabled = true
|
||||||
|
else:
|
||||||
|
build_log_camp_button.disabled = true
|
||||||
|
|
||||||
|
coordinate_label.text = "Building %s at q:%d r:%d..." % [building_type, selected_q, selected_r]
|
||||||
var error: int = build_request.request(
|
var error: int = build_request.request(
|
||||||
LOCATIONS_BASE_URL + "/api/locations/build",
|
LOCATIONS_BASE_URL + "/api/locations/build",
|
||||||
PackedStringArray([
|
PackedStringArray([
|
||||||
@@ -640,36 +723,42 @@ func _build_log_camp() -> void:
|
|||||||
"Authorization: Bearer %s" % access_token
|
"Authorization: Bearer %s" % access_token
|
||||||
]),
|
]),
|
||||||
HTTPClient.METHOD_POST,
|
HTTPClient.METHOD_POST,
|
||||||
JSON.stringify({ "q": selected_q, "r": selected_r, "buildingType": "LogCamp" })
|
JSON.stringify({ "q": selected_q, "r": selected_r, "buildingType": building_type })
|
||||||
)
|
)
|
||||||
if error != OK:
|
if error != OK:
|
||||||
build_log_camp_button.disabled = false
|
build_log_camp_button.disabled = not selected_can_build_log_camp
|
||||||
|
build_mine_button.disabled = not selected_can_build_mine
|
||||||
coordinate_label.text = "Could not contact the locations service."
|
coordinate_label.text = "Could not contact the locations service."
|
||||||
|
|
||||||
|
|
||||||
func _on_build_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
func _on_build_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||||
var text: String = body.get_string_from_utf8()
|
var text: String = body.get_string_from_utf8()
|
||||||
if result != HTTPRequest.RESULT_SUCCESS:
|
if result != HTTPRequest.RESULT_SUCCESS:
|
||||||
coordinate_label.text = "Log Camp build request failed."
|
coordinate_label.text = "Build request failed."
|
||||||
build_log_camp_button.disabled = not selected_can_build_log_camp
|
build_log_camp_button.disabled = not selected_can_build_log_camp
|
||||||
|
build_mine_button.disabled = not selected_can_build_mine
|
||||||
return
|
return
|
||||||
|
|
||||||
if response_code < 200 or response_code >= 300:
|
if response_code < 200 or response_code >= 300:
|
||||||
coordinate_label.text = "Log Camp build failed: %s" % text
|
coordinate_label.text = "Build failed: %s" % text
|
||||||
build_log_camp_button.disabled = not selected_can_build_log_camp
|
build_log_camp_button.disabled = not selected_can_build_log_camp
|
||||||
|
build_mine_button.disabled = not selected_can_build_mine
|
||||||
_refresh_player_state()
|
_refresh_player_state()
|
||||||
return
|
return
|
||||||
|
|
||||||
selected_can_build_log_camp = false
|
selected_can_build_log_camp = false
|
||||||
|
selected_can_build_mine = false
|
||||||
build_log_camp_button.disabled = true
|
build_log_camp_button.disabled = true
|
||||||
|
build_mine_button.disabled = true
|
||||||
var parsed = JSON.parse_string(text)
|
var parsed = JSON.parse_string(text)
|
||||||
if typeof(parsed) == TYPE_DICTIONARY:
|
if typeof(parsed) == TYPE_DICTIONARY:
|
||||||
var location: Dictionary = parsed
|
var location: Dictionary = parsed
|
||||||
|
active_building_label = _building_display_name(str(location.get("buildingType", "Building")))
|
||||||
building_started_unix = _parse_utc_timestamp(str(location.get("buildingStartedAtUtc", "")))
|
building_started_unix = _parse_utc_timestamp(str(location.get("buildingStartedAtUtc", "")))
|
||||||
building_completes_unix = _parse_utc_timestamp(str(location.get("buildingCompletesAtUtc", "")))
|
building_completes_unix = _parse_utc_timestamp(str(location.get("buildingCompletesAtUtc", "")))
|
||||||
building_completion_refresh_requested = false
|
building_completion_refresh_requested = false
|
||||||
_update_building_timer()
|
_update_building_timer()
|
||||||
coordinate_label.text = "Log Camp construction started. Completion takes 1 minute."
|
coordinate_label.text = "%s construction started." % active_building_label
|
||||||
_load_visible_locations()
|
_load_visible_locations()
|
||||||
_refresh_player_state()
|
_refresh_player_state()
|
||||||
|
|
||||||
@@ -733,9 +822,9 @@ func _update_building_timer() -> void:
|
|||||||
building_bar.value = elapsed / duration
|
building_bar.value = elapsed / duration
|
||||||
|
|
||||||
if remaining > 0:
|
if remaining > 0:
|
||||||
building_label.text = "Log Camp: %ds" % remaining
|
building_label.text = "%s: %ds" % [active_building_label, remaining]
|
||||||
else:
|
else:
|
||||||
building_label.text = "Log Camp: ready"
|
building_label.text = "%s: ready" % active_building_label
|
||||||
|
|
||||||
if remaining <= 0 and not building_completion_refresh_requested:
|
if remaining <= 0 and not building_completion_refresh_requested:
|
||||||
building_completion_refresh_requested = true
|
building_completion_refresh_requested = true
|
||||||
@@ -746,6 +835,7 @@ func _update_building_timer() -> void:
|
|||||||
func _sync_active_building_timer(locations: Array, username: String) -> void:
|
func _sync_active_building_timer(locations: Array, username: String) -> void:
|
||||||
var best_started := 0.0
|
var best_started := 0.0
|
||||||
var best_completes := 0.0
|
var best_completes := 0.0
|
||||||
|
var best_label := "Build"
|
||||||
|
|
||||||
for item in locations:
|
for item in locations:
|
||||||
if typeof(item) != TYPE_DICTIONARY:
|
if typeof(item) != TYPE_DICTIONARY:
|
||||||
@@ -754,7 +844,8 @@ func _sync_active_building_timer(locations: Array, username: String) -> void:
|
|||||||
var location: Dictionary = item
|
var location: Dictionary = item
|
||||||
if str(location.get("ownerUsername", "")) != username:
|
if str(location.get("ownerUsername", "")) != username:
|
||||||
continue
|
continue
|
||||||
if str(location.get("buildingType", "")) != "LogCamp":
|
var building_type: String = str(location.get("buildingType", ""))
|
||||||
|
if building_type.is_empty():
|
||||||
continue
|
continue
|
||||||
if str(location.get("buildingStatus", "")) != "Building":
|
if str(location.get("buildingStatus", "")) != "Building":
|
||||||
continue
|
continue
|
||||||
@@ -766,13 +857,25 @@ func _sync_active_building_timer(locations: Array, username: String) -> void:
|
|||||||
if best_completes <= 0.0 or completes < best_completes:
|
if best_completes <= 0.0 or completes < best_completes:
|
||||||
best_started = started
|
best_started = started
|
||||||
best_completes = completes
|
best_completes = completes
|
||||||
|
best_label = _building_display_name(building_type)
|
||||||
|
|
||||||
building_started_unix = best_started
|
building_started_unix = best_started
|
||||||
building_completes_unix = best_completes
|
building_completes_unix = best_completes
|
||||||
|
active_building_label = best_label
|
||||||
building_completion_refresh_requested = false
|
building_completion_refresh_requested = false
|
||||||
_update_building_timer()
|
_update_building_timer()
|
||||||
|
|
||||||
|
|
||||||
|
func _building_display_name(building_type: String) -> String:
|
||||||
|
match building_type:
|
||||||
|
"LogCamp":
|
||||||
|
return "Log Camp"
|
||||||
|
"Mine":
|
||||||
|
return "Mine"
|
||||||
|
_:
|
||||||
|
return "Build"
|
||||||
|
|
||||||
|
|
||||||
func _parse_utc_timestamp(timestamp: String) -> float:
|
func _parse_utc_timestamp(timestamp: String) -> float:
|
||||||
if timestamp.is_empty():
|
if timestamp.is_empty():
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|||||||
@@ -163,9 +163,13 @@ func _draw_tile(tile: Dictionary) -> void:
|
|||||||
var visible_location: Dictionary = visible_tiles.get(key, {})
|
var visible_location: Dictionary = visible_tiles.get(key, {})
|
||||||
var building_type: String = str(visible_location.get("buildingType", ""))
|
var building_type: String = str(visible_location.get("buildingType", ""))
|
||||||
var building_status: String = str(visible_location.get("buildingStatus", ""))
|
var building_status: String = str(visible_location.get("buildingStatus", ""))
|
||||||
if building_type == "LogCamp" and (building_status == "Built" or building_status.is_empty()):
|
if coord == home_tile:
|
||||||
|
_draw_town_hall_marker(center, height)
|
||||||
|
elif building_type == "LogCamp" and (building_status == "Built" or building_status.is_empty()):
|
||||||
_draw_log_camp_marker(center, height)
|
_draw_log_camp_marker(center, height)
|
||||||
elif building_type == "LogCamp":
|
elif building_type == "Mine" and (building_status == "Built" or building_status.is_empty()):
|
||||||
|
_draw_mine_marker(center, height)
|
||||||
|
elif not building_type.is_empty():
|
||||||
_draw_building_marker(center, height)
|
_draw_building_marker(center, height)
|
||||||
|
|
||||||
|
|
||||||
@@ -301,6 +305,61 @@ func _draw_log_camp_marker(center: Vector2, height: float) -> void:
|
|||||||
draw_line(marker_center + Vector2(-width * 0.38, marker_height * 0.86), marker_center + Vector2(width * 0.38, marker_height * 0.86), log_color.darkened(0.12), 3.0 * zoom)
|
draw_line(marker_center + Vector2(-width * 0.38, marker_height * 0.86), marker_center + Vector2(width * 0.38, marker_height * 0.86), log_color.darkened(0.12), 3.0 * zoom)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_mine_marker(center: Vector2, height: float) -> void:
|
||||||
|
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 2.0)
|
||||||
|
var width: float = 20.0 * zoom
|
||||||
|
var marker_height: float = 13.0 * zoom
|
||||||
|
var rock_color := Color(0.28, 0.31, 0.34)
|
||||||
|
var entry_color := Color(0.08, 0.09, 0.1)
|
||||||
|
var beam_color := Color(0.62, 0.46, 0.26)
|
||||||
|
var ore_color := Color(0.72, 0.82, 0.9)
|
||||||
|
|
||||||
|
var mound := PackedVector2Array([
|
||||||
|
marker_center + Vector2(-width * 0.56, marker_height * 0.48),
|
||||||
|
marker_center + Vector2(-width * 0.32, -marker_height * 0.22),
|
||||||
|
marker_center + Vector2(0, -marker_height * 0.52),
|
||||||
|
marker_center + Vector2(width * 0.38, -marker_height * 0.18),
|
||||||
|
marker_center + Vector2(width * 0.58, marker_height * 0.48)
|
||||||
|
])
|
||||||
|
draw_colored_polygon(mound, rock_color)
|
||||||
|
draw_rect(Rect2(marker_center + Vector2(-width * 0.18, marker_height * 0.02), Vector2(width * 0.36, marker_height * 0.48)), entry_color, true)
|
||||||
|
draw_line(marker_center + Vector2(-width * 0.28, marker_height * 0.02), marker_center + Vector2(width * 0.28, marker_height * 0.02), beam_color, 2.0 * zoom)
|
||||||
|
draw_line(marker_center + Vector2(-width * 0.18, marker_height * 0.02), marker_center + Vector2(-width * 0.18, marker_height * 0.5), beam_color, 2.0 * zoom)
|
||||||
|
draw_line(marker_center + Vector2(width * 0.18, marker_height * 0.02), marker_center + Vector2(width * 0.18, marker_height * 0.5), beam_color, 2.0 * zoom)
|
||||||
|
draw_circle(marker_center + Vector2(width * 0.34, -marker_height * 0.1), 2.0 * zoom, ore_color)
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_town_hall_marker(center: Vector2, height: float) -> void:
|
||||||
|
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 3.0)
|
||||||
|
var width: float = 24.0 * zoom
|
||||||
|
var marker_height: float = 18.0 * zoom
|
||||||
|
var wall_color := Color(0.76, 0.58, 0.32)
|
||||||
|
var roof_color := Color(0.42, 0.19, 0.12)
|
||||||
|
var trim_color := Color(0.98, 0.78, 0.3)
|
||||||
|
var shadow_color := Color(0.12, 0.08, 0.04)
|
||||||
|
|
||||||
|
var body_rect := Rect2(marker_center + Vector2(-width * 0.38, -marker_height * 0.02), Vector2(width * 0.76, marker_height * 0.62))
|
||||||
|
var roof := PackedVector2Array([
|
||||||
|
marker_center + Vector2(-width * 0.54, -marker_height * 0.02),
|
||||||
|
marker_center + Vector2(0, -marker_height * 0.72),
|
||||||
|
marker_center + Vector2(width * 0.54, -marker_height * 0.02)
|
||||||
|
])
|
||||||
|
var tower_rect := Rect2(marker_center + Vector2(-width * 0.13, -marker_height * 0.45), Vector2(width * 0.26, marker_height * 0.36))
|
||||||
|
var tower_roof := PackedVector2Array([
|
||||||
|
marker_center + Vector2(-width * 0.20, -marker_height * 0.45),
|
||||||
|
marker_center + Vector2(0, -marker_height * 0.84),
|
||||||
|
marker_center + Vector2(width * 0.20, -marker_height * 0.45)
|
||||||
|
])
|
||||||
|
|
||||||
|
draw_rect(Rect2(body_rect.position + Vector2(1, 1) * zoom, body_rect.size), shadow_color, true)
|
||||||
|
draw_colored_polygon(roof, roof_color)
|
||||||
|
draw_rect(body_rect, wall_color, true)
|
||||||
|
draw_rect(tower_rect, wall_color.lightened(0.08), true)
|
||||||
|
draw_colored_polygon(tower_roof, roof_color.darkened(0.05))
|
||||||
|
draw_line(body_rect.position + Vector2(0, body_rect.size.y), body_rect.position + body_rect.size, trim_color, 2.0 * zoom)
|
||||||
|
draw_rect(Rect2(marker_center + Vector2(-width * 0.08, marker_height * 0.28), Vector2(width * 0.16, marker_height * 0.32)), shadow_color.lightened(0.2), true)
|
||||||
|
|
||||||
|
|
||||||
func _draw_building_marker(center: Vector2, height: float) -> void:
|
func _draw_building_marker(center: Vector2, height: float) -> void:
|
||||||
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 1.0)
|
var marker_center: Vector2 = center + Vector2(0, -height * zoom - 1.0)
|
||||||
var width: float = 20.0 * zoom
|
var width: float = 20.0 * zoom
|
||||||
@@ -368,6 +427,13 @@ func set_visible_locations(locations: Array, username: String) -> void:
|
|||||||
queue_redraw()
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func get_visible_location(q: int, r: int) -> Dictionary:
|
||||||
|
var key: String = _tile_key(q, r)
|
||||||
|
if visible_tiles.has(key):
|
||||||
|
return visible_tiles[key]
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
func _tile_key(q: int, r: int) -> String:
|
func _tile_key(q: int, r: int) -> String:
|
||||||
return "%d,%d" % [q, r]
|
return "%d,%d" % [q, r]
|
||||||
|
|
||||||
@@ -420,6 +486,8 @@ func _tile_display_label(key: String, data: Dictionary) -> String:
|
|||||||
var building_label: String = ""
|
var building_label: String = ""
|
||||||
if building_type == "LogCamp":
|
if building_type == "LogCamp":
|
||||||
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":
|
||||||
|
building_label = " | Mine" if building_status == "Built" or building_status.is_empty() else " | Mine building"
|
||||||
|
|
||||||
if home_tile == Vector2i(int(data.get("q", 0)), int(data.get("r", 0))):
|
if home_tile == Vector2i(int(data.get("q", 0)), int(data.get("r", 0))):
|
||||||
return "%s | Your home%s" % [terrain, building_label]
|
return "%s | Your home%s" % [terrain, building_label]
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class LocationResponse
|
|||||||
Label = location.Label,
|
Label = location.Label,
|
||||||
Level = location.Level,
|
Level = location.Level,
|
||||||
BuildingType = location.BuildingType,
|
BuildingType = location.BuildingType,
|
||||||
BuildingStatus = location.BuildingType == "LogCamp" && string.IsNullOrWhiteSpace(location.BuildingStatus)
|
BuildingStatus = (location.BuildingType == "LogCamp" || location.BuildingType == "Mine") && string.IsNullOrWhiteSpace(location.BuildingStatus)
|
||||||
? "Built"
|
? "Built"
|
||||||
: location.BuildingStatus,
|
: location.BuildingStatus,
|
||||||
BuildingStartedAtUtc = location.BuildingStartedAtUtc,
|
BuildingStartedAtUtc = location.BuildingStartedAtUtc,
|
||||||
|
|||||||
@@ -14,8 +14,11 @@ public class PlayerResources
|
|||||||
public int GoldPerMinute { get; set; } = 10;
|
public int GoldPerMinute { get; set; } = 10;
|
||||||
public int Wood { get; set; }
|
public int Wood { get; set; }
|
||||||
public int WoodPerMinute { get; set; }
|
public int WoodPerMinute { get; set; }
|
||||||
|
public int Ore { get; set; }
|
||||||
|
public int OrePerMinute { get; set; }
|
||||||
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 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ public class PlayerResourcesResponse
|
|||||||
public int GoldPerMinute { get; set; }
|
public int GoldPerMinute { get; set; }
|
||||||
public int Wood { get; set; }
|
public int Wood { get; set; }
|
||||||
public int WoodPerMinute { get; set; }
|
public int WoodPerMinute { get; set; }
|
||||||
|
public int Ore { get; set; }
|
||||||
|
public int OrePerMinute { 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 UpdatedAtUtc { get; set; }
|
public DateTime UpdatedAtUtc { get; set; }
|
||||||
|
|
||||||
public static PlayerResourcesResponse FromResources(PlayerResources resources) => new()
|
public static PlayerResourcesResponse FromResources(PlayerResources resources) => new()
|
||||||
@@ -18,8 +21,11 @@ public class PlayerResourcesResponse
|
|||||||
GoldPerMinute = resources.GoldPerMinute,
|
GoldPerMinute = resources.GoldPerMinute,
|
||||||
Wood = resources.Wood,
|
Wood = resources.Wood,
|
||||||
WoodPerMinute = resources.WoodPerMinute,
|
WoodPerMinute = resources.WoodPerMinute,
|
||||||
|
Ore = resources.Ore,
|
||||||
|
OrePerMinute = resources.OrePerMinute,
|
||||||
LastGoldGeneratedAtUtc = resources.LastGoldGeneratedAtUtc,
|
LastGoldGeneratedAtUtc = resources.LastGoldGeneratedAtUtc,
|
||||||
LastWoodGeneratedAtUtc = resources.LastWoodGeneratedAtUtc,
|
LastWoodGeneratedAtUtc = resources.LastWoodGeneratedAtUtc,
|
||||||
|
LastOreGeneratedAtUtc = resources.LastOreGeneratedAtUtc,
|
||||||
UpdatedAtUtc = resources.UpdatedAtUtc
|
UpdatedAtUtc = resources.UpdatedAtUtc
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,26 +28,28 @@ locations are unowned `Open` records until claimed by a player.
|
|||||||
|
|
||||||
Player resource state is stored server-side in the `PlayerResources` collection.
|
Player resource state is stored server-side in the `PlayerResources` collection.
|
||||||
New players start with 100 gold. A player's headquarters generates 10 gold per
|
New players start with 100 gold. A player's headquarters generates 10 gold per
|
||||||
minute. Log Camps generate wood. Generation is applied lazily when the resource
|
minute. Log Camps generate wood and Mines generate ore. Generation is applied
|
||||||
record is read.
|
lazily when the resource record is read.
|
||||||
|
|
||||||
## Units
|
## Units
|
||||||
|
|
||||||
Unit training is stored server-side in the `UnitTraining` collection. The first
|
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.
|
unit type is `Scout`, which costs 50 gold and takes 60 seconds to train.
|
||||||
Finished training is completed lazily when unit state is read. Claiming an
|
Finished training is completed lazily when unit state is read. Claiming an
|
||||||
unclaimed visible location consumes one completed Scout.
|
unclaimed visible location consumes one completed Scout by deleting that Scout's
|
||||||
|
training record.
|
||||||
|
|
||||||
## Buildings
|
## Buildings
|
||||||
|
|
||||||
Buildings are stored on location records. The first building type is `LogCamp`,
|
Buildings are stored on location records. `LogCamp` can be built on controlled
|
||||||
which can be built on controlled Forest territory, takes 60 seconds to build,
|
Forest territory, takes 60 seconds to build, and adds 5 wood per minute after it
|
||||||
and adds 5 wood per minute to the owning player's resource generation after it
|
finishes. `Mine` can be built on controlled Ore territory, takes 60 seconds to
|
||||||
finishes. Each location has one building slot; a building under construction
|
build, and adds 5 ore per minute after it finishes. Each location has one
|
||||||
occupies that slot.
|
building slot; a building under construction occupies that slot.
|
||||||
|
|
||||||
Timer settings are stored in the MongoDB `GameSettings` collection and are
|
Timer settings are stored in the MongoDB `GameSettings` collection and are
|
||||||
seeded on first read:
|
seeded on first read:
|
||||||
|
|
||||||
- `ScoutTrainingSeconds`
|
- `ScoutTrainingSeconds`
|
||||||
- `LogCampBuildSeconds`
|
- `LogCampBuildSeconds`
|
||||||
|
- `MineBuildSeconds`
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public class GameSettingsService
|
|||||||
{
|
{
|
||||||
public const string ScoutTrainingSeconds = "ScoutTrainingSeconds";
|
public const string ScoutTrainingSeconds = "ScoutTrainingSeconds";
|
||||||
public const string LogCampBuildSeconds = "LogCampBuildSeconds";
|
public const string LogCampBuildSeconds = "LogCampBuildSeconds";
|
||||||
|
public const string MineBuildSeconds = "MineBuildSeconds";
|
||||||
|
|
||||||
private readonly IMongoCollection<GameSetting> _settings;
|
private readonly IMongoCollection<GameSetting> _settings;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ public class LocationService
|
|||||||
private readonly int _homeSearchRadius;
|
private readonly int _homeSearchRadius;
|
||||||
private readonly int _visibilityDepth;
|
private readonly int _visibilityDepth;
|
||||||
private readonly int _logCampWoodPerMinute;
|
private readonly int _logCampWoodPerMinute;
|
||||||
|
private readonly int _mineOrePerMinute;
|
||||||
private readonly int _defaultLogCampBuildSeconds;
|
private readonly int _defaultLogCampBuildSeconds;
|
||||||
|
private readonly int _defaultMineBuildSeconds;
|
||||||
|
|
||||||
public LocationService(IConfiguration cfg, ResourceService resources, GameSettingsService settings)
|
public LocationService(IConfiguration cfg, ResourceService resources, GameSettingsService settings)
|
||||||
{
|
{
|
||||||
@@ -29,9 +31,15 @@ public class LocationService
|
|||||||
_logCampWoodPerMinute = int.TryParse(cfg["Buildings:LogCampWoodPerMinute"], out var logCampWoodPerMinute)
|
_logCampWoodPerMinute = int.TryParse(cfg["Buildings:LogCampWoodPerMinute"], out var logCampWoodPerMinute)
|
||||||
? Math.Max(1, logCampWoodPerMinute)
|
? Math.Max(1, logCampWoodPerMinute)
|
||||||
: 5;
|
: 5;
|
||||||
|
_mineOrePerMinute = int.TryParse(cfg["Buildings:MineOrePerMinute"], out var mineOrePerMinute)
|
||||||
|
? Math.Max(1, mineOrePerMinute)
|
||||||
|
: 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;
|
||||||
|
_defaultMineBuildSeconds = int.TryParse(cfg["Buildings:MineBuildSeconds"], out var mineBuildSeconds)
|
||||||
|
? Math.Max(1, mineBuildSeconds)
|
||||||
|
: 60;
|
||||||
|
|
||||||
var coordinateIndex = Builders<Location>.IndexKeys
|
var coordinateIndex = Builders<Location>.IndexKeys
|
||||||
.Ascending(x => x.Q)
|
.Ascending(x => x.Q)
|
||||||
@@ -123,7 +131,8 @@ public class LocationService
|
|||||||
|
|
||||||
public async Task<Location?> BuildAsync(BuildLocationRequest request, string username)
|
public async Task<Location?> BuildAsync(BuildLocationRequest request, string username)
|
||||||
{
|
{
|
||||||
if (!string.Equals(request.BuildingType, "LogCamp", StringComparison.OrdinalIgnoreCase))
|
var buildingType = NormalizeBuildingType(request.BuildingType);
|
||||||
|
if (buildingType is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Unsupported building type.", nameof(request.BuildingType));
|
throw new ArgumentException("Unsupported building type.", nameof(request.BuildingType));
|
||||||
}
|
}
|
||||||
@@ -140,17 +149,24 @@ public class LocationService
|
|||||||
throw new InvalidOperationException("This location already has a building or construction in progress.");
|
throw new InvalidOperationException("This location already has a building or construction in progress.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.Equals(location.Terrain, "Forest", StringComparison.OrdinalIgnoreCase))
|
var requiredTerrain = buildingType == "LogCamp" ? "Forest" : "Ore";
|
||||||
|
if (!string.Equals(location.Terrain, requiredTerrain, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Log Camps can only be built on Forest territory.");
|
throw new InvalidOperationException($"{buildingType} can only be built on {requiredTerrain} territory.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await CompleteFinishedBuildingsAsync(username);
|
await CompleteFinishedBuildingsAsync(username);
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var buildSeconds = await _settings.GetIntAsync(GameSettingsService.LogCampBuildSeconds, _defaultLogCampBuildSeconds);
|
var settingKey = buildingType == "LogCamp"
|
||||||
|
? GameSettingsService.LogCampBuildSeconds
|
||||||
|
: GameSettingsService.MineBuildSeconds;
|
||||||
|
var defaultBuildSeconds = buildingType == "LogCamp"
|
||||||
|
? _defaultLogCampBuildSeconds
|
||||||
|
: _defaultMineBuildSeconds;
|
||||||
|
var buildSeconds = await _settings.GetIntAsync(settingKey, defaultBuildSeconds);
|
||||||
var update = Builders<Location>.Update
|
var update = Builders<Location>.Update
|
||||||
.Set(x => x.BuildingType, "LogCamp")
|
.Set(x => x.BuildingType, buildingType)
|
||||||
.Set(x => x.BuildingStatus, "Building")
|
.Set(x => x.BuildingStatus, "Building")
|
||||||
.Set(x => x.BuildingStartedAtUtc, now)
|
.Set(x => x.BuildingStartedAtUtc, now)
|
||||||
.Set(x => x.BuildingCompletesAtUtc, now.AddSeconds(buildSeconds))
|
.Set(x => x.BuildingCompletesAtUtc, now.AddSeconds(buildSeconds))
|
||||||
@@ -177,7 +193,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 == "LogCamp" || x.BuildingType == "Mine") &&
|
||||||
x.BuildingStatus == "Building" &&
|
x.BuildingStatus == "Building" &&
|
||||||
x.BuildingCompletesAtUtc <= now)
|
x.BuildingCompletesAtUtc <= now)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -199,7 +215,14 @@ public class LocationService
|
|||||||
|
|
||||||
if (updated is not null)
|
if (updated is not null)
|
||||||
{
|
{
|
||||||
await _resources.AddWoodGenerationAsync(username, _logCampWoodPerMinute);
|
if (updated.BuildingType == "LogCamp")
|
||||||
|
{
|
||||||
|
await _resources.AddWoodGenerationAsync(username, _logCampWoodPerMinute);
|
||||||
|
}
|
||||||
|
else if (updated.BuildingType == "Mine")
|
||||||
|
{
|
||||||
|
await _resources.AddOreGenerationAsync(username, _mineOrePerMinute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -551,4 +574,15 @@ public class LocationService
|
|||||||
_ => "Field"
|
_ => "Field"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string? NormalizeBuildingType(string buildingType)
|
||||||
|
{
|
||||||
|
var trimmed = buildingType.Trim();
|
||||||
|
return trimmed.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"logcamp" or "log camp" => "LogCamp",
|
||||||
|
"mine" => "Mine",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ public class ResourceService
|
|||||||
.SetOnInsert(x => x.Username, username)
|
.SetOnInsert(x => x.Username, username)
|
||||||
.SetOnInsert(x => x.Gold, _startingGold)
|
.SetOnInsert(x => x.Gold, _startingGold)
|
||||||
.SetOnInsert(x => x.Wood, 0)
|
.SetOnInsert(x => x.Wood, 0)
|
||||||
|
.SetOnInsert(x => x.Ore, 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)
|
||||||
.Set(x => x.GoldPerMinute, _headquartersGoldPerMinute)
|
.Set(x => x.GoldPerMinute, _headquartersGoldPerMinute)
|
||||||
.Set(x => x.UpdatedAtUtc, now);
|
.Set(x => x.UpdatedAtUtc, now);
|
||||||
|
|
||||||
@@ -102,6 +104,28 @@ public class ResourceService
|
|||||||
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AddOreGenerationAsync(string username, int orePerMinute)
|
||||||
|
{
|
||||||
|
if (orePerMinute <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources = await EnsureAsync(username);
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var update = Builders<PlayerResources>.Update
|
||||||
|
.Inc(x => x.OrePerMinute, orePerMinute)
|
||||||
|
.Set(x => x.UpdatedAtUtc, now);
|
||||||
|
|
||||||
|
if (resources.OrePerMinute <= 0 || resources.LastOreGeneratedAtUtc.Year < 2000)
|
||||||
|
{
|
||||||
|
update = update.Set(x => x.LastOreGeneratedAtUtc, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _resources.UpdateOneAsync(x => x.Username == username, update);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<PlayerResources> ApplyGoldGenerationAsync(PlayerResources resources)
|
private async Task<PlayerResources> ApplyGoldGenerationAsync(PlayerResources resources)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
@@ -111,8 +135,11 @@ public class ResourceService
|
|||||||
var woodElapsedMinutes = resources.WoodPerMinute <= 0 || resources.LastWoodGeneratedAtUtc.Year < 2000
|
var woodElapsedMinutes = resources.WoodPerMinute <= 0 || resources.LastWoodGeneratedAtUtc.Year < 2000
|
||||||
? 0
|
? 0
|
||||||
: (int)Math.Floor((now - resources.LastWoodGeneratedAtUtc).TotalMinutes);
|
: (int)Math.Floor((now - resources.LastWoodGeneratedAtUtc).TotalMinutes);
|
||||||
|
var oreElapsedMinutes = resources.OrePerMinute <= 0 || resources.LastOreGeneratedAtUtc.Year < 2000
|
||||||
|
? 0
|
||||||
|
: (int)Math.Floor((now - resources.LastOreGeneratedAtUtc).TotalMinutes);
|
||||||
|
|
||||||
if (goldElapsedMinutes <= 0 && woodElapsedMinutes <= 0)
|
if (goldElapsedMinutes <= 0 && woodElapsedMinutes <= 0 && oreElapsedMinutes <= 0)
|
||||||
{
|
{
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
@@ -135,6 +162,13 @@ public class ResourceService
|
|||||||
.Set(x => x.LastWoodGeneratedAtUtc, resources.LastWoodGeneratedAtUtc.AddMinutes(woodElapsedMinutes));
|
.Set(x => x.LastWoodGeneratedAtUtc, resources.LastWoodGeneratedAtUtc.AddMinutes(woodElapsedMinutes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oreElapsedMinutes > 0)
|
||||||
|
{
|
||||||
|
update = update
|
||||||
|
.Inc(x => x.Ore, oreElapsedMinutes * resources.OrePerMinute)
|
||||||
|
.Set(x => x.LastOreGeneratedAtUtc, resources.LastOreGeneratedAtUtc.AddMinutes(oreElapsedMinutes));
|
||||||
|
}
|
||||||
|
|
||||||
return await _resources.FindOneAndUpdateAsync(
|
return await _resources.FindOneAndUpdateAsync(
|
||||||
x => x.Username == resources.Username,
|
x => x.Username == resources.Username,
|
||||||
update,
|
update,
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public class UnitTrainingService
|
|||||||
public async Task<PlayerUnitsResponse> GetMineAsync(string username)
|
public async Task<PlayerUnitsResponse> GetMineAsync(string username)
|
||||||
{
|
{
|
||||||
await CompleteFinishedTrainingAsync(username);
|
await CompleteFinishedTrainingAsync(username);
|
||||||
|
await _training.DeleteManyAsync(x => x.Username == username && x.Status == "Consumed");
|
||||||
|
|
||||||
var all = await _training.Find(x => x.Username == username).ToListAsync();
|
var all = await _training.Find(x => x.Username == username).ToListAsync();
|
||||||
var completedScouts = all.Count(x => x.UnitType == ScoutUnitType && x.Status == "Completed");
|
var completedScouts = all.Count(x => x.UnitType == ScoutUnitType && x.Status == "Completed");
|
||||||
@@ -85,18 +86,11 @@ public class UnitTrainingService
|
|||||||
{
|
{
|
||||||
await CompleteFinishedTrainingAsync(username);
|
await CompleteFinishedTrainingAsync(username);
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var consumed = await _training.FindOneAndDeleteAsync(
|
||||||
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",
|
x => x.Username == username && x.UnitType == ScoutUnitType && x.Status == "Completed",
|
||||||
update,
|
new FindOneAndDeleteOptions<UnitTraining>
|
||||||
new FindOneAndUpdateOptions<UnitTraining>
|
|
||||||
{
|
{
|
||||||
Sort = Builders<UnitTraining>.Sort.Ascending(x => x.CompletedAtUtc).Ascending(x => x.CreatedAtUtc),
|
Sort = Builders<UnitTraining>.Sort.Ascending(x => x.CompletedAtUtc).Ascending(x => x.CreatedAtUtc)
|
||||||
ReturnDocument = ReturnDocument.After
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return consumed is not null;
|
return consumed is not null;
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
},
|
},
|
||||||
"Buildings": {
|
"Buildings": {
|
||||||
"LogCampWoodPerMinute": 5,
|
"LogCampWoodPerMinute": 5,
|
||||||
"LogCampBuildSeconds": 60
|
"LogCampBuildSeconds": 60,
|
||||||
|
"MineOrePerMinute": 5,
|
||||||
|
"MineBuildSeconds": 60
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,3 +17,5 @@ data:
|
|||||||
Units__ScoutTrainingSeconds: "60"
|
Units__ScoutTrainingSeconds: "60"
|
||||||
Buildings__LogCampWoodPerMinute: "5"
|
Buildings__LogCampWoodPerMinute: "5"
|
||||||
Buildings__LogCampBuildSeconds: "60"
|
Buildings__LogCampBuildSeconds: "60"
|
||||||
|
Buildings__MineOrePerMinute: "5"
|
||||||
|
Buildings__MineBuildSeconds: "60"
|
||||||
|
|||||||
Reference in New Issue
Block a user