Add battlefield visuals and camp talk slice
This commit is contained in:
113
tools/smoke_visual_assets.gd
Normal file
113
tools/smoke_visual_assets.gd
Normal file
@@ -0,0 +1,113 @@
|
||||
extends SceneTree
|
||||
|
||||
const BattleStateScript := preload("res://scripts/core/battle_state.gd")
|
||||
const BattleSceneScript := preload("res://scripts/scenes/battle_scene.gd")
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
var failures: Array[String] = []
|
||||
_check_battle_visual_data(failures)
|
||||
_check_scene_texture_loading(failures)
|
||||
_check_attack_motion_signal(failures)
|
||||
|
||||
if failures.is_empty():
|
||||
print("visual assets smoke ok")
|
||||
quit(0)
|
||||
return
|
||||
|
||||
for failure in failures:
|
||||
push_error(failure)
|
||||
quit(1)
|
||||
|
||||
|
||||
func _check_battle_visual_data(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
failures.append("could not load opening battle")
|
||||
return
|
||||
|
||||
var briefing := state.get_briefing()
|
||||
if (briefing.get("camp_dialogue", []) as Array).is_empty():
|
||||
failures.append("001 briefing should expose camp dialogue")
|
||||
var merchant := state.get_shop_merchant()
|
||||
if merchant.is_empty() or (merchant.get("lines", []) as Array).is_empty():
|
||||
failures.append("001 shop should expose merchant lines")
|
||||
|
||||
_check_image_path(failures, state.get_map_background_path(), "001 map background")
|
||||
for unit_id in ["cao_cao", "xiahou_dun", "yellow_turban_1", "yellow_turban_2", "yellow_turban_3"]:
|
||||
var unit := state.get_unit(unit_id)
|
||||
if unit.is_empty():
|
||||
failures.append("missing expected unit: %s" % unit_id)
|
||||
continue
|
||||
_check_image_path(failures, str(unit.get("sprite", "")), "unit %s sprite" % unit_id)
|
||||
|
||||
for item_id in ["bronze_sword", "training_spear", "short_bow", "hand_axe", "iron_armor", "panacea"]:
|
||||
var item := state.get_item_def(item_id)
|
||||
if item.is_empty():
|
||||
failures.append("missing expected item: %s" % item_id)
|
||||
continue
|
||||
_check_image_path(failures, str(item.get("icon", "")), "item %s icon" % item_id)
|
||||
|
||||
|
||||
func _check_scene_texture_loading(failures: Array[String]) -> void:
|
||||
var scene = BattleSceneScript.new()
|
||||
if not scene.state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
failures.append("could not load battle scene state")
|
||||
scene.free()
|
||||
return
|
||||
if scene._current_battle_background_texture() == null:
|
||||
failures.append("battle scene should load a battlefield background texture")
|
||||
var archer: Dictionary = scene.state.get_unit("yellow_turban_3")
|
||||
if scene._load_art_texture(str(archer.get("sprite", ""))) == null:
|
||||
failures.append("battle scene should load archer sprite texture")
|
||||
var panacea: Dictionary = scene.state.get_item_def("panacea")
|
||||
if scene._load_art_texture(str(panacea.get("icon", ""))) == null:
|
||||
failures.append("battle scene should load panacea icon texture")
|
||||
scene.free()
|
||||
|
||||
|
||||
func _check_attack_motion_signal(failures: Array[String]) -> void:
|
||||
var state = BattleStateScript.new()
|
||||
if not state.load_battle("res://data/scenarios/001_yellow_turbans.json"):
|
||||
failures.append("could not load battle for attack motion")
|
||||
return
|
||||
|
||||
var attacker := state.get_unit("cao_cao")
|
||||
var target := state.get_unit("yellow_turban_1")
|
||||
if attacker.is_empty() or target.is_empty():
|
||||
failures.append("missing attacker or target for attack motion")
|
||||
return
|
||||
attacker["pos"] = Vector2i(6, 2)
|
||||
target["pos"] = Vector2i(7, 2)
|
||||
|
||||
var motions: Array[String] = []
|
||||
state.unit_action_motion_requested.connect(func(unit_id: String, from_cell: Vector2i, to_cell: Vector2i, action_kind: String) -> void:
|
||||
motions.append("%s|%s|%d,%d|%d,%d" % [unit_id, action_kind, from_cell.x, from_cell.y, to_cell.x, to_cell.y])
|
||||
)
|
||||
if not state.select_unit("cao_cao"):
|
||||
failures.append("could not select Cao Cao for attack motion")
|
||||
return
|
||||
if not state.try_attack_selected("yellow_turban_1"):
|
||||
failures.append("Cao Cao should be able to attack adjacent target")
|
||||
return
|
||||
if not motions.has("cao_cao|attack|6,2|7,2"):
|
||||
failures.append("attack motion signal missing expected Cao Cao attack: %s" % str(motions))
|
||||
|
||||
|
||||
func _check_image_path(failures: Array[String], path: String, context: String) -> void:
|
||||
if path.is_empty():
|
||||
failures.append("%s has an empty image path" % context)
|
||||
return
|
||||
if not path.begins_with("res://"):
|
||||
failures.append("%s must use a res:// path: %s" % [context, path])
|
||||
return
|
||||
if not FileAccess.file_exists(path):
|
||||
failures.append("%s references missing image: %s" % [context, path])
|
||||
return
|
||||
var image := Image.new()
|
||||
var err := image.load(path)
|
||||
if err != OK:
|
||||
failures.append("%s references unreadable image: %s" % [context, path])
|
||||
return
|
||||
if image.get_width() < 512 or image.get_height() < 512:
|
||||
failures.append("%s image should be at least 512x512: %s (%dx%d)" % [context, path, image.get_width(), image.get_height()])
|
||||
@@ -500,6 +500,9 @@ function Check-Deployment($Deployment, [string]$ScenarioId, [int]$Width, [int]$H
|
||||
if (Has-Prop $Deployment "portrait") {
|
||||
Check-Portrait-Path (Get-Prop $Deployment "portrait" "") "Scenario $ScenarioId deployment $unitId portrait"
|
||||
}
|
||||
if (Has-Prop $Deployment "sprite") {
|
||||
Check-Portrait-Path (Get-Prop $Deployment "sprite" "") "Scenario $ScenarioId deployment $unitId sprite"
|
||||
}
|
||||
if (Has-Prop $Deployment "requires_joined") {
|
||||
if (-not ((Get-Prop $Deployment "requires_joined" $false) -is [bool])) {
|
||||
Fail "Scenario $ScenarioId deployment $unitId requires_joined must be boolean."
|
||||
@@ -871,6 +874,9 @@ function Check-Item-Effects() {
|
||||
$itemId = $itemProp.Name
|
||||
$item = $itemProp.Value
|
||||
$kind = [string](Get-Prop $item "kind" "")
|
||||
if (Has-Prop $item "icon") {
|
||||
Check-Portrait-Path (Get-Prop $item "icon" "") "Item $itemId icon"
|
||||
}
|
||||
if (-not $validItemKinds.Contains($kind)) {
|
||||
Fail "Item $itemId has unknown kind: $kind"
|
||||
}
|
||||
@@ -1197,6 +1203,25 @@ function Check-Shop($Shop, [string]$ScenarioId) {
|
||||
if (Has-Prop $Shop "stock") {
|
||||
Check-Shop-Stock-Block $Shop.stock $seenShopItems "Scenario $ScenarioId shop"
|
||||
}
|
||||
if (Has-Prop $Shop "merchant") {
|
||||
$merchant = Get-Prop $Shop "merchant" $null
|
||||
if ($null -eq $merchant -or $merchant -is [string] -or $merchant -is [System.Array]) {
|
||||
Fail "Scenario $ScenarioId shop merchant must be an object."
|
||||
}
|
||||
$merchantName = [string](Get-Prop $merchant "name" "Merchant")
|
||||
if ([string]::IsNullOrWhiteSpace($merchantName)) {
|
||||
Fail "Scenario $ScenarioId shop merchant has an empty name."
|
||||
}
|
||||
$merchantLines = Get-Prop $merchant "lines" $null
|
||||
if ($null -eq $merchantLines -or -not ($merchantLines -is [System.Array])) {
|
||||
Fail "Scenario $ScenarioId shop merchant must have line array."
|
||||
}
|
||||
foreach ($merchantLine in @($merchantLines)) {
|
||||
if ([string]::IsNullOrWhiteSpace([string]$merchantLine)) {
|
||||
Fail "Scenario $ScenarioId shop merchant has an empty line."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$conditionalItems = Get-Prop $Shop "conditional_items" @()
|
||||
foreach ($block in @($conditionalItems)) {
|
||||
@@ -1670,6 +1695,9 @@ function Check-Briefing($Briefing, [string]$ScenarioId) {
|
||||
Fail "Scenario $ScenarioId briefing has an empty line."
|
||||
}
|
||||
}
|
||||
foreach ($line in @((Get-Prop $Briefing "camp_dialogue" @()))) {
|
||||
Check-Dialogue-Line $line "Scenario $ScenarioId briefing camp_dialogue"
|
||||
}
|
||||
|
||||
$conditionalLines = Get-Prop $Briefing "conditional_lines" @()
|
||||
foreach ($block in @($conditionalLines)) {
|
||||
@@ -1814,6 +1842,9 @@ Check-Class-Promotions
|
||||
|
||||
foreach ($classProp in $classes.PSObject.Properties) {
|
||||
Check-Skill-Refs (Get-Prop $classProp.Value "skills" @()) "Class $($classProp.Name)"
|
||||
if (Has-Prop $classProp.Value "sprite") {
|
||||
Check-Portrait-Path (Get-Prop $classProp.Value "sprite" "") "Class $($classProp.Name) sprite"
|
||||
}
|
||||
}
|
||||
|
||||
$officerNames = New-Object System.Collections.Generic.HashSet[string]
|
||||
@@ -1842,6 +1873,9 @@ foreach ($scenario in $campaign.scenarios) {
|
||||
}
|
||||
|
||||
$map = $scenarioData.map
|
||||
if (Has-Prop $map "background") {
|
||||
Check-Portrait-Path (Get-Prop $map "background" "") "Scenario $scenarioId map background"
|
||||
}
|
||||
$width = [int]$map.width
|
||||
$height = [int]$map.height
|
||||
$rows = @($map.terrain)
|
||||
|
||||
Reference in New Issue
Block a user