Example #1
0
        private void PrepareTimeout(IUIManager?ui, IReadOnlyList <Enemy> subbosses, SMHandoff smh, Cancellable toCancel)
        {
            smh.Exec.PhaseShifter = toCancel;
            var timeout = Timeout;

            //Note that the <!> HP(hp) sets invulnTime=0.
            if (props.invulnTime != null && props.phaseType != PhaseType.TIMEOUT)
            {
                WaitingUtils.WaitThenCB(smh.Exec, smh.cT, props.invulnTime.Value, false,
                                        () => smh.Exec.Enemy.SetVulnerable(Vulnerability.VULNERABLE));
            }
            WaitingUtils.WaitThenCancel(smh.Exec, smh.cT, timeout, true, toCancel);
            if (props.phaseType?.IsSpell() ?? false)
            {
                smh.Exec.Enemy.RequestSpellCircle(timeout, smh.cT);
                foreach (var subboss in subbosses)
                {
                    subboss.RequestSpellCircle(timeout, smh.cT);
                }
            }
            //else smh.exec.Enemy.DestroySpellCircle();
            if (!props.HideTimeout && smh.Exec.TriggersUITimeout)
            {
                ui?.DoTimeout(props.phaseType?.IsCard() ?? false, timeout, smh.cT);
            }
        }
Example #2
0
            public void DoAIteration(AsyncPattern[] target)
            {
                //To prevent secondary sequential children from trying to copy this object's GCX
                // which will have already changed when the next loop starts.
                GenCtx base_gcx  = looper.GCX.Copy();
                bool   done      = false;
                Action loop_done = () => {
                    base_gcx.Dispose();
                    done = true;
                };

                if (waitChild)
                {
                    checkIsChildDone = () => done;
                    //On the frame that the child finishes, the waitstep will increment elapsedFrames
                    //even though it should not. However, it is difficult to tell the waitstep whether
                    //the child was finished or not finished before that frame. This is the easiest solution.
                    --elapsedFrames;
                }
                else
                {
                    checkIsChildDone = null;
                }

                if (looper.props.childSelect == null)
                {
                    if (sequential)
                    {
                        void DoNext(int ii)
                        {
                            if (ii >= target.Length || looper.Handoff.cT.Cancelled)
                            {
                                loop_done();
                            }
                            else
                            {
                                DoAIteration(target[ii], () => DoNext(ii + 1), base_gcx);
                            }
                        }

                        DoNext(0);
                    }
                    else
                    {
                        var loop_fragment_done = WaitingUtils.GetManyCallback(target.Length, loop_done);
                        for (int ii = 0; ii < target.Length; ++ii)
                        {
                            DoAIteration(target[ii], loop_fragment_done, base_gcx);
                        }
                    }
                }
                else
                {
                    DoAIteration(target[(int)looper.props.childSelect(looper.GCX) % target.Length], loop_done, base_gcx);
                }
            }
Example #3
0
 public void OnFail(ChallengeManager.TrackingContext ctx)
 {
     Log.Unity($"FAILED challenge {cr.Description}");
     UIManager.MessageChallengeEnd(false, out float t);
     if (ctx.exec != null)
     {
         ctx.exec.ShiftPhase();
     }
     WaitingUtils.WaitThenCB(ctx.cm, Cancellable.Null, t, false,
                             () => { BulletManager.PlayerTarget.Player.Hit(999, true); });
 }
Example #4
0
            public void DoAIteration(ref float elapsedFrames, IReadOnlyList <StateMachine> target)
            {
                //See IPExecution tracker for comments on this code
                GenCtx base_gcx  = looper.GCX.Copy();
                bool   done      = false;
                Action loop_done = () => {
                    base_gcx.Dispose();
                    done = true;
                };

                if (waitChild)
                {
                    checkIsChildDone = () => done;
                    --elapsedFrames;
                }
                else
                {
                    checkIsChildDone = null;
                }

                if (looper.props.childSelect == null)
                {
                    if (sequential)
                    {
                        void DoNext(int ii)
                        {
                            if (ii >= target.Count || looper.Handoff.cT.Cancelled)
                            {
                                loop_done();
                            }
                            else
                            {
                                DoAIteration(target[ii], () => DoNext(ii + 1), base_gcx);
                            }
                        }

                        DoNext(0);
                    }
                    else
                    {
                        var loop_fragment_done = WaitingUtils.GetManyCallback(target.Count, loop_done);
                        for (int ii = 0; ii < target.Count; ++ii)
                        {
                            DoAIteration(target[ii], loop_fragment_done, base_gcx);
                        }
                    }
                }
                else
                {
                    DoAIteration(target[(int)looper.props.childSelect(looper.GCX) % target.Count], loop_done, base_gcx);
                }
            }
