Polish chapter one battle presentation

This commit is contained in:
2026-06-19 15:27:54 +09:00
parent ed23b2bdf0
commit fb04cbda44
2 changed files with 418 additions and 39 deletions

View File

@@ -47,6 +47,8 @@ const UI_SFX_VOLUME_DB := -8.0
const FLOATING_TEXT_LIFETIME := 1.0
const FLOATING_TEXT_RISE := 42.0
const OBJECTIVE_NOTICE_DURATION := 2.6
const EDGE_SCROLL_MARGIN := 34.0
const EDGE_SCROLL_SPEED := 360.0
const UNIT_MOVE_ANIMATION_DURATION := 0.18
const TARGET_PREVIEW_BADGE_SIZE := Vector2(104, 22)
const LOW_HP_WARNING_RATIO := 0.35
@@ -62,11 +64,11 @@ const UNIT_ARROW_ATTACK_DURATION := 0.36
const UNIT_COMMAND_ATTACK_DURATION := 0.38
const UNIT_HEAVY_ATTACK_DURATION := 0.34
const UNIT_TACTIC_CAST_DURATION := 0.42
const DIALOGUE_PANEL_POSITION := Vector2(40, 356)
const DIALOGUE_PANEL_SIZE := Vector2(1200, 304)
const DIALOGUE_PORTRAIT_SIZE := Vector2(220, 262)
const DIALOGUE_COLUMN_SIZE := Vector2(850, 266)
const DIALOGUE_TEXT_SIZE := Vector2(830, 112)
const DIALOGUE_PANEL_POSITION := Vector2(40, 324)
const DIALOGUE_PANEL_SIZE := Vector2(1200, 356)
const DIALOGUE_PORTRAIT_SIZE := Vector2(220, 310)
const DIALOGUE_COLUMN_SIZE := Vector2(850, 318)
const DIALOGUE_TEXT_SIZE := Vector2(830, 164)
const BRIEFING_CAMP_THUMBNAIL_SIZE := Vector2(188, 86)
const CAMP_TALK_PORTRAIT_SIZE := Vector2(58, 58)
const SHOP_MERCHANT_BADGE_SIZE := Vector2(50, 50)
@@ -121,9 +123,12 @@ const SPEAKER_DISPLAY_NAMES := {
"Zhang Xiu": "장수",
"Jia Xu": "가후",
"Cao Ang": "조앙",
"Xu Rong": "서영",
"Li Jue": "이각",
"Chen Gong": "진궁",
"Gao Shun": "고순",
"Lu Bu": "여포",
"Qingzhou Chief": "청주 두령",
"Yan Liang": "안량",
"Wen Chou": "문추",
"Yuan Shao": "원소",
@@ -166,9 +171,12 @@ const SPEAKER_CANONICAL_NAMES := {
"장수": "Zhang Xiu",
"가후": "Jia Xu",
"조앙": "Cao Ang",
"서영": "Xu Rong",
"이각": "Li Jue",
"진궁": "Chen Gong",
"고순": "Gao Shun",
"여포": "Lu Bu",
"청주 두령": "Qingzhou Chief",
"안량": "Yan Liang",
"문추": "Wen Chou",
"원소": "Yuan Shao",
@@ -188,6 +196,46 @@ const SPEAKER_CANONICAL_NAMES := {
"천자 금위": "Imperial Guard",
"완성 척후": "Wan Scout"
}
const DIALOGUE_RIGHT_SIDE_SPEAKERS := {
"Camp Merchant": true,
"Coalition Merchant": true,
"Coalition Quartermaster": true,
"Dingtao Field Sutler": true,
"Escort Road Sutler": true,
"Puyang Night Trader": true,
"Wan Castle Sutler": true,
"Xiapi Flood-Gate Sutler": true,
"White Horse Road Sutler": true,
"Scout": true,
"Wan Scout": true,
"Yuan Scout": true,
"Imperial Envoy": true,
"Imperial Guard": true,
"Xu Rong": true,
"Li Jue": true,
"Zhang Xiu": true,
"Jia Xu": true,
"Zhang Liao": true,
"Chen Gong": true,
"Gao Shun": true,
"Lu Bu": true,
"Qingzhou Chief": true,
"Yuan Shao": true,
"Yan Liang": true,
"Wen Chou": true,
"Ju Shou": true,
"Chunyu Qiong": true,
"Yuan Guard": true,
"Yuan Field Advisor": true,
"Yuan Rally Advisor": true,
"Yuan Tan Guard": true,
"Yuan Shang Guard": true,
"Ye Guard": true,
"Yuan Shang Inner Guard": true,
"Inner City Advisor": true,
"Ye Last Loyalist": true,
"Palace Advisor": true
}
var state: BattleState = BattleStateScript.new()
var campaign_state: CampaignState = CampaignStateScript.new()
@@ -352,6 +400,7 @@ var battle_background_path := ""
var battle_background_texture: Texture2D
var ui_regular_font: Font
var ui_bold_font: Font
var board_scroll_offset := Vector2.ZERO
func _ready() -> void:
@@ -1522,7 +1571,7 @@ func _create_hud() -> void:
briefing_objective_header.add_child(briefing_objective_toggle_button)
briefing_objective_panel = PanelContainer.new()
briefing_objective_panel.custom_minimum_size = Vector2(680, 104)
briefing_objective_panel.custom_minimum_size = Vector2(680, 124)
_apply_panel_style(briefing_objective_panel, "edict")
briefing_column.add_child(briefing_objective_panel)
@@ -1530,17 +1579,17 @@ func _create_hud() -> void:
briefing_objective_row.add_theme_constant_override("separation", 8)
briefing_objective_panel.add_child(briefing_objective_row)
briefing_objective_row.add_child(_make_bamboo_gutter(18, 84))
briefing_objective_row.add_child(_make_edict_marker_stack(["", "", ""], 84))
briefing_objective_row.add_child(_make_bamboo_gutter(18, 104))
briefing_objective_row.add_child(_make_edict_marker_stack(["", "", ""], 104))
briefing_objective_label = Label.new()
briefing_objective_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
briefing_objective_label.custom_minimum_size = Vector2(500, 84)
briefing_objective_label.custom_minimum_size = Vector2(500, 104)
briefing_objective_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_apply_label_style(briefing_objective_label, UI_AGED_INK, 15)
briefing_objective_row.add_child(briefing_objective_label)
briefing_objective_row.add_child(_make_edict_marker_stack(["", "", ""], 84))
briefing_objective_row.add_child(_make_bamboo_gutter(18, 84))
briefing_objective_row.add_child(_make_edict_marker_stack(["", "", ""], 104))
briefing_objective_row.add_child(_make_bamboo_gutter(18, 104))
briefing_column.add_child(_make_ink_wash_rule(680, 8))
briefing_column.add_child(_make_section_caption("전장도와 군막 보고", 680))
@@ -1879,7 +1928,7 @@ func _create_hud() -> void:
dialogue_speaker_row.add_child(_make_seal_tile("", 24))
dialogue_text_panel = PanelContainer.new()
dialogue_text_panel.custom_minimum_size = Vector2(DIALOGUE_TEXT_SIZE.x, 104)
dialogue_text_panel.custom_minimum_size = Vector2(DIALOGUE_TEXT_SIZE.x, DIALOGUE_TEXT_SIZE.y)
_apply_panel_style(dialogue_text_panel, "speech_scroll")
dialogue_column.add_child(dialogue_text_panel)
@@ -2426,6 +2475,10 @@ func _handle_key(event: InputEventKey) -> void:
func _process(delta: float) -> void:
var needs_redraw := false
if battle_started and state.battle_status == BattleState.STATUS_ACTIVE and not _is_dialogue_visible():
needs_redraw = true
if _update_edge_scroll(delta):
needs_redraw = true
if objective_notice_timer > 0.0:
objective_notice_timer = maxf(0.0, objective_notice_timer - delta)
if objective_notice_timer <= 0.0 and objective_notice_panel != null:
@@ -2478,7 +2531,7 @@ func _can_select(unit: Dictionary) -> bool:
func _draw_map() -> void:
var board_rect := Rect2(BOARD_OFFSET, Vector2(state.map_size.x, state.map_size.y) * TILE_SIZE)
var board_rect := _board_rect()
var background := _current_battle_background_texture()
var has_background := background != null
if background != null:
@@ -2976,7 +3029,6 @@ func _draw_overlays() -> void:
func _draw_units() -> void:
var font := _draw_ui_font()
for unit in state.units:
if not unit.get("alive", false) or not unit.get("deployed", true):
continue
@@ -2984,25 +3036,11 @@ func _draw_units() -> void:
var rect := _visual_rect_for_unit(unit)
var center := rect.position + rect.size * 0.5
var team_color := PLAYER_COLOR if unit.get("team", "") == BattleState.TEAM_PLAYER else ENEMY_COLOR
var token_back := Color(0.02, 0.022, 0.026, 0.78)
var acted := bool(unit.get("acted", false))
var sprite_modulate := _unit_sprite_modulate(unit, acted)
draw_circle(center + Vector2(0, 3), 29, Color(0.0, 0.0, 0.0, 0.38))
draw_circle(center, 28, token_back)
var sprite_texture := _load_art_texture(str(unit.get("sprite", "")))
if sprite_texture != null:
var sprite_target := Rect2(rect.position + Vector2(5, 1), Vector2(TILE_SIZE - 10, TILE_SIZE - 16))
var sprite_rect := _fit_texture_rect(sprite_texture, sprite_target)
draw_texture_rect(sprite_texture, sprite_rect, false, sprite_modulate)
else:
var body_color := team_color.darkened(0.35) if acted else team_color
draw_circle(center, 22, body_color)
draw_arc(center, 28, 0.0, TAU, 64, Color(0.03, 0.035, 0.04), 3.0)
draw_arc(center, 28, -PI * 0.65, PI * 0.35, 36, team_color.lightened(0.18), 3.0)
_draw_unit_identity_marks(rect, center, unit, team_color)
_draw_unit_class_emblem(rect, center, unit, team_color)
_draw_unit_class_badge(rect, unit, team_color)
draw_circle(center + Vector2(0, 17), 20, Color(0.0, 0.0, 0.0, 0.30))
_draw_pixel_unit_sprite(rect, unit, team_color, sprite_modulate)
var hp_ratio := float(unit["hp"]) / float(max(1, int(unit["max_hp"])))
var hp_back := Rect2(rect.position + Vector2(8, TILE_SIZE - 8), Vector2(TILE_SIZE - 16, 5))
@@ -3154,6 +3192,124 @@ func _unit_sprite_modulate(unit: Dictionary, acted: bool) -> Color:
return Color.WHITE
func _draw_pixel_unit_sprite(rect: Rect2, unit: Dictionary, team_color: Color, modulate: Color) -> void:
var family := _unit_class_family(unit)
var phase := _unit_idle_phase(unit)
var bob := roundf(sin(phase) * 1.25)
var step := 1.0 if sin(phase * 1.65) >= 0.0 else -1.0
var pixel := 3.0
var origin := Vector2(roundf(rect.position.x + 12.0), roundf(rect.position.y + 5.0 + bob))
var outline := _unit_pixel_color(Color(0.035, 0.026, 0.018, 1.0), modulate)
var skin := _unit_pixel_color(Color(0.86, 0.62, 0.38, 1.0), modulate)
var cloth := _unit_pixel_color(team_color.lightened(0.05), modulate)
var cloth_dark := _unit_pixel_color(team_color.darkened(0.34), modulate)
var class_color := _unit_pixel_color(_unit_class_badge_color(unit, team_color), modulate)
var accent := _unit_pixel_color(Color(0.98, 0.76, 0.28, 1.0) if not str(unit.get("officer_id", "")).is_empty() else class_color.lightened(0.25), modulate)
_draw_pixel_rect(origin, 2, 11, 8, 2, pixel, Color(0.0, 0.0, 0.0, 0.22 * modulate.a))
if family == "cavalry":
_draw_pixel_cavalry(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
elif family == "ranged":
_draw_pixel_archer(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
elif family == "tactic":
_draw_pixel_strategist(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
elif family == "heavy":
_draw_pixel_heavy(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
else:
_draw_pixel_infantry(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
func _unit_idle_phase(unit: Dictionary) -> float:
var seed := 0
var unit_id := str(unit.get("id", "unit"))
for index in range(unit_id.length()):
seed += unit_id.unicode_at(index) * (index + 1)
return float(Time.get_ticks_msec()) * 0.0024 + float(seed % 360) * 0.01745
func _unit_pixel_color(color: Color, modulate: Color) -> Color:
return Color(
color.r * modulate.r,
color.g * modulate.g,
color.b * modulate.b,
color.a * modulate.a
)
func _draw_pixel_rect(origin: Vector2, x: float, y: float, width: float, height: float, pixel: float, color: Color) -> void:
draw_rect(Rect2(origin + Vector2(x, y) * pixel, Vector2(width, height) * pixel), color)
func _draw_pixel_infantry(origin: Vector2, pixel: float, outline: Color, skin: Color, cloth: Color, cloth_dark: Color, class_color: Color, accent: Color, step: float) -> void:
_draw_pixel_rect(origin, 4, 1, 4, 2, pixel, outline)
_draw_pixel_rect(origin, 5, 2, 2, 2, pixel, skin)
_draw_pixel_rect(origin, 3, 4, 6, 5, pixel, outline)
_draw_pixel_rect(origin, 4, 4, 4, 4, pixel, cloth)
_draw_pixel_rect(origin, 3, 6, 2, 3, pixel, class_color)
_draw_pixel_rect(origin, 7, 6, 2, 3, pixel, cloth_dark)
_draw_pixel_rect(origin, 4 + step, 9, 2, 3, pixel, outline)
_draw_pixel_rect(origin, 7 - step, 9, 2, 3, pixel, outline)
_draw_pixel_rect(origin, 1, 4, 1, 8, pixel, accent.lightened(0.15))
_draw_pixel_rect(origin, 0, 3, 3, 1, pixel, accent)
func _draw_pixel_archer(origin: Vector2, pixel: float, outline: Color, skin: Color, cloth: Color, cloth_dark: Color, class_color: Color, accent: Color, step: float) -> void:
_draw_pixel_rect(origin, 4, 1, 4, 2, pixel, outline)
_draw_pixel_rect(origin, 5, 2, 2, 2, pixel, skin)
_draw_pixel_rect(origin, 3, 4, 6, 5, pixel, outline)
_draw_pixel_rect(origin, 4, 4, 4, 4, pixel, cloth)
_draw_pixel_rect(origin, 5, 5, 2, 4, pixel, class_color)
_draw_pixel_rect(origin, 4 + step, 9, 2, 3, pixel, outline)
_draw_pixel_rect(origin, 7 - step, 9, 2, 3, pixel, outline)
draw_line(origin + Vector2(9, 3) * pixel, origin + Vector2(11, 7) * pixel, accent, 2.0)
draw_line(origin + Vector2(11, 7) * pixel, origin + Vector2(9, 11) * pixel, accent, 2.0)
draw_line(origin + Vector2(4, 6) * pixel, origin + Vector2(11, 7) * pixel, accent.lightened(0.15), 1.3)
_draw_pixel_rect(origin, 2, 5, 2, 1, pixel, cloth_dark)
func _draw_pixel_cavalry(origin: Vector2, pixel: float, outline: Color, skin: Color, cloth: Color, cloth_dark: Color, class_color: Color, accent: Color, step: float) -> void:
var horse := _unit_pixel_color(Color(0.33, 0.20, 0.11, 1.0), Color(1.0, 1.0, 1.0, outline.a))
var mane := _unit_pixel_color(Color(0.12, 0.075, 0.04, 1.0), Color(1.0, 1.0, 1.0, outline.a))
_draw_pixel_rect(origin, 1, 7, 9, 3, pixel, outline)
_draw_pixel_rect(origin, 2, 7, 7, 2, pixel, horse)
_draw_pixel_rect(origin, 8, 5, 3, 3, pixel, outline)
_draw_pixel_rect(origin, 8, 6, 2, 2, pixel, horse)
_draw_pixel_rect(origin, 7, 5, 1, 3, pixel, mane)
_draw_pixel_rect(origin, 2 + step, 10, 2, 3, pixel, outline)
_draw_pixel_rect(origin, 7 - step, 10, 2, 3, pixel, outline)
_draw_pixel_rect(origin, 4, 2, 4, 2, pixel, outline)
_draw_pixel_rect(origin, 5, 3, 2, 2, pixel, skin)
_draw_pixel_rect(origin, 4, 5, 4, 3, pixel, cloth)
_draw_pixel_rect(origin, 5, 5, 2, 2, pixel, class_color)
draw_line(origin + Vector2(4, 4) * pixel, origin + Vector2(2, 1) * pixel, accent, 2.0)
func _draw_pixel_strategist(origin: Vector2, pixel: float, outline: Color, skin: Color, cloth: Color, cloth_dark: Color, class_color: Color, accent: Color, step: float) -> void:
_draw_pixel_rect(origin, 4, 1, 4, 2, pixel, outline)
_draw_pixel_rect(origin, 5, 2, 2, 2, pixel, skin)
_draw_pixel_rect(origin, 3, 4, 6, 7, pixel, outline)
_draw_pixel_rect(origin, 4, 4, 4, 6, pixel, cloth)
_draw_pixel_rect(origin, 3, 6, 2, 3, pixel, class_color)
_draw_pixel_rect(origin, 7, 6, 2, 3, pixel, class_color)
_draw_pixel_rect(origin, 4 + step, 11, 2, 2, pixel, outline)
_draw_pixel_rect(origin, 7 - step, 11, 2, 2, pixel, outline)
_draw_pixel_rect(origin, 8, 3, 3, 1, pixel, accent)
_draw_pixel_rect(origin, 9, 4, 2, 1, pixel, accent)
_draw_pixel_rect(origin, 2, 5, 1, 5, pixel, cloth_dark)
func _draw_pixel_heavy(origin: Vector2, pixel: float, outline: Color, skin: Color, cloth: Color, cloth_dark: Color, class_color: Color, accent: Color, step: float) -> void:
_draw_pixel_rect(origin, 4, 1, 4, 2, pixel, outline)
_draw_pixel_rect(origin, 5, 2, 2, 2, pixel, skin)
_draw_pixel_rect(origin, 2, 4, 8, 6, pixel, outline)
_draw_pixel_rect(origin, 3, 4, 6, 5, pixel, cloth)
_draw_pixel_rect(origin, 4, 5, 4, 4, pixel, class_color)
_draw_pixel_rect(origin, 3 + step, 10, 2, 3, pixel, outline)
_draw_pixel_rect(origin, 8 - step, 10, 2, 3, pixel, outline)
draw_line(origin + Vector2(9, 2) * pixel, origin + Vector2(2, 10) * pixel, accent, 3.0)
_draw_pixel_rect(origin, 8, 1, 3, 2, pixel, accent.lightened(0.20))
func _draw_unit_identity_marks(rect: Rect2, center: Vector2, unit: Dictionary, team_color: Color) -> void:
if _is_generic_enemy_unit(unit):
var sash := ENEMY_COLOR.lightened(0.22)
@@ -3960,18 +4116,86 @@ func _target_preview_badge_color(kind: String) -> Color:
func _cell_from_screen(screen_position: Vector2) -> Vector2i:
var local := screen_position - BOARD_OFFSET
var local := screen_position - _board_origin()
if local.x < 0 or local.y < 0:
return Vector2i(-1, -1)
return Vector2i(int(floor(local.x / TILE_SIZE)), int(floor(local.y / TILE_SIZE)))
func _rect_for_cell(cell: Vector2i) -> Rect2:
return Rect2(BOARD_OFFSET + Vector2(cell.x, cell.y) * TILE_SIZE, Vector2(TILE_SIZE, TILE_SIZE))
return Rect2(_board_origin() + Vector2(cell.x, cell.y) * TILE_SIZE, Vector2(TILE_SIZE, TILE_SIZE))
func _board_rect() -> Rect2:
return Rect2(BOARD_OFFSET, Vector2(state.map_size.x, state.map_size.y) * TILE_SIZE)
return Rect2(_board_origin(), _board_size())
func _board_origin() -> Vector2:
return BOARD_OFFSET + board_scroll_offset
func _board_size() -> Vector2:
return Vector2(state.map_size.x, state.map_size.y) * TILE_SIZE
func _map_view_rect() -> Rect2:
var viewport_size := _viewport_size_for_layout()
var right_edge := minf(SIDE_PANEL_POSITION.x - 18.0, viewport_size.x - 18.0)
var bottom_edge := viewport_size.y - 20.0
return Rect2(
BOARD_OFFSET,
Vector2(maxf(160.0, right_edge - BOARD_OFFSET.x), maxf(160.0, bottom_edge - BOARD_OFFSET.y))
)
func _viewport_size_for_layout() -> Vector2:
if is_inside_tree():
return get_viewport_rect().size
var window_size := Vector2(DisplayServer.window_get_size())
if window_size.x > 0.0 and window_size.y > 0.0:
return window_size
return Vector2(1280, 720)
func _reset_board_scroll() -> void:
board_scroll_offset = _clamped_board_scroll_offset(Vector2.ZERO)
func _clamped_board_scroll_offset(offset: Vector2) -> Vector2:
var view_rect := _map_view_rect()
var board_size := _board_size()
var min_x := minf(0.0, view_rect.size.x - board_size.x)
var min_y := minf(0.0, view_rect.size.y - board_size.y)
return Vector2(clampf(offset.x, min_x, 0.0), clampf(offset.y, min_y, 0.0))
func _update_edge_scroll(delta: float) -> bool:
if _is_input_locked():
return false
var view_rect := _map_view_rect()
var mouse_position := get_viewport().get_mouse_position()
if not view_rect.has_point(mouse_position):
return false
var velocity := Vector2.ZERO
if mouse_position.x <= view_rect.position.x + EDGE_SCROLL_MARGIN:
velocity.x += EDGE_SCROLL_SPEED
elif mouse_position.x >= view_rect.end.x - EDGE_SCROLL_MARGIN:
velocity.x -= EDGE_SCROLL_SPEED
if mouse_position.y <= view_rect.position.y + EDGE_SCROLL_MARGIN:
velocity.y += EDGE_SCROLL_SPEED
elif mouse_position.y >= view_rect.end.y - EDGE_SCROLL_MARGIN:
velocity.y -= EDGE_SCROLL_SPEED
if velocity == Vector2.ZERO:
return false
var previous_offset := board_scroll_offset
board_scroll_offset = _clamped_board_scroll_offset(board_scroll_offset + velocity * delta)
if previous_offset.distance_squared_to(board_scroll_offset) <= 0.01:
return false
var next_hover := _cell_from_screen(mouse_position)
if next_hover != hover_cell:
hover_cell = next_hover
_update_hud()
return true
func _short_name(unit_name: String) -> String:
@@ -5041,7 +5265,7 @@ func _normalized_dialogue_lines(lines: Array) -> Array:
"speaker": display_speaker,
"text": text,
"portrait": portrait,
"side": _normalized_dialogue_side(line.get("side", "left"))
"side": _dialogue_side_for_line(line)
})
elif typeof(line) == TYPE_STRING:
var text := str(line)
@@ -5058,6 +5282,16 @@ func _normalized_dialogue_side(value) -> String:
return "left"
func _dialogue_side_for_line(line: Dictionary) -> String:
var explicit_side := str(line.get("side", "")).strip_edges()
if not explicit_side.is_empty():
return _normalized_dialogue_side(explicit_side)
var speaker := _canonical_speaker_name(str(line.get("speaker", line.get("display_speaker", ""))))
if DIALOGUE_RIGHT_SIDE_SPEAKERS.has(speaker):
return "right"
return "left"
func _can_show_dialogue_now() -> bool:
if not battle_started or campaign_complete_screen:
return false
@@ -5095,7 +5329,7 @@ func _render_dialogue_line() -> void:
var line: Dictionary = active_dialogue_lines[active_dialogue_index]
var speaker := str(line.get("speaker", ""))
var display_speaker := _localized_speaker_name(str(line.get("display_speaker", speaker)))
var side := _normalized_dialogue_side(line.get("side", "left"))
var side := _dialogue_side_for_line(line)
_apply_dialogue_side(side)
dialogue_speaker_label.text = display_speaker if not display_speaker.is_empty() else ""
dialogue_speaker_label.visible = not display_speaker.is_empty()
@@ -5467,6 +5701,7 @@ func _load_scenario(scenario_id: String) -> void:
campaign_state.get_joined_officers_snapshot(),
campaign_state.get_scenario_title(active_scenario_id)
)
_reset_board_scroll()
func _format_briefing_title(briefing: Dictionary) -> String:
@@ -7832,7 +8067,7 @@ func _update_post_move_menu() -> void:
func _local_command_panel_position_for_cell(cell: Vector2i, panel_size: Vector2) -> Vector2:
if not state.is_inside(cell):
return BOARD_OFFSET + Vector2(LOCAL_COMMAND_PANEL_BOARD_PADDING, LOCAL_COMMAND_PANEL_BOARD_PADDING)
return _board_origin() + Vector2(LOCAL_COMMAND_PANEL_BOARD_PADDING, LOCAL_COMMAND_PANEL_BOARD_PADDING)
var cell_rect := _rect_for_cell(cell)
var centered_y := cell_rect.position.y + (TILE_SIZE - panel_size.y) * 0.5
var centered_x := cell_rect.position.x + (TILE_SIZE - panel_size.x) * 0.5
@@ -7860,9 +8095,16 @@ func _local_command_panel_position_for_cell(cell: Vector2i, panel_size: Vector2)
func _clamped_local_command_panel_position(position: Vector2, panel_size: Vector2) -> Vector2:
var board_size := Vector2(state.map_size.x, state.map_size.y) * TILE_SIZE
var board_min := BOARD_OFFSET + Vector2(LOCAL_COMMAND_PANEL_BOARD_PADDING, LOCAL_COMMAND_PANEL_BOARD_PADDING)
var board_max := BOARD_OFFSET + board_size - panel_size - Vector2(LOCAL_COMMAND_PANEL_BOARD_PADDING, LOCAL_COMMAND_PANEL_BOARD_PADDING)
var board_rect := _board_rect()
var view_rect := _map_view_rect()
var board_min := Vector2(
maxf(board_rect.position.x, view_rect.position.x),
maxf(board_rect.position.y, view_rect.position.y)
) + Vector2(LOCAL_COMMAND_PANEL_BOARD_PADDING, LOCAL_COMMAND_PANEL_BOARD_PADDING)
var board_max := Vector2(
minf(board_rect.end.x, view_rect.end.x),
minf(board_rect.end.y, view_rect.end.y)
) - panel_size - Vector2(LOCAL_COMMAND_PANEL_BOARD_PADDING, LOCAL_COMMAND_PANEL_BOARD_PADDING)
board_max.x = maxf(board_min.x, board_max.x)
board_max.y = maxf(board_min.y, board_max.y)
return Vector2(