Adding units
This commit is contained in:
@@ -2,6 +2,7 @@ extends Control
|
||||
|
||||
const SESSION_PATH := "user://auth_session.json"
|
||||
const LOCATIONS_BASE_URL := "https://tloc.ranaze.com"
|
||||
const RESOURCE_REFRESH_SECONDS := 15.0
|
||||
const HexGridView := preload("res://scenes/game/hex_grid_view.gd")
|
||||
|
||||
var coordinate_label: Label
|
||||
@@ -10,10 +11,23 @@ var grid_view
|
||||
var http_request: HTTPRequest
|
||||
var visible_request: HTTPRequest
|
||||
var resources_request: HTTPRequest
|
||||
var units_request: HTTPRequest
|
||||
var train_unit_request: HTTPRequest
|
||||
var resources_timer: Timer
|
||||
var session: Dictionary = {}
|
||||
var escape_overlay: Control
|
||||
var escape_panel: PanelContainer
|
||||
var gold_label: Label
|
||||
var tick_bar: ProgressBar
|
||||
var tick_label: Label
|
||||
var gold_tick_anchor_unix := 0.0
|
||||
var gold_tick_seconds := 60.0
|
||||
var train_button: Button
|
||||
var unit_label: Label
|
||||
var training_label: Label
|
||||
var training_bar: ProgressBar
|
||||
var training_started_unix := 0.0
|
||||
var training_completes_unix := 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -22,6 +36,11 @@ func _ready() -> void:
|
||||
_assign_home_location()
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
_update_tick_bar()
|
||||
_update_training_bar()
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
_toggle_escape_menu()
|
||||
@@ -91,6 +110,27 @@ func _build_ui() -> void:
|
||||
gold_label.add_theme_color_override("font_color", Color(0.95, 0.78, 0.32))
|
||||
top_content.add_child(gold_label)
|
||||
|
||||
var tick_box := VBoxContainer.new()
|
||||
tick_box.custom_minimum_size = Vector2(130, 0)
|
||||
tick_box.add_theme_constant_override("separation", 4)
|
||||
top_content.add_child(tick_box)
|
||||
|
||||
tick_label = Label.new()
|
||||
tick_label.text = "Next: --"
|
||||
tick_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
tick_label.add_theme_font_size_override("font_size", 12)
|
||||
tick_label.add_theme_color_override("font_color", Color(0.72, 0.82, 0.78))
|
||||
tick_box.add_child(tick_label)
|
||||
|
||||
tick_bar = ProgressBar.new()
|
||||
tick_bar.custom_minimum_size = Vector2(130, 8)
|
||||
tick_bar.max_value = 1.0
|
||||
tick_bar.value = 0.0
|
||||
tick_bar.show_percentage = false
|
||||
tick_bar.add_theme_stylebox_override("background", _progress_style(Color(0.035, 0.055, 0.055), Color(0.18, 0.28, 0.26)))
|
||||
tick_bar.add_theme_stylebox_override("fill", _progress_style(Color(0.82, 0.65, 0.2), Color(0.9, 0.78, 0.36)))
|
||||
tick_box.add_child(tick_bar)
|
||||
|
||||
var user_label := Label.new()
|
||||
user_label.text = _session_name()
|
||||
user_label.add_theme_font_size_override("font_size", 15)
|
||||
@@ -123,11 +163,48 @@ func _build_ui() -> void:
|
||||
bottom_margin.add_theme_constant_override("margin_bottom", 8)
|
||||
bottom_bar.add_child(bottom_margin)
|
||||
|
||||
var bottom_content := HBoxContainer.new()
|
||||
bottom_content.add_theme_constant_override("separation", 16)
|
||||
bottom_margin.add_child(bottom_content)
|
||||
|
||||
coordinate_label = Label.new()
|
||||
coordinate_label.text = "Drag to pan. Mouse wheel zooms. Select a tile to inspect territory."
|
||||
coordinate_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
coordinate_label.add_theme_font_size_override("font_size", 14)
|
||||
coordinate_label.add_theme_color_override("font_color", Color(0.72, 0.8, 0.78))
|
||||
bottom_margin.add_child(coordinate_label)
|
||||
bottom_content.add_child(coordinate_label)
|
||||
|
||||
unit_label = Label.new()
|
||||
unit_label.text = "Scouts: --"
|
||||
unit_label.custom_minimum_size = Vector2(88, 0)
|
||||
unit_label.add_theme_font_size_override("font_size", 14)
|
||||
unit_label.add_theme_color_override("font_color", Color(0.72, 0.82, 0.78))
|
||||
bottom_content.add_child(unit_label)
|
||||
|
||||
var training_box := VBoxContainer.new()
|
||||
training_box.custom_minimum_size = Vector2(150, 0)
|
||||
training_box.add_theme_constant_override("separation", 4)
|
||||
bottom_content.add_child(training_box)
|
||||
|
||||
training_label = Label.new()
|
||||
training_label.text = "Training: idle"
|
||||
training_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
training_label.add_theme_font_size_override("font_size", 12)
|
||||
training_label.add_theme_color_override("font_color", Color(0.72, 0.82, 0.78))
|
||||
training_box.add_child(training_label)
|
||||
|
||||
training_bar = ProgressBar.new()
|
||||
training_bar.custom_minimum_size = Vector2(150, 8)
|
||||
training_bar.max_value = 1.0
|
||||
training_bar.value = 0.0
|
||||
training_bar.show_percentage = false
|
||||
training_bar.add_theme_stylebox_override("background", _progress_style(Color(0.035, 0.055, 0.055), Color(0.18, 0.28, 0.26)))
|
||||
training_bar.add_theme_stylebox_override("fill", _progress_style(Color(0.28, 0.62, 0.72), Color(0.43, 0.82, 0.92)))
|
||||
training_box.add_child(training_bar)
|
||||
|
||||
train_button = _small_button("Train Scout 50g")
|
||||
train_button.pressed.connect(_train_scout)
|
||||
bottom_content.add_child(train_button)
|
||||
|
||||
http_request = HTTPRequest.new()
|
||||
http_request.request_completed.connect(_on_home_request_completed)
|
||||
@@ -141,6 +218,20 @@ func _build_ui() -> void:
|
||||
resources_request.request_completed.connect(_on_resources_request_completed)
|
||||
add_child(resources_request)
|
||||
|
||||
units_request = HTTPRequest.new()
|
||||
units_request.request_completed.connect(_on_units_request_completed)
|
||||
add_child(units_request)
|
||||
|
||||
train_unit_request = HTTPRequest.new()
|
||||
train_unit_request.request_completed.connect(_on_train_unit_request_completed)
|
||||
add_child(train_unit_request)
|
||||
|
||||
resources_timer = Timer.new()
|
||||
resources_timer.wait_time = RESOURCE_REFRESH_SECONDS
|
||||
resources_timer.autostart = false
|
||||
resources_timer.timeout.connect(_refresh_player_state)
|
||||
add_child(resources_timer)
|
||||
|
||||
_build_escape_menu()
|
||||
|
||||
|
||||
@@ -259,7 +350,13 @@ func _on_visible_request_completed(result: int, response_code: int, _headers: Pa
|
||||
var visible_locations: Array = parsed
|
||||
grid_view.set_visible_locations(visible_locations, username)
|
||||
coordinate_label.text = "Visible territory loaded. Sight extends 3 hexes beyond controlled land."
|
||||
_refresh_player_state()
|
||||
resources_timer.start()
|
||||
|
||||
|
||||
func _refresh_player_state() -> void:
|
||||
_load_resources()
|
||||
_load_units()
|
||||
|
||||
|
||||
func _load_resources() -> void:
|
||||
@@ -268,6 +365,9 @@ func _load_resources() -> void:
|
||||
gold_label.text = "Gold: --"
|
||||
return
|
||||
|
||||
if resources_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
return
|
||||
|
||||
var error: int = resources_request.request(
|
||||
LOCATIONS_BASE_URL + "/api/resources/me",
|
||||
PackedStringArray([
|
||||
@@ -294,6 +394,170 @@ func _on_resources_request_completed(result: int, response_code: int, _headers:
|
||||
var gold_per_minute: int = int(resources.get("goldPerMinute", 0))
|
||||
gold_label.text = "Gold: %d (+%d/min)" % [gold, gold_per_minute]
|
||||
|
||||
var anchor_text: String = str(resources.get("lastGoldGeneratedAtUtc", ""))
|
||||
gold_tick_anchor_unix = _parse_utc_timestamp(anchor_text)
|
||||
if gold_tick_anchor_unix <= 0.0:
|
||||
gold_tick_anchor_unix = Time.get_unix_time_from_system()
|
||||
_update_tick_bar()
|
||||
|
||||
|
||||
func _load_units() -> void:
|
||||
var access_token: String = str(session.get("accessToken", ""))
|
||||
if access_token.is_empty():
|
||||
unit_label.text = "Scouts: --"
|
||||
return
|
||||
|
||||
if units_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
return
|
||||
|
||||
var error: int = units_request.request(
|
||||
LOCATIONS_BASE_URL + "/api/units/me",
|
||||
PackedStringArray([
|
||||
"Authorization: Bearer %s" % access_token
|
||||
]),
|
||||
HTTPClient.METHOD_GET
|
||||
)
|
||||
if error != OK:
|
||||
unit_label.text = "Scouts: ?"
|
||||
|
||||
|
||||
func _on_units_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
|
||||
unit_label.text = "Scouts: ?"
|
||||
return
|
||||
|
||||
var parsed = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(parsed) != TYPE_DICTIONARY:
|
||||
unit_label.text = "Scouts: ?"
|
||||
return
|
||||
|
||||
var units: Dictionary = parsed
|
||||
unit_label.text = "Scouts: %d" % int(units.get("completedScouts", 0))
|
||||
|
||||
var training: Array = []
|
||||
var raw_training = units.get("training", [])
|
||||
if typeof(raw_training) == TYPE_ARRAY:
|
||||
training = raw_training
|
||||
if training.is_empty():
|
||||
training_started_unix = 0.0
|
||||
training_completes_unix = 0.0
|
||||
_update_training_bar()
|
||||
return
|
||||
|
||||
if typeof(training[0]) != TYPE_DICTIONARY:
|
||||
return
|
||||
|
||||
var active_training: Dictionary = training[0]
|
||||
training_started_unix = _parse_utc_timestamp(str(active_training.get("startedAtUtc", "")))
|
||||
training_completes_unix = _parse_utc_timestamp(str(active_training.get("completesAtUtc", "")))
|
||||
_update_training_bar()
|
||||
|
||||
|
||||
func _train_scout() -> void:
|
||||
var access_token: String = str(session.get("accessToken", ""))
|
||||
if access_token.is_empty():
|
||||
coordinate_label.text = "No auth token available. Scout training was not started."
|
||||
return
|
||||
|
||||
if train_unit_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
return
|
||||
|
||||
train_button.disabled = true
|
||||
coordinate_label.text = "Starting scout training..."
|
||||
var error: int = train_unit_request.request(
|
||||
LOCATIONS_BASE_URL + "/api/units/train",
|
||||
PackedStringArray([
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer %s" % access_token
|
||||
]),
|
||||
HTTPClient.METHOD_POST,
|
||||
JSON.stringify({ "unitType": "Scout" })
|
||||
)
|
||||
if error != OK:
|
||||
train_button.disabled = false
|
||||
coordinate_label.text = "Could not contact the unit training service."
|
||||
|
||||
|
||||
func _on_train_unit_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
train_button.disabled = false
|
||||
var text: String = body.get_string_from_utf8()
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
coordinate_label.text = "Scout training request failed."
|
||||
return
|
||||
|
||||
if response_code < 200 or response_code >= 300:
|
||||
coordinate_label.text = "Scout training failed: %s" % text
|
||||
_refresh_player_state()
|
||||
return
|
||||
|
||||
var parsed = JSON.parse_string(text)
|
||||
if typeof(parsed) == TYPE_DICTIONARY:
|
||||
var training: Dictionary = parsed
|
||||
training_started_unix = _parse_utc_timestamp(str(training.get("startedAtUtc", "")))
|
||||
training_completes_unix = _parse_utc_timestamp(str(training.get("completesAtUtc", "")))
|
||||
coordinate_label.text = "Scout training started. Completion takes 1 minute."
|
||||
|
||||
_refresh_player_state()
|
||||
|
||||
|
||||
func _update_tick_bar() -> void:
|
||||
if not tick_bar or not tick_label:
|
||||
return
|
||||
|
||||
if gold_tick_anchor_unix <= 0.0:
|
||||
tick_bar.value = 0.0
|
||||
tick_label.text = "Next: --"
|
||||
return
|
||||
|
||||
var elapsed: float = max(0.0, Time.get_unix_time_from_system() - gold_tick_anchor_unix)
|
||||
var tick_progress: float = fposmod(elapsed, gold_tick_seconds) / gold_tick_seconds
|
||||
var seconds_remaining: int = int(ceil(gold_tick_seconds - fposmod(elapsed, gold_tick_seconds)))
|
||||
if seconds_remaining >= int(gold_tick_seconds):
|
||||
seconds_remaining = int(gold_tick_seconds)
|
||||
|
||||
tick_bar.value = tick_progress
|
||||
tick_label.text = "Next: %ds" % seconds_remaining
|
||||
|
||||
|
||||
func _update_training_bar() -> void:
|
||||
if not training_bar or not training_label:
|
||||
return
|
||||
|
||||
if training_started_unix <= 0.0 or training_completes_unix <= 0.0:
|
||||
training_bar.value = 0.0
|
||||
training_label.text = "Training: idle"
|
||||
return
|
||||
|
||||
var now: float = Time.get_unix_time_from_system()
|
||||
var duration: float = max(1.0, training_completes_unix - training_started_unix)
|
||||
var elapsed: float = clamp(now - training_started_unix, 0.0, duration)
|
||||
var remaining: int = int(max(0, int(ceil(training_completes_unix - now))))
|
||||
training_bar.value = elapsed / duration
|
||||
|
||||
if remaining <= 0:
|
||||
training_label.text = "Training: ready"
|
||||
else:
|
||||
training_label.text = "Training: %ds" % remaining
|
||||
|
||||
|
||||
func _parse_utc_timestamp(timestamp: String) -> float:
|
||||
if timestamp.is_empty():
|
||||
return 0.0
|
||||
|
||||
var normalized := timestamp.strip_edges()
|
||||
var timezone_index := normalized.find("+")
|
||||
if timezone_index > -1:
|
||||
normalized = normalized.substr(0, timezone_index)
|
||||
if normalized.ends_with("Z"):
|
||||
normalized = normalized.substr(0, normalized.length() - 1)
|
||||
|
||||
var fractional_index := normalized.find(".")
|
||||
if fractional_index > -1:
|
||||
normalized = normalized.substr(0, fractional_index)
|
||||
|
||||
normalized = normalized.replace("T", " ")
|
||||
return Time.get_unix_time_from_datetime_string(normalized)
|
||||
|
||||
|
||||
func _build_escape_menu() -> void:
|
||||
escape_overlay = Control.new()
|
||||
@@ -393,6 +657,13 @@ func _menu_button(text_value: String) -> Button:
|
||||
return button
|
||||
|
||||
|
||||
func _small_button(text_value: String) -> Button:
|
||||
var button := _menu_button(text_value)
|
||||
button.custom_minimum_size = Vector2(128, 32)
|
||||
button.add_theme_font_size_override("font_size", 13)
|
||||
return button
|
||||
|
||||
|
||||
func _find_first_button(node: Node) -> Button:
|
||||
if node is Button:
|
||||
return node
|
||||
@@ -421,6 +692,15 @@ func _button_style(color: Color) -> StyleBoxFlat:
|
||||
return style
|
||||
|
||||
|
||||
func _progress_style(color: Color, border_color: Color) -> StyleBoxFlat:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = color
|
||||
style.border_color = border_color
|
||||
style.set_border_width_all(1)
|
||||
style.set_corner_radius_all(3)
|
||||
return style
|
||||
|
||||
|
||||
func _legend_item(color: Color, label_text: String) -> HBoxContainer:
|
||||
var item := HBoxContainer.new()
|
||||
item.add_theme_constant_override("separation", 5)
|
||||
|
||||
Reference in New Issue
Block a user