Example #5
0
        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);
            }
        }
Example #6
0
            public void DoLastAIteration(IReadOnlyList <StateMachine> target)
            {
                //Unlike GIR, which hoists its cleanup code into a callback, GTR awaits its last child
                // and calls its cleanup code in Start.
                //Therefore, this code follows the wait-child pattern.
                GenCtx base_gcx = looper.GCX.Copy();
                bool   done     = false;

                checkIsChildDone = () => done;
                Action loop_done = () => {
                    base_gcx.Dispose();
                    done = true;
                    //AllDone called by Start code
                };

                if (looper.props.childSelect == null)
                {
                    if (sequential)
                    {
                        void DoNext(int ii)
                        {
                            if (ii >= target.Count || looper.Handoff.cT.Cancelled)
                            {
                                loop_done();
                            }
                            else
                            {
                                DoAIteration(target[ii], () => DoNext(ii + 1), base_gcx);
                            }
                        }

                        DoNext(0);
                    }
                    else
                    {
                        var loop_fragment_done = WaitingUtils.GetManyCallback(target.Count, loop_done);
                        for (int ii = 0; ii < target.Count; ++ii)
                        {
                            DoAIteration(target[ii], loop_fragment_done, base_gcx);
                        }
                    }
                }
                else
                {
                    DoAIteration(target[(int)looper.props.childSelect(looper.GCX) % target.Count], loop_done, base_gcx);
                }
            }
Example #7
0
            public void DoLastAIteration(AsyncPattern[] target)
            {
                GenCtx base_gcx  = looper.GCX.Copy();
                Action loop_done = () => {
                    base_gcx.Dispose();
                    AllADone();
                };

                if (looper.props.childSelect == null)
                {
                    if (sequential)
                    {
                        void DoNext(int ii)
                        {
                            if (ii >= target.Length || looper.Handoff.cT.Cancelled)
                            {
                                loop_done();
                            }
                            else
                            {
                                DoAIteration(target[ii], () => DoNext(ii + 1), base_gcx);
                            }
                        }

                        DoNext(0);
                    }
                    else
                    {
                        var loop_fragment_done = WaitingUtils.GetManyCallback(target.Length, loop_done);
                        for (int ii = 0; ii < target.Length; ++ii)
                        {
                            DoAIteration(target[ii], loop_fragment_done, base_gcx);
                        }
                    }
                }
                else
                {
                    DoAIteration(target[(int)looper.props.childSelect(looper.GCX) % target.Length], loop_done, base_gcx);
                }
            }
 public static Event BossExplode() => smh => {
     UnityEngine.Object.Instantiate(ResourceManager.GetSummonable("bossexplode")).GetComponent <ExplodeEffect>().Initialize(BossExplodeWait, smh.Exec.rBPI.loc);
     DependencyInjection.MaybeFind <IRaiko>()?.Shake(BossExplodeShake, ShakeMag, 2, smh.cT, null);
     SFXService.BossExplode();
     return(WaitingUtils.WaitForUnchecked(smh.Exec, smh.cT, BossExplodeWait, false));
 };
Example #9
0
        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);
                }
            }
        }
