private async Task OnFinish(SMHandoff smh, ICancellee prepared, CampaignSnapshot start_campaign, IBackgroundOrchestrator?bgo, IAyaPhotoBoard?photoBoard) { if (props.BgTransitionOut != null) { bgo?.QueueTransition(props.BgTransitionOut); } if (props.BossPhotoHP.Try(out _)) { photoBoard?.TearDown(); } //The shift-phase token is cancelled by timeout or by HP. var completedBy = prepared.Cancelled ? (smh.Exec.isEnemy ? (smh.Exec.Enemy.PhotoHP <= 0 && (props.photoHP ?? 0) > 0) ? PhaseClearMethod.PHOTO : (smh.Exec.Enemy.HP <= 0 && (props.hp ?? 0) > 0) ? PhaseClearMethod.HP : (PhaseClearMethod?)null : null) ?? PhaseClearMethod.TIMEOUT : PhaseClearMethod.CANCELLED; var pc = new PhaseCompletion(props, completedBy, smh.Exec, start_campaign, Timeout); if (pc.StandardCardFinish) { if (props.Boss != null) { BulletManager.RequestPowerAura("powerup1", 0, 0, new RealizedPowerAuraOptions( new PowerAuraOptions(new[] { PowerAuraOption.Color(_ => ColorHelpers.CV4(props.Boss.colors.powerAuraColor)), PowerAuraOption.Time(_ => 1f), PowerAuraOption.Iterations(_ => - 1f), PowerAuraOption.Scale(_ => 3.5f), PowerAuraOption.Static(), PowerAuraOption.High(), }), GenCtx.Empty, smh.Exec.GlobalPosition(), smh.cT, null !)); } smh.Exec.DropItems(pc.DropItems, 1.4f, 0.6f, 1f, 0.2f, 2f); DependencyInjection.MaybeFind <IRaiko>() ?.Shake(defaultShakeTime, defaultShakeMult, defaultShakeMag, smh.cT, null); } GameManagement.Instance.PhaseEnd(pc); if (pc.StandardCardFinish && !smh.Cancelled && props.Boss != null && pc.CaptureStars.HasValue) { Object.Instantiate(GameManagement.References.prefabReferences.phasePerformance) .GetComponent <PhasePerformance>().Initialize($"{props.Boss.CasualName} / Boss Card", pc); await WaitingUtils.WaitForUnchecked(smh.Exec, smh.cT, EndOfCardDelayTime, false); } }
public async Task Start(SMHandoff smh, IUIManager?ui, IReadOnlyList <Enemy> subbosses) { var bgo = DependencyInjection.MaybeFind <IBackgroundOrchestrator>(); var photoBoard = DependencyInjection.MaybeFind <IAyaPhotoBoard>(); PreparePhase(ui, smh, out Task cutins, bgo, photoBoard); var lenienceToken = props.Lenient ? GameManagement.Instance.Lenience.CreateToken1(MultiOp.Priority.CLEAR_PHASE) : null; if (props.rootMove != null) { await props.rootMove.Start(smh); } await cutins; smh.ThrowIfCancelled(); if (props.phaseType?.IsPattern() == true) { ETime.Timer.PhaseTimer.Restart(); } var joint_smh = smh.CreateJointCancellee(out var pcTS); PrepareTimeout(ui, subbosses, joint_smh, pcTS); //The start snapshot is taken after the root movement, // so meter can be used during the 1+2 seconds between cards var start_campaign = new CampaignSnapshot(GameManagement.Instance); if (props.phaseType != null) { DependencyInjection.MaybeFind <IChallengeManager>()?.SetupBossPhase(joint_smh); } try { await base.Start(joint_smh); await WaitingUtils.WaitForUnchecked(joint_smh.Exec, joint_smh.cT, 0f, true); //Wait for synchronization before returning to parent joint_smh.ThrowIfCancelled(); } catch (OperationCanceledException) { if (smh.Exec.PhaseShifter == pcTS) { smh.Exec.PhaseShifter = null; } //This is critical to avoid boss destruction during the two-frame phase buffer if (smh.Exec.isEnemy) { smh.Exec.Enemy.SetVulnerable(Vulnerability.NO_DAMAGE); } lenienceToken?.TryRevoke(); if (props.Cleanup) { GameManagement.ClearPhaseAutocull(props.SoftcullProps(smh.Exec)); } if (smh.Exec.AllowFinishCalls) { //TODO why does this use parentCT? finishPhase?.Trigger(smh.Exec, smh.GCX, smh.parentCT); await OnFinish(smh, pcTS, start_campaign, bgo, photoBoard); } if (smh.Cancelled) { throw; } if (props.phaseType != null) { Log.Unity($"Cleared {props.phaseType.Value} phase: {props.cardTitle?.ValueOrEn ?? ""}"); } if (endPhase != null) { await endPhase.Start(smh); } } }