movemeent tweaks

This commit is contained in:
hz
2026-05-19 05:42:31 -05:00
parent 14e2c26e74
commit 762143918b
3 changed files with 118 additions and 15 deletions
@@ -54,6 +54,8 @@ 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_barracks_button: Button var build_barracks_button: Button
var unit_action_popup: PopupPanel
var unit_action_move_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
@@ -67,6 +69,8 @@ var completed_archer_count := 0
var selected_archer_q := 9999 var selected_archer_q := 9999
var selected_archer_r := 9999 var selected_archer_r := 9999
var selected_archer_count := 0 var selected_archer_count := 0
var pending_move_q := 9999
var pending_move_r := 9999
var refresh_prompt_active := false var refresh_prompt_active := false
var refresh_request_active := false var refresh_request_active := false
@@ -170,9 +174,11 @@ func _build_ui() -> void:
grid_view.set_anchors_preset(Control.PRESET_FULL_RECT) grid_view.set_anchors_preset(Control.PRESET_FULL_RECT)
grid_view.tile_hovered.connect(_on_tile_hovered) grid_view.tile_hovered.connect(_on_tile_hovered)
grid_view.tile_selected.connect(_on_tile_selected) grid_view.tile_selected.connect(_on_tile_selected)
grid_view.tile_action_requested.connect(_on_tile_action_requested)
map_layer.add_child(grid_view) map_layer.add_child(grid_view)
_build_map_overlays(map_layer) _build_map_overlays(map_layer)
_build_unit_action_menu()
var bottom_bar := PanelContainer.new() var bottom_bar := PanelContainer.new()
bottom_bar.custom_minimum_size = Vector2(0, 46) bottom_bar.custom_minimum_size = Vector2(0, 46)
@@ -412,6 +418,28 @@ func _build_refresh_dialog() -> void:
add_child(refresh_dialog) add_child(refresh_dialog)
func _build_unit_action_menu() -> void:
unit_action_popup = PopupPanel.new()
unit_action_popup.transparent_bg = true
add_child(unit_action_popup)
var panel := PanelContainer.new()
panel.add_theme_stylebox_override("panel", _panel_style(Color(0.06, 0.09, 0.09, 0.96), Color(0.17, 0.78, 0.83), 1, 6))
unit_action_popup.add_child(panel)
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 8)
margin.add_theme_constant_override("margin_right", 8)
margin.add_theme_constant_override("margin_top", 8)
margin.add_theme_constant_override("margin_bottom", 8)
panel.add_child(margin)
unit_action_move_button = _small_button("Move")
unit_action_move_button.custom_minimum_size = Vector2(92, 34)
unit_action_move_button.pressed.connect(_confirm_unit_move)
margin.add_child(unit_action_move_button)
func _on_tile_hovered(q: int, r: int, terrain: String) -> void: func _on_tile_hovered(q: int, r: int, terrain: String) -> void:
if coordinate_label: if coordinate_label:
coordinate_label.text = "Hex q:%d r:%d | %s" % [q, r, terrain] coordinate_label.text = "Hex q:%d r:%d | %s" % [q, r, terrain]
@@ -440,21 +468,62 @@ func _handle_unit_selection_or_move(q: int, r: int) -> bool:
var archer_count: int = grid_view.get_archer_count_at(q, r) var archer_count: int = grid_view.get_archer_count_at(q, r)
if archer_count > 0: if archer_count > 0:
if unit_action_popup:
unit_action_popup.hide()
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
grid_view.set_selected_unit_tile(q, r) grid_view.set_selected_unit_tile(q, r)
if coordinate_label: if coordinate_label:
coordinate_label.text = "Selected Archer squad: %d at q:%d r:%d. Select a visible non-rival tile to move." % [archer_count, q, r] coordinate_label.text = "Selected Archer squad: %d at q:%d r:%d. Right-click an adjacent visible tile for orders." % [archer_count, q, r]
return true
if selected_archer_count > 0:
_move_selected_archers(q, r)
return true return true
return false return false
func _on_tile_action_requested(q: int, r: int, _terrain: String, screen_position: Vector2) -> void:
if not grid_view:
return
if selected_archer_count <= 0:
if unit_action_popup:
unit_action_popup.hide()
if coordinate_label:
coordinate_label.text = "Select an Archer squad before giving orders."
return
if q == selected_archer_q and r == selected_archer_r:
if coordinate_label:
coordinate_label.text = "Archer squad is already on that tile."
return
if not grid_view.is_neighbor(selected_archer_q, selected_archer_r, q, r):
if coordinate_label:
coordinate_label.text = "Archers can only move to an adjacent tile."
return
if not grid_view.is_visible_non_rival_tile(q, r):
if coordinate_label:
coordinate_label.text = "Archers can only move to visible non-rival tiles."
return
pending_move_q = q
pending_move_r = r
if coordinate_label:
coordinate_label.text = "Orders for Archer squad: q:%d r:%d." % [q, r]
if unit_action_popup:
var popup_size := Vector2i(116, 52)
var visible_rect := get_viewport().get_visible_rect()
var max_x := int(max(0.0, visible_rect.size.x - popup_size.x - 8.0))
var max_y := int(max(0.0, visible_rect.size.y - popup_size.y - 8.0))
var popup_position := Vector2i(clampi(int(screen_position.x), 8, max_x), clampi(int(screen_position.y), 8, max_y))
unit_action_popup.popup(Rect2i(popup_position, popup_size))
func _confirm_unit_move() -> void:
if unit_action_popup:
unit_action_popup.hide()
if pending_move_q == 9999:
return
_move_selected_archers(pending_move_q, pending_move_r)
func _can_build_log_camp_on_selected_tile() -> bool: func _can_build_log_camp_on_selected_tile() -> bool:
return _can_build_on_selected_tile("Forest") return _can_build_on_selected_tile("Forest")
@@ -517,6 +586,10 @@ func _clear_selected_archers() -> void:
selected_archer_q = 9999 selected_archer_q = 9999
selected_archer_r = 9999 selected_archer_r = 9999
selected_archer_count = 0 selected_archer_count = 0
pending_move_q = 9999
pending_move_r = 9999
if unit_action_popup:
unit_action_popup.hide()
if grid_view: if grid_view:
grid_view.clear_selected_unit_tile() grid_view.clear_selected_unit_tile()
@@ -961,6 +1034,9 @@ func _move_selected_archers(to_q: int, to_r: int) -> void:
if to_q == selected_archer_q and to_r == selected_archer_r: if to_q == selected_archer_q and to_r == selected_archer_r:
coordinate_label.text = "Archer squad is already on that tile." coordinate_label.text = "Archer squad is already on that tile."
return return
if not grid_view.is_neighbor(selected_archer_q, selected_archer_r, to_q, to_r):
coordinate_label.text = "Archers can only move to an adjacent tile."
return
if not grid_view.is_visible_non_rival_tile(to_q, to_r): if not grid_view.is_visible_non_rival_tile(to_q, to_r):
coordinate_label.text = "Archers can only move to visible non-rival tiles." coordinate_label.text = "Archers can only move to visible non-rival tiles."
return return
@@ -2,6 +2,7 @@ extends Control
signal tile_hovered(q: int, r: int, terrain: String) signal tile_hovered(q: int, r: int, terrain: String)
signal tile_selected(q: int, r: int, terrain: String) signal tile_selected(q: int, r: int, terrain: String)
signal tile_action_requested(q: int, r: int, terrain: String, screen_position: Vector2)
const HEX_SIZE := 42.0 const HEX_SIZE := 42.0
const ISO_Y_SCALE := 0.56 const ISO_Y_SCALE := 0.56
@@ -80,6 +81,14 @@ func _gui_input(event: InputEvent) -> void:
var label: String = _tile_display_label(key, data) if visible_tiles.has(key) else "Unexplored" var label: String = _tile_display_label(key, data) if visible_tiles.has(key) else "Unexplored"
tile_selected.emit(selected_tile.x, selected_tile.y, label) tile_selected.emit(selected_tile.x, selected_tile.y, label)
queue_redraw() queue_redraw()
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
var action_tile := _closest_tile_at(event.position)
if action_tile.x != 9999:
var action_data: Dictionary = _tile_data(action_tile.x, action_tile.y)
var action_key: String = _tile_key(action_tile.x, action_tile.y)
var action_label: String = _tile_display_label(action_key, action_data) if visible_tiles.has(action_key) else "Unexplored"
tile_action_requested.emit(action_tile.x, action_tile.y, action_label, get_global_mouse_position())
accept_event()
elif event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed: elif event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
zoom = clampf(zoom + 0.08, 0.65, 1.6) zoom = clampf(zoom + 0.08, 0.65, 1.6)
queue_redraw() queue_redraw()
@@ -229,7 +238,20 @@ func _draw_control_layer(control_tiles: Array, control: String, layer_scale: flo
func _update_hover(mouse_position: Vector2) -> void: func _update_hover(mouse_position: Vector2) -> void:
var closest: Vector2i = Vector2i(9999, 9999) var closest := _closest_tile_at(mouse_position)
if closest != hovered_tile:
hovered_tile = closest
if hovered_tile.x != 9999:
var data: Dictionary = _tile_data(hovered_tile.x, hovered_tile.y)
var key: String = _tile_key(hovered_tile.x, hovered_tile.y)
var terrain: String = _tile_display_label(key, data) if visible_tiles.has(key) else "Unexplored"
tile_hovered.emit(hovered_tile.x, hovered_tile.y, terrain)
queue_redraw()
func _closest_tile_at(mouse_position: Vector2) -> Vector2i:
var closest := Vector2i(9999, 9999)
var closest_distance: float = 999999.0 var closest_distance: float = 999999.0
for tile in tiles: for tile in tiles:
@@ -244,14 +266,7 @@ func _update_hover(mouse_position: Vector2) -> void:
if closest_distance > HEX_SIZE * zoom: if closest_distance > HEX_SIZE * zoom:
closest = Vector2i(9999, 9999) closest = Vector2i(9999, 9999)
if closest != hovered_tile: return closest
hovered_tile = closest
if hovered_tile.x != 9999:
var data: Dictionary = _tile_data(hovered_tile.x, hovered_tile.y)
var key: String = _tile_key(hovered_tile.x, hovered_tile.y)
var terrain: String = _tile_display_label(key, data) if visible_tiles.has(key) else "Unexplored"
tile_hovered.emit(hovered_tile.x, hovered_tile.y, terrain)
queue_redraw()
func _tile_center(q: int, r: int) -> Vector2: func _tile_center(q: int, r: int) -> Vector2:
@@ -529,6 +544,13 @@ func has_owned_neighbor(q: int, r: int) -> bool:
return false return false
func is_neighbor(q1: int, r1: int, q2: int, r2: int) -> bool:
for neighbor in _neighbor_coordinates(q1, r1):
if neighbor.x == q2 and neighbor.y == r2:
return true
return false
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()
@@ -660,7 +682,7 @@ func _archer_count_at(q: int, r: int) -> int:
if int(unit.get("q", 0)) == q and int(unit.get("r", 0)) == r: if int(unit.get("q", 0)) == q and int(unit.get("r", 0)) == r:
count += 1 count += 1
if count == 0 and completed_archer_count > 0 and Vector2i(q, r) == _archer_station_tile(): if unit_instances.is_empty() and count == 0 and completed_archer_count > 0 and Vector2i(q, r) == _archer_station_tile():
count = completed_archer_count count = completed_archer_count
return count return count
@@ -153,6 +153,11 @@ public class UnitTrainingService
throw new InvalidOperationException("Select a different destination tile."); throw new InvalidOperationException("Select a different destination tile.");
} }
if (HexDistance(request.FromQ, request.FromR, request.ToQ, request.ToR) != 1)
{
throw new InvalidOperationException("Archers can only move to adjacent tiles.");
}
if (!await CanMoveToAsync(username, request.ToQ, request.ToR)) if (!await CanMoveToAsync(username, request.ToQ, request.ToR))
{ {
throw new InvalidOperationException("Archers can only move to visible non-rival tiles."); throw new InvalidOperationException("Archers can only move to visible non-rival tiles.");