117 lines
8.7 KiB
PowerShell
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."
|