TH1/Tools/CheckSuikaFallingSplashAnimation.ps1

117 lines
8.7 KiB
PowerShell

param(
[string]$SkillFile = "Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/HakureiNorwayHeroSkill.cs",
[string]$ActionFile = "Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs",
[string]$FragmentFile = "Unity/Assets/Scripts/TH1_Anim/Fragments/FragmentSuikaFallingSplash.cs",
[string]$FragmentDataFile = "Unity/Assets/Scripts/TH1_Anim/Fragments/FragmentData.cs",
[string]$AttackGroundFragmentFile = "Unity/Assets/Scripts/TH1_Anim/Fragments/FragmentAttackGround.cs",
[string]$PlayerDataFile = "Unity/Assets/Scripts/TH1_Data/PlayerData.cs",
[string]$UnitLogicFile = "Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs",
[string]$FragmentManagerFile = "Unity/Assets/Scripts/TH1_Anim/FragmentManager.cs",
[string]$AtomFile = "Unity/Assets/Scripts/TH1_Anim/UnitAtomAnim/UnitAtomAnim.cs",
[string]$AtomDataFile = "Unity/Assets/Scripts/TH1_Anim/UnitAtomAnim/UnitAtomAnimData.cs",
[string]$AtomMoveFile = "Unity/Assets/Scripts/TH1_Anim/UnitAtomAnim/UnitAtomAnimMove.cs"
)
$ErrorActionPreference = "Stop"
$repoRoot = git rev-parse --show-toplevel 2>$null
if (-not $repoRoot) {
throw "Not inside a git repository."
}
$repoRoot = [System.IO.Path]::GetFullPath($repoRoot.Trim())
function Read-RepoFile([string]$relativePath) {
$fullPath = Join-Path $repoRoot $relativePath
if (-not (Test-Path -LiteralPath $fullPath)) {
throw "Required file not found: $fullPath"
}
return Get-Content -LiteralPath $fullPath -Raw -Encoding UTF8
}
$skillText = Read-RepoFile $SkillFile
$actionText = Read-RepoFile $ActionFile
$fragmentText = Read-RepoFile $FragmentFile
$fragmentDataText = Read-RepoFile $FragmentDataFile
$attackGroundFragmentText = Read-RepoFile $AttackGroundFragmentFile
$playerDataText = Read-RepoFile $PlayerDataFile
$unitLogicText = Read-RepoFile $UnitLogicFile
$fragmentManagerText = Read-RepoFile $FragmentManagerFile
$atomText = Read-RepoFile $AtomFile
$atomDataText = Read-RepoFile $AtomDataFile
$atomMoveText = Read-RepoFile $AtomMoveFile
function Assert-Contains([string]$text, [string]$needle, [string]$label) {
if (-not $text.Contains($needle)) {
throw "Suika falling splash animation guardrail failed: $label missing '$needle'."
}
}
Assert-Contains $atomText 'ParabolaMove' 'atom animation type'
Assert-Contains $atomText 'UnitAtomAnimType.ParabolaMove => new UnitAtomAnimParabolaMove' 'atom animation factory'
Assert-Contains $atomDataText 'UnitAtomAnimParabolaMoveData' 'atom animation data'
Assert-Contains $atomDataText 'float duration = 1.1f' 'parabola default duration'
Assert-Contains $atomDataText 'float height = 18f' 'parabola default height'
Assert-Contains $atomMoveText 'class UnitAtomAnimParabolaMove' 'parabola atom animation'
Assert-Contains $fragmentManagerText 'FragmentType.SuikaFallingSplash => new FragmentSuikaFallingSplash' 'fragment factory'
Assert-Contains $fragmentText 'class FragmentSuikaFallingSplash' 'Suika fragment'
Assert-Contains $fragmentText 'private const float JumpDuration = 1.1f;' 'Suika fragment jump duration'
Assert-Contains $fragmentText 'private const float JumpHeight = 18f;' 'Suika fragment jump height'
Assert-Contains $fragmentText 'SplashImpactPause' 'Suika fragment post-splash pause'
Assert-Contains $fragmentText 'UnitAtomAnimType.ParabolaMove' 'Suika fragment launch arc'
Assert-Contains $fragmentText 'AnimPhase.AttackImpact + 20' 'post-impact final move phase'
Assert-Contains $fragmentText 'UnitAtomAnimType.Move' 'post-impact final move'
Assert-Contains $fragmentText 'RefreshFinalState' 'final refresh'
Assert-Contains $fragmentText 'RefreshLandingSight' 'landing sight refresh'
Assert-Contains $fragmentText 'foreach (var grid in Data.SightRefreshGrids)' 'new sight grid iteration'
Assert-Contains $fragmentText 'gridRenderer?.InstantUpdateGrid(true)' 'new sight grid force refresh'
Assert-Contains $playerDataText 'GetAroundGridIdList(range, grid, remainCenter: true)' 'movement sight includes standing grid'
Assert-Contains $fragmentDataText 'public List<GridData> SightRefreshGrids;' 'fragment sight refresh data'
Assert-Contains $unitLogicText 'public List<GridData> SuikaFallingSplashSightRefreshGrids;' 'attack info sight refresh data'
Assert-Contains $actionText 'sightRefreshGrids: attackInfo.SuikaFallingSplashSightRefreshGrids' 'attack fragment sight refresh handoff'
Assert-Contains $actionText 'List<GridData> suikaGroundSightRefreshGrids = null;' 'ground jump sight refresh cache'
Assert-Contains $actionText 'sightRefreshGrids: suikaGroundSightRefreshGrids' 'ground jump fragment sight refresh handoff'
Assert-Contains $actionText 'FragmentType.SuikaFallingSplash, suikaData' 'ground self-jump fragment'
Assert-Contains $actionText 'TryCreateSuikaFallingSplashFragment' 'attack action fragment switch'
Assert-Contains $actionText 'FragmentType.SuikaFallingSplash' 'attack action fragment type'
Assert-Contains $actionText 'visualCollector?.FlushTo(suikaFallingSplashFragment)' 'splash damage visual collection'
Assert-Contains $skillText 'TryRepositionUnitWithoutMoveSideEffects(map, suika, target)' 'ground self-jump data-only reposition'
Assert-Contains $skillText 'CollectSuikaFallingSplashNewSightGrids' 'Suika sight refresh collector'
Assert-Contains $skillText 'GetAroundGridIdList(range, landingGrid, remainCenter: true)' 'Suika landing sight includes final grid'
Assert-Contains $skillText 'attackInfo.IsSuikaFallingSplash = true;' 'skill attack marker'
Assert-Contains $skillText 'attackInfo.SuikaFallingSplashFinalGrid = landingGrid;' 'skill final grid marker'
Assert-Contains $skillText 'ExecuteSuikaFallingSplashDamage(map, suika, targetGrid, AnimPhase.AttackImpact + 10)' 'post-impact splash visual phase'
Assert-Contains $skillText 'TargetGridHasOtherUnit(map, suika, landingGrid)' 'death-replacement target occupancy guard'
if ($attackGroundFragmentText -match 'SkillType\.SuikaFallingSplash\s*=>\s*ProjectileType\.Bomb') {
throw "Suika falling splash animation guardrail failed: FragmentAttackGround must not map SuikaFallingSplash to Bomb projectile."
}
$method = [regex]::Match($skillText, '(?ms)public static bool TryExecuteSuikaFlyAfterAttack\(MapData map, AttackInfo attackInfo\).*?^\s*private static void ExecuteSuikaFallingSplashDamage')
if (-not $method.Success) {
throw "Suika falling splash animation guardrail failed: cannot locate TryExecuteSuikaFlyAfterAttack body."
}
$body = $method.Value
if ($body -notmatch 'ExecuteSuikaFallingSplashDamage\(map, suika, targetGrid, AnimPhase\.AttackImpact \+ 10\);[\s\S]*?TargetGridHasOtherUnit\(map, suika, landingGrid\)[\s\S]*?TryFindRandomEmptyAround\(map, suika, targetGrid, out landingGrid\)[\s\S]*?sightRefreshGrids = CollectSuikaFallingSplashNewSightGrids\(map, suika, attackInfo\.OriginPlayer,[\s\S]*?landingGrid\);[\s\S]*?TryRepositionUnitWithoutMoveSideEffects\(map, suika, landingGrid\)[\s\S]*?attackInfo\.IsSuikaFallingSplash = true;[\s\S]*?attackInfo\.SuikaFallingSplashFinalGrid = landingGrid;[\s\S]*?attackInfo\.SuikaFallingSplashSightRefreshGrids = sightRefreshGrids;[\s\S]*?UpdateSightByPath') {
throw "Suika falling splash animation guardrail failed: attack-after-splash must settle damage, avoid death-replacement occupants, cache new sight grids, reposition data, then update sight."
}
$groundMethod = [regex]::Match($actionText, '(?ms)public class UnitAttackGroundAction.*?protected override bool Execute\(CommonActionParams actionParams\).*?^\s*public override bool CheckCan')
if (-not $groundMethod.Success) {
throw "Suika falling splash animation guardrail failed: cannot locate UnitAttackGroundAction execute body."
}
if ($groundMethod.Value -notmatch 'suikaGroundSightRefreshGrids = HakureiNorwayHeroSkillUtil\.CollectSuikaFallingSplashNewSightGrids[\s\S]*?unit1\.AttackGroundExecute\(actionParams\.MapData, targetGrid, out animSkillData,[\s\S]*?out skillAttackGroundCountsAsActiveAttack\)[\s\S]*?sightRefreshGrids: suikaGroundSightRefreshGrids') {
throw "Suika falling splash animation guardrail failed: ground self-jump must cache sight grids before AttackGroundExecute updates sight, then pass them into the Suika fragment."
}
$fragmentMethod = [regex]::Match($fragmentText, '(?ms)public class FragmentSuikaFallingSplash.*?^\s*public override void OnUpdate')
if (-not $fragmentMethod.Success) {
throw "Suika falling splash animation guardrail failed: cannot locate FragmentSuikaFallingSplash body."
}
if ($fragmentMethod.Value -notmatch 'UnitAtomAnimParabolaMoveData[\s\S]*?JumpHeight[\s\S]*?JumpDuration[\s\S]*?PlayTargetAttackImpact\(\);[\s\S]*?PlayLandingImpact\(\);[\s\S]*?AnimPhase\.AttackImpact \+ 15[\s\S]*?SplashImpactPause[\s\S]*?AnimPhase\.AttackImpact \+ 20[\s\S]*?UnitAtomAnimType\.Move[\s\S]*?AnimPhase\.Settle') {
throw "Suika falling splash animation guardrail failed: fragment must play a high, slow parabola, impact/splash pause, optional final move, then settle refresh."
}
Write-Host "Suika falling splash animation guardrail passed."