Example #10
0
        private void PreparePhase(IUIManager?ui, SMHandoff smh, out Task cutins,
                                  IBackgroundOrchestrator?bgo, IAyaPhotoBoard?photoBoard)
        {
            cutins = Task.CompletedTask;
            ui?.ShowPhaseType(props.phaseType);
            if (props.cardTitle != null || props.phaseType != null)
            {
                var rate = (props.Boss != null) ?
                           GameManagement.Instance.LookForSpellHistory(props.Boss.key, props.Index) :
                           null;
                ui?.SetSpellname(props.cardTitle?.ToString(), rate);
            }
            if (!props.HideTimeout && smh.Exec.TriggersUITimeout)
            {
                ui?.ShowStaticTimeout(Timeout);
            }
            if (props.livesOverride.HasValue)
            {
                ui?.ShowBossLives(props.livesOverride.Value);
            }
            if (smh.Exec.isEnemy)
            {
                if (props.photoHP.Try(out var photoHP))
                {
                    smh.Exec.Enemy.SetPhotoHP(photoHP, photoHP);
                }
                else if ((props.hp ?? props.phaseType?.DefaultHP()).Try(out var hp))
                {
                    if (props.Boss != null)
                    {
                        hp = (int)(hp * GameManagement.Difficulty.bossHPMod);
                    }
                    smh.Exec.Enemy.SetHP(hp, hp);
                }
                if ((props.hpbar ?? props.phaseType?.HPBarLength()).Try(out var hpbar))
                {
                    smh.Exec.Enemy.SetHPBar(hpbar, props.phaseType ?? PhaseType.NONSPELL);
                }
                smh.Exec.Enemy.SetVulnerable(props.phaseType?.DefaultVulnerability() ??
                                             (props.Boss == null ? Vulnerability.VULNERABLE : Vulnerability.NO_DAMAGE));
            }
            if (props.BossPhotoHP.Try(out var pins))
            {
                photoBoard?.SetupPins(pins);
            }
            bool forcedBG = false;

            if (GameManagement.Instance.mode != InstanceMode.CARD_PRACTICE && !SaveData.Settings.TeleportAtPhaseStart)
            {
                if (props.bossCutin && props.Boss != null && props.Background != null)
                {
                    GameManagement.Instance.ExternalLenience(props.Boss.bossCutinTime);
                    SFXService.BossCutin();
                    //Service not required since no callback
                    DependencyInjection.MaybeFind <IRaiko>()?.Shake(props.Boss.bossCutinTime / 2f, null, 1f, smh.cT, null);
                    Object.Instantiate(props.Boss.bossCutin);
                    bgo?.QueueTransition(props.Boss.bossCutinTrIn);
                    bgo?.ConstructTarget(props.Boss.bossCutinBg, true);
                    WaitingUtils.WaitFor(smh, props.Boss.bossCutinBgTime, false).ContinueWithSync(() => {
                        if (!smh.Cancelled)
                        {
                            bgo?.QueueTransition(props.Boss.bossCutinTrOut);
                            bgo?.ConstructTarget(props.Background, true);
                        }
                    });
                    cutins   = WaitingUtils.WaitForUnchecked(smh.Exec, smh.cT, props.Boss.bossCutinTime, false);
                    forcedBG = true;
                }
                else if (props.GetSpellCutin(out var sc))
                {
                    SFXService.BossSpellCutin();
                    DependencyInjection.MaybeFind <IRaiko>()?.Shake(1.5f, null, 1f, smh.cT, null);
                    Object.Instantiate(sc);
                }
            }
            if (!forcedBG && props.Background != null)
            {
                if (props.BgTransitionIn != null)
                {
                    bgo?.QueueTransition(props.BgTransitionIn);
                }
                bgo?.ConstructTarget(props.Background, true);
            }
        }
