Polish chapter one battle presentation
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user