destination indicator update

This commit is contained in:
hz
2026-05-20 19:21:09 -05:00
parent 94f3b1e258
commit a40c8cf50d
3 changed files with 160 additions and 7 deletions
@@ -74,6 +74,9 @@ var selected_is_home := false
var completed_scout_count := 0 var completed_scout_count := 0
var completed_archer_count := 0 var completed_archer_count := 0
var completed_peasant_count := 0 var completed_peasant_count := 0
var selected_scout_q := 9999
var selected_scout_r := 9999
var selected_scout_count := 0
var selected_peasant_id := "" var selected_peasant_id := ""
var selected_peasant_q := 9999 var selected_peasant_q := 9999
var selected_peasant_r := 9999 var selected_peasant_r := 9999
@@ -518,8 +521,23 @@ func _handle_unit_selection_or_move(q: int, r: int) -> bool:
return false return false
var archer_count: int = grid_view.get_archer_count_at(q, r) var archer_count: int = grid_view.get_archer_count_at(q, r)
var scout_count: int = grid_view.get_scout_count_at(q, r)
var peasant_id: String = grid_view.get_peasant_id_at(q, r) var peasant_id: String = grid_view.get_peasant_id_at(q, r)
var peasant_count: int = grid_view.get_peasant_count_at(q, r) var peasant_count: int = grid_view.get_peasant_count_at(q, r)
if scout_count > 0:
if unit_action_popup:
unit_action_popup.hide()
selected_scout_q = q
selected_scout_r = r
selected_scout_count = scout_count
selected_archer_count = 0
selected_peasant_count = 0
selected_peasant_id = ""
grid_view.set_selected_unit_tile(q, r)
if coordinate_label:
coordinate_label.text = "Selected Scout squad: %d at q:%d r:%d. Right-click a visible tile for orders." % [scout_count, q, r]
return true
if peasant_count > 0: if peasant_count > 0:
if unit_action_popup: if unit_action_popup:
unit_action_popup.hide() unit_action_popup.hide()
@@ -527,6 +545,7 @@ func _handle_unit_selection_or_move(q: int, r: int) -> bool:
selected_peasant_q = q selected_peasant_q = q
selected_peasant_r = r selected_peasant_r = r
selected_peasant_count = peasant_count selected_peasant_count = peasant_count
selected_scout_count = 0
selected_archer_count = 0 selected_archer_count = 0
grid_view.set_selected_unit_tile(q, r) grid_view.set_selected_unit_tile(q, r)
if coordinate_label: if coordinate_label:
@@ -539,6 +558,7 @@ func _handle_unit_selection_or_move(q: int, r: int) -> bool:
selected_archer_q = q selected_archer_q = q
selected_archer_r = r selected_archer_r = r
selected_archer_count = archer_count selected_archer_count = archer_count
selected_scout_count = 0
selected_peasant_id = "" selected_peasant_id = ""
selected_peasant_count = 0 selected_peasant_count = 0
grid_view.set_selected_unit_tile(q, r) grid_view.set_selected_unit_tile(q, r)
@@ -556,7 +576,8 @@ func _on_tile_action_requested(q: int, r: int, _terrain: String, screen_position
var has_building := _location_has_completed_building(location) var has_building := _location_has_completed_building(location)
var has_worker := not _nullable_string(location.get("workerUnitId", "")).is_empty() var has_worker := not _nullable_string(location.get("workerUnitId", "")).is_empty()
var selected_peasants := selected_peasant_count > 0 var selected_peasants := selected_peasant_count > 0
if selected_archer_count <= 0 and not selected_peasants and not has_worker: var selected_scouts := selected_scout_count > 0
if selected_archer_count <= 0 and not selected_scouts and not selected_peasants and not has_worker:
if unit_action_popup: if unit_action_popup:
unit_action_popup.hide() unit_action_popup.hide()
if coordinate_label: if coordinate_label:
@@ -566,6 +587,10 @@ func _on_tile_action_requested(q: int, r: int, _terrain: String, screen_position
if coordinate_label: if coordinate_label:
coordinate_label.text = "Archer squad is already on that tile." coordinate_label.text = "Archer squad is already on that tile."
return return
if selected_scouts and q == selected_scout_q and r == selected_scout_r:
if coordinate_label:
coordinate_label.text = "Scout squad is already on that tile."
return
if selected_peasants and not grid_view.is_owned_tile(q, r): if selected_peasants and not grid_view.is_owned_tile(q, r):
if coordinate_label: if coordinate_label:
coordinate_label.text = "Peasants can only move within controlled territory." coordinate_label.text = "Peasants can only move within controlled territory."
@@ -580,7 +605,7 @@ func _on_tile_action_requested(q: int, r: int, _terrain: String, screen_position
if coordinate_label: if coordinate_label:
coordinate_label.text = "Orders for q:%d r:%d." % [q, r] coordinate_label.text = "Orders for q:%d r:%d." % [q, r]
if unit_action_popup: if unit_action_popup:
unit_action_move_button.visible = selected_archer_count > 0 or selected_peasants unit_action_move_button.visible = selected_archer_count > 0 or selected_scouts or selected_peasants
unit_action_assign_button.visible = not selected_peasant_id.is_empty() and has_building and not has_worker unit_action_assign_button.visible = not selected_peasant_id.is_empty() and has_building and not has_worker
unit_action_deassign_button.visible = has_worker unit_action_deassign_button.visible = has_worker
var popup_size := Vector2i(116, 132) var popup_size := Vector2i(116, 132)
@@ -598,6 +623,8 @@ func _confirm_unit_move() -> void:
return return
if selected_archer_count > 0: if selected_archer_count > 0:
_move_selected_archers(pending_move_q, pending_move_r) _move_selected_archers(pending_move_q, pending_move_r)
elif selected_scout_count > 0:
_move_selected_scouts(pending_move_q, pending_move_r)
elif selected_peasant_count > 0: elif selected_peasant_count > 0:
_move_selected_peasants(pending_move_q, pending_move_r) _move_selected_peasants(pending_move_q, pending_move_r)
@@ -696,6 +723,9 @@ func _update_action_buttons() -> void:
func _clear_selected_archers() -> void: func _clear_selected_archers() -> void:
selected_scout_q = 9999
selected_scout_r = 9999
selected_scout_count = 0
selected_archer_q = 9999 selected_archer_q = 9999
selected_archer_r = 9999 selected_archer_r = 9999
selected_archer_count = 0 selected_archer_count = 0
@@ -1229,6 +1259,44 @@ func _move_selected_archers(to_q: int, to_r: int) -> void:
coordinate_label.text = "Could not contact the unit move service." coordinate_label.text = "Could not contact the unit move service."
func _move_selected_scouts(to_q: int, to_r: int) -> void:
if selected_scout_count <= 0:
return
if to_q == selected_scout_q and to_r == selected_scout_r:
coordinate_label.text = "Scout squad is already on that tile."
return
if not grid_view.is_visible_tile(to_q, to_r):
coordinate_label.text = "Scouts can only move to visible tiles."
return
var access_token: String = str(session.get("accessToken", ""))
if access_token.is_empty():
coordinate_label.text = "No auth token available. Scout squad was not moved."
return
if move_units_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
return
coordinate_label.text = "Ordering %d Scouts to move to q:%d r:%d..." % [selected_scout_count, to_q, to_r]
var error: int = move_units_request.request(
LOCATIONS_BASE_URL + "/api/units/move",
PackedStringArray([
"Content-Type: application/json",
"Authorization: Bearer %s" % access_token
]),
HTTPClient.METHOD_POST,
JSON.stringify({
"unitType": "Scout",
"fromQ": selected_scout_q,
"fromR": selected_scout_r,
"toQ": to_q,
"toR": to_r
})
)
if error != OK:
coordinate_label.text = "Could not contact the unit move service."
func _move_selected_peasants(to_q: int, to_r: int) -> void: func _move_selected_peasants(to_q: int, to_r: int) -> void:
if selected_peasant_count <= 0: if selected_peasant_count <= 0:
return return
@@ -261,18 +261,99 @@ func _draw_movement_indicators() -> void:
var from_r := int(unit.get("r", 0)) var from_r := int(unit.get("r", 0))
var to_q := int(unit.get("destinationQ", 0)) var to_q := int(unit.get("destinationQ", 0))
var to_r := int(unit.get("destinationR", 0)) var to_r := int(unit.get("destinationR", 0))
var from_center := _tile_center(from_q, from_r) var route := _movement_route(Vector2i(from_q, from_r), Vector2i(to_q, to_r), str(unit.get("unitType", "")))
if route.size() < 2:
continue
var to_center := _tile_center(to_q, to_r) var to_center := _tile_center(to_q, to_r)
var target_tile: Dictionary = _tile_data(to_q, to_r) var target_tile: Dictionary = _tile_data(to_q, to_r)
var target_height := float(target_tile.get("height", _tile_height(to_q, to_r))) var target_height := float(target_tile.get("height", _tile_height(to_q, to_r)))
var marker_color := Color(0.98, 0.82, 0.28, 0.92) if str(unit.get("unitType", "")) == "Peasant" else Color(0.38, 0.86, 1.0, 0.92) var marker_color := Color(0.98, 0.82, 0.28, 0.92) if str(unit.get("unitType", "")) == "Peasant" else Color(0.38, 0.86, 1.0, 0.92)
draw_line(from_center, to_center, Color(marker_color.r, marker_color.g, marker_color.b, 0.72), 3.0) for index in range(route.size() - 1):
draw_circle(from_center, 4.0, Color(marker_color.r, marker_color.g, marker_color.b, 0.88)) var from_center := _tile_center(route[index].x, route[index].y)
var next_center := _tile_center(route[index + 1].x, route[index + 1].y)
draw_line(from_center, next_center, Color(marker_color.r, marker_color.g, marker_color.b, 0.72), 3.0)
draw_circle(from_center, 4.0, Color(marker_color.r, marker_color.g, marker_color.b, 0.88))
if index > 0:
draw_circle(from_center, 2.5, Color(marker_color.r, marker_color.g, marker_color.b, 0.95))
draw_polyline(_closed_points(_hex_points(to_center, target_height + 3.0)), marker_color, 4.0) draw_polyline(_closed_points(_hex_points(to_center, target_height + 3.0)), marker_color, 4.0)
draw_circle(to_center, 7.0, Color(marker_color.r, marker_color.g, marker_color.b, 0.76)) draw_circle(to_center, 7.0, Color(marker_color.r, marker_color.g, marker_color.b, 0.76))
func _movement_route(start: Vector2i, target: Vector2i, unit_type: String) -> Array[Vector2i]:
if unit_type == "Peasant":
var owned_route := _owned_route(start, target)
if not owned_route.is_empty():
return owned_route
return _direct_hex_route(start, target)
func _owned_route(start: Vector2i, target: Vector2i) -> Array[Vector2i]:
if not owned_tiles.has(_tile_key(target.x, target.y)):
return []
var queue: Array[Vector2i] = [start]
var visited := { start: true }
var previous := {}
var cursor := 0
while cursor < queue.size():
var current: Vector2i = queue[cursor]
cursor += 1
if current == target:
break
var neighbors := _neighbor_coordinates(current.x, current.y)
neighbors.sort_custom(func(a: Vector2i, b: Vector2i) -> bool:
var distance_a := _hex_distance(a.x, a.y, target.x, target.y)
var distance_b := _hex_distance(b.x, b.y, target.x, target.y)
if distance_a == distance_b:
return a.x < b.x if a.y == b.y else a.y < b.y
return distance_a < distance_b
)
for neighbor in neighbors:
if visited.has(neighbor) or not owned_tiles.has(_tile_key(neighbor.x, neighbor.y)):
continue
visited[neighbor] = true
previous[neighbor] = current
queue.append(neighbor)
if not visited.has(target):
return []
var route: Array[Vector2i] = [target]
var step := target
while previous.has(step):
step = previous[step]
route.push_front(step)
return route
func _direct_hex_route(start: Vector2i, target: Vector2i) -> Array[Vector2i]:
var route: Array[Vector2i] = [start]
var current := start
var guard := 0
while current != target and guard < 128:
var neighbors := _neighbor_coordinates(current.x, current.y)
neighbors.sort_custom(func(a: Vector2i, b: Vector2i) -> bool:
var distance_a := _hex_distance(a.x, a.y, target.x, target.y)
var distance_b := _hex_distance(b.x, b.y, target.x, target.y)
if distance_a == distance_b:
return a.x < b.x if a.y == b.y else a.y < b.y
return distance_a < distance_b
)
current = neighbors[0]
route.append(current)
guard += 1
return route
func _hex_distance(q1: int, r1: int, q2: int, r2: int) -> int:
var s1 := -q1 - r1
var s2 := -q2 - r2
return max(max(abs(q1 - q2), abs(r1 - r2)), abs(s1 - s2))
func _update_hover(mouse_position: Vector2) -> void: func _update_hover(mouse_position: Vector2) -> void:
var closest := _closest_tile_at(mouse_position) var closest := _closest_tile_at(mouse_position)
@@ -712,6 +793,10 @@ func is_neighbor(q1: int, r1: int, q2: int, r2: int) -> bool:
return false return false
func get_scout_count_at(q: int, r: int) -> int:
return _scout_count_at(q, r)
func set_completed_archers(count: int) -> void: func set_completed_archers(count: int) -> void:
completed_archer_count = max(0, count) completed_archer_count = max(0, count)
queue_redraw() queue_redraw()
@@ -186,9 +186,9 @@ public class UnitTrainingService
await RefillMovementAsync(username); await RefillMovementAsync(username);
var normalizedUnitType = NormalizeUnitType(request.UnitType); var normalizedUnitType = NormalizeUnitType(request.UnitType);
if (normalizedUnitType != ArcherUnitType && normalizedUnitType != PeasantUnitType) if (normalizedUnitType != ScoutUnitType && normalizedUnitType != ArcherUnitType && normalizedUnitType != PeasantUnitType)
{ {
throw new ArgumentException("Only Archers and Peasants can be moved right now.", nameof(request.UnitType)); throw new ArgumentException("Only Scouts, Archers, and Peasants can be moved right now.", nameof(request.UnitType));
} }
if (request.FromQ == request.ToQ && request.FromR == request.ToR) if (request.FromQ == request.ToQ && request.FromR == request.ToR)