Example #11
0
        public override async Task Start(SMHandoff smh)
        {
            var jsmh       = smh.CreateJointCancellee(out var cts);
            var subbosses  = new List <Enemy>();
            var subsummons = new List <BehaviorEntity>();
            var ui         = DependencyInjection.MaybeFind <IUIManager>();

            if (props.boss != null)
            {
                GameManagement.Instance.SetCurrentBoss(props.boss, jsmh.Exec, jsmh.cT);
                ui?.SetBossHPLoader(jsmh.Exec.Enemy);
                (subbosses, subsummons) = ConfigureAllBosses(ui, jsmh, props.boss, props.bosses);
            }
            bool firstBoss = true;

            for (var next = jsmh.Exec.phaseController.WhatIsNextPhase();
                 next > -1 && next < phases.Length;
                 next = jsmh.Exec.phaseController.WhatIsNextPhase(next + 1))
            {
                if (phases[next].props.skip)
                {
                    continue;
                }
                if (PHASE_BUFFER)
                {
                    await WaitingUtils.WaitForUnchecked(jsmh.Exec, jsmh.cT, ETime.FRAME_TIME * 2f, false);
                }
                jsmh.ThrowIfCancelled();
                if (props.bgms != null)
                {
                    AudioTrackService.InvokeBGM(props.bgms.GetBounded(next, null));
                }
                if (props.boss != null && next >= props.setUIFrom)
                {
                    SetUniqueBossUI(ui, firstBoss, jsmh,
                                    props.bosses == null ? props.boss :
                                    props.bosses[props.bossUI?.GetBounded(next, 0) ?? 0]);
                    firstBoss = false;
                }
                //don't show lives on setup phase
                if (next > 0 && props.boss != null)
                {
                    ui?.ShowBossLives(RemainingLives(next));
                }
                try {
                    await phases[next].Start(jsmh, ui, subbosses);
                } catch (OperationCanceledException) {
                    //Runs the cleanup code if we were cancelled
                    break;
                }
            }
            cts.Cancel();
            if (props.boss != null && !SceneIntermediary.LOADING)
            {
                ui?.CloseBoss();
                if (!firstBoss)
                {
                    ui?.CloseProfile();
                }
                foreach (var subsummon in subsummons)
                {
                    subsummon.InvokeCull();
                }
            }
        }
Example #12
0
        private void DoTransition(BackgroundTransition bgt)
        {
            if (FromBG == null)
            {
                return;
            }
            if (ToBG == null)
            {
                throw new Exception("Cannot do transition when target BG is null");
            }
            var   pb      = new MaterialPropertyBlock();
            var   mat     = Instantiate(baseMixerMaterial);
            float timeout = bgt.TimeToFinish();
            var   cts     = new Cancellable();

            transitionCTS.Add(cts);
            Func <bool>?condition = null;

            if (bgt.type == BackgroundTransition.EffectType.WipeTex)
            {
                bgt.WipeTex.Apply(mat);
                CombinerKeywords.Apply(mat, CombinerKeywords.WIPE_TEX);
            }
            else if (bgt.type == BackgroundTransition.EffectType.Wipe1)
            {
                bgt.Wipe1.Apply(mat);
                CombinerKeywords.Apply(mat, CombinerKeywords.WIPE1);
            }
            else if (bgt.type == BackgroundTransition.EffectType.WipeFromCenter)
            {
                bgt.WipeFromCenter.Apply(mat);
                CombinerKeywords.Apply(mat, CombinerKeywords.WIPEFROMCENTER);
            }
            else if (bgt.type == BackgroundTransition.EffectType.Shatter4)
            {
                Action cb = WaitingUtils.GetCondition(out condition);
                FromBG.Shatter4(bgt.Shatter4, false, cb);
                CombinerKeywords.Apply(mat, CombinerKeywords.TO_ONLY);
            }
            else if (bgt.type == BackgroundTransition.EffectType.WipeY)
            {
                bgt.WipeY.Apply(mat);
                CombinerKeywords.Apply(mat, CombinerKeywords.WIPEY); //TODO apply these two generics from within the BGT scope.
            }
            BackgroundCombiner.SetMaterial(mat, pb);
            void Finish()
            {
                if (!cts.Cancelled)
                {
                    FinishTransition();
                }
                transitionCTS.Remove(cts);
            }

            if (condition == null)
            {
                if (timeout > 0)
                {
                    WaitingUtils.WaitThenCBEvenIfCancelled(this, cts, timeout, false, Finish);
                }
                else
                {
                    throw new Exception("Cannot wait for transition without a timeout or condition");
                }
            }
            else
            {
                WaitingUtils.WaitThenCBEvenIfCancelled(this, cts, timeout, condition, Finish);
            }
        }