public static void Reload()
        {
            // ChapterSelect only updates the ID.
            string lastAreaSID = AreaData.Get(SaveData.Instance.LastArea.ID)?.ToKey().GetSID() ?? AreaKey.Default.GetSID();

            // Note: SaveData.Instance.LastArea is reset by AreaData.Interlude_Safe -> SaveData.LevelSetStats realizing that AreaOffset == -1
            // Store the "resolved" last selected area in a local variable, then re-set it after reloading.

            // Reload all maps.
            Everest.Content.Recrawl();
            AreaData.Unload();
            AreaData.Load();
            AreaData.ReloadMountainViews();

            // Fake a save data reload to resync the save data to the new area list.
            AreaData lastArea = AreaDataExt.Get(lastAreaSID);

            SaveData.Instance.LastArea = lastArea?.ToKey() ?? AreaKey.Default;
            SaveData.Instance.BeforeSave();
            SaveData.Instance.AfterInitialize();

            Overworld overworld = (Engine.Scene.Entities.FindFirst <Oui>())?.Overworld;

            if (overworld == null)
            {
                return;
            }
            if (overworld.Mountain.Area >= AreaData.Areas.Count)
            {
                overworld.Mountain.EaseCamera(0, AreaData.Areas[0].MountainIdle, null, true);
            }
            overworld.ReloadMenus((Overworld.StartMode)(-1));
        }
Beispiel #2
0
        public override IEnumerator Enter(Oui from)
        {
            if (Direction == 0)
            {
                Overworld.Goto <OuiChapterSelect>();
                goto Done;
            }
            Direction = Math.Sign(Direction);

            yield return(0.25f);

            int    startID       = SaveData.Instance.LastArea.ID;
            string startLevelSet = SaveData.Instance.GetLevelSet();
            int    count         = AreaData.Areas.Count;

            for (int i = (count + startID + Direction) % count; i != startID; i = (count + i + Direction) % count)
            {
                AreaData area = AreaData.Areas[i];
                if (area.GetLevelSet() != startLevelSet)
                {
                    SaveData.Instance.LastArea = area.ToKey();
                    goto Done;
                }
            }

Done:
            Audio.Play("event:/ui/world_map/chapter/pane_expand");
            Overworld.Goto <OuiChapterSelect>();
            yield break;
        }
Beispiel #3
0
        public override IEnumerator Enter(Oui from)
        {
            // Fix "out of bounds" level selection.
            int areaOffs = SaveData.Instance.GetLevelSetStats().AreaOffset;
            int areaMax  = Math.Max(areaOffs, SaveData.Instance.UnlockedAreas);

            area = Calc.Clamp(area, areaOffs, areaMax);

            Visible = true;
            EaseCamera();
            display = true;

            journalEnabled = Celeste.PlayMode == Celeste.PlayModes.Debug || (SaveData.Instance?.CheatMode ?? false);
            for (int i = 0; i <= SaveData.Instance.UnlockedAreas && !journalEnabled; i++)
            {
                if (SaveData.Instance.Areas[i].Modes[0].TimePlayed > 0L && !AreaData.Get(i).Interlude)
                {
                    journalEnabled = true;
                }
            }

            OuiChapterSelectIcon unselected = null;

            if (from is OuiChapterPanel)
            {
                (unselected = icons[area]).Unselect();
            }

            currentLevelSet = SaveData.Instance?.GetLevelSet() ?? "Celeste";
            foreach (OuiChapterSelectIcon icon in icons)
            {
                AreaData area = AreaData.Areas[icon.Area];
                if (area.GetLevelSet() != currentLevelSet)
                {
                    continue;
                }

                int index = area.ToKey().ID;
                if (index <= Math.Max(1, SaveData.Instance.UnlockedAreas) && icon != unselected)
                {
                    icon.Position = icon.HiddenPosition;
                    icon.Show();
                    icon.AssistModeUnlockable = false;
                }
                else if (SaveData.Instance.AssistMode && index == SaveData.Instance.UnlockedAreas + 1)
                {
                    icon.Position = icon.HiddenPosition;
                    icon.Show();
                    icon.AssistModeUnlockable = true;
                }

                // yield return 0.01f; // Originally returns 0.01f
            }

            if (from is OuiChapterPanel)
            {
                yield return(0.25f);
            }
        }
Beispiel #4
0
 public void Inspect(AreaData area, AreaMode mode = AreaMode.Normal)
 {
     Focused = false;
     Audio.Play(SFX.ui_world_icon_select);
     SaveData.Instance.LastArea = area.ToKey(mode);
     if (OuiIcons != null && area.ID < OuiIcons.Count)
     {
         OuiIcons[area.ID].Select();
     }
     Overworld.Mountain.Model.EaseState(area.MountainState);
     Overworld.Goto <OuiChapterPanel>();
 }
Beispiel #5
0
        private static void OnChapterPanelReset(On.Celeste.OuiChapterPanel.orig_Reset orig, OuiChapterPanel self)
        {
            resetCrystalHeart(self);

            AreaData forceArea = self.Overworld == null ? null : new DynData <Overworld>(self.Overworld).Get <AreaData>("collabInGameForcedArea");

            if (forceArea == null)
            {
                orig(self);
                customizeCrystalHeart(self);
                return;
            }

            SaveData save    = SaveData.Instance;
            Session  session = save.CurrentSession;

            lastArea = save.LastArea;

            save.LastArea       = forceArea.ToKey();
            save.CurrentSession = null;

            DynData <OuiChapterSelect> ouiChapterSelect = new DynData <OuiChapterSelect>(self.Overworld.GetUI <OuiChapterSelect>());
            OuiChapterSelectIcon       icon             = ouiChapterSelect.Get <List <OuiChapterSelectIcon> >("icons")[save.LastArea.ID];

            icon.SnapToSelected();
            icon.Add(new Coroutine(UpdateIconRoutine(self, icon)));

            orig(self);
            customizeCrystalHeart(self);

            DynData <OuiChapterPanel> data = new DynData <OuiChapterPanel>(self);

            data["hasCollabCredits"] = true;

            if (!isPanelShowingLobby())
            {
                data["chapter"] = (new DynData <Overworld>(self.Overworld).Get <AreaData>("collabInGameForcedArea").Name + "_author").DialogCleanOrNull() ?? "";
            }

            /*
             * (data.modes as IList).Add(
             *  DynamicData.New(t_OuiChapterPanelOption)(new {
             *      Label = "",
             *      BgColor = Calc.HexToColor("223022"),
             *      Icon = GFX.Gui["areas/null"],
             *      Large = false
             *  })
             * );
             */

            // LastArea is also checked in Render.
            save.CurrentSession = session;
        }
Beispiel #6
0
        public static void Reload(bool recrawl)
        {
            SaveData saveData = SaveData.Instance;

            // ChapterSelect only updates the ID.
            string lastAreaSID = saveData == null ? null : (AreaData.Get(saveData.LastArea.ID)?.ToKey().GetSID() ?? AreaKey.Default.GetSID());

            // Note: SaveData.Instance.LastArea is reset by AreaData.Interlude_Safe -> SaveData.LevelSetStats realizing that AreaOffset == -1
            // Store the "resolved" last selected area in a local variable, then re-set it after reloading.

            // Reload all maps.
            if (recrawl)
            {
                Everest.Content.Recrawl();
            }

            lock (AreaReloadLock) { // prevent anything from calling AreaData.Get during this.
                AreaData.Unload();
                AreaData.Load();
                AreaData.ReloadMountainViews();

                // Fake a save data reload to resync the save data to the new area list.
                if (saveData != null)
                {
                    AreaData lastArea = AreaDataExt.Get(lastAreaSID);
                    saveData.LastArea = lastArea?.ToKey() ?? AreaKey.Default;
                    saveData.BeforeSave();
                    saveData.AfterInitialize();
                }
            }

            if (Engine.Scene is Overworld overworld)
            {
                if (overworld.Mountain.Area >= AreaData.Areas.Count)
                {
                    overworld.Mountain.EaseCamera(0, AreaData.Areas[0].MountainIdle, null, true);
                }

                OuiChapterSelect chapterSelect = overworld.GetUI <OuiChapterSelect>();
                overworld.UIs.Remove(chapterSelect);
                overworld.Remove(chapterSelect);

                chapterSelect         = new OuiChapterSelect();
                chapterSelect.Visible = false;
                overworld.Add(chapterSelect);
                overworld.UIs.Add(chapterSelect);
                chapterSelect.IsStart(overworld, (Overworld.StartMode)(-1));
            }
        }
Beispiel #7
0
        private IEnumerator StartRoutine(AreaData area, AreaMode mode = AreaMode.Normal, string checkpoint = null)
        {
            Overworld.Maddy.Hide(false);
            area.Wipe(Overworld, false, null);
            Audio.SetMusic(null, true, true);
            Audio.SetAmbience(null, true);
            if ((area.ID == 0 || area.ID == 9) && checkpoint == null && mode == AreaMode.Normal)
            {
                Overworld.RendererList.UpdateLists();
                Overworld.RendererList.MoveToFront(Overworld.Snow);
            }
            yield return(0.5f);

            LevelEnter.Go(new Session(area.ToKey(mode), checkpoint), false);
        }
Beispiel #8
0
        private void ProcessMeta(BinaryPacker.Element meta)
        {
            AreaData area = AreaData.Get(Area);
            AreaMode mode = Area.Mode;

            if (mode == AreaMode.Normal)
            {
                new MapMeta(meta).ApplyTo(area);
                Area = area.ToKey();
            }

            meta = meta.Children?.FirstOrDefault(el => el.Name == "mode");
            if (meta == null)
            {
                return;
            }

            new MapMetaModeProperties(meta).ApplyTo(area, mode);
        }
Beispiel #9
0
        private void ProcessMeta(BinaryPacker.Element meta)
        {
            AreaData area = AreaData.Get(Area);
            AreaMode mode = Area.Mode;

            if (mode == AreaMode.Normal)
            {
                new MapMeta(meta).ApplyTo(area);
                Area = area.ToKey();

                // Backup A-Side's Metadata. Only back up useful data.
                area.SetASideAreaDataBackup(new AreaData {
                    IntroType     = area.IntroType,
                    ColorGrade    = area.ColorGrade,
                    DarknessAlpha = area.DarknessAlpha,
                    BloomBase     = area.BloomBase,
                    BloomStrength = area.BloomStrength,
                    CoreMode      = area.CoreMode,
                    Dreaming      = area.Dreaming
                });
            }

            BinaryPacker.Element modeMeta = meta.Children?.FirstOrDefault(el => el.Name == "mode");
            if (modeMeta == null)
            {
                return;
            }

            new MapMetaModeProperties(modeMeta).ApplyTo(area, mode);

            // Metadata for B-Side and C-Side are parsed and stored.
            if (mode != AreaMode.Normal)
            {
                MapMeta mapMeta = new MapMeta(meta)
                {
                    Modes = area.GetMeta().Modes
                };
                area.Mode[(int)mode].SetMapMeta(mapMeta);
            }
        }
        private static void onLevelExitConstructor(On.Celeste.LevelExit.orig_ctor orig, LevelExit self, LevelExit.Mode mode, Session session, HiresSnow snow)
        {
            orig(self, mode, session, snow);

            if (mode == LevelExit.Mode.Restart || mode == LevelExit.Mode.GoldenBerryRestart)
            {
                // be sure to keep the lobby info in the session, even if we are resetting it.
                temporaryLobbySIDHolder    = CollabModule.Instance.Session.LobbySID;
                temporaryRoomHolder        = CollabModule.Instance.Session.LobbyRoom;
                temporarySpawnPointHolder  = new Vector2(CollabModule.Instance.Session.LobbySpawnPointX, CollabModule.Instance.Session.LobbySpawnPointY);
                temporarySaveAllowedHolder = CollabModule.Instance.Session.SaveAndReturnToLobbyAllowed;
            }
            if ((mode == LevelExit.Mode.GiveUp || mode == LevelExit.Mode.Completed) && CollabModule.Instance.Session.LobbySID != null)
            {
                // be sure that Return to Map and such from a collab entry returns to the lobby, not to the collab entry...
                // if the lobby exists, of course.
                AreaData lobby = AreaData.Get(CollabModule.Instance.Session.LobbySID);
                if (lobby != null)
                {
                    SaveData.Instance.LastArea_Safe = lobby.ToKey();
                }
            }
        }
        public override IEnumerator Enter(Oui from)
        {
            if (Direction == 0)
            {
                Overworld.Goto <OuiChapterSelect>();
                goto Done;
            }
            Direction = Math.Sign(Direction);

            yield return(0.25f);

            int    startID       = SaveData.Instance.LastArea.ID;
            string startLevelSet = SaveData.Instance.GetLevelSet();
            int    count         = AreaData.Areas.Count;

            for (int i = (count + startID + Direction) % count; i != startID; i = (count + i + Direction) % count)
            {
                AreaData area = AreaData.Get(i);
                if (area == null || area.GetLevelSet() != startLevelSet)
                {
                    SaveData.Instance.LastArea = area.ToKey();
                    goto Done;
                }
            }

Done:
            if (Direction > 0)
            {
                Audio.Play(SFX.ui_world_chapter_pane_expand);
            }
            else
            {
                Audio.Play(SFX.ui_world_chapter_pane_contract);
            }
            Overworld.Goto <OuiChapterSelect>();
        }
Beispiel #12
0
        private static void onOuiFileSelectSlotShow(On.Celeste.OuiFileSelectSlot.orig_Show orig, OuiFileSelectSlot self)
        {
            // If we are currently in a collab map, display the lobby level set stats instead.
            AreaKey?savedLastArea = null;
            string  collab        = collabNames.FirstOrDefault(collabName => self.SaveData?.LevelSet != null && self.SaveData.LevelSet.StartsWith($"{collabName}/") && self.SaveData.LevelSet != $"{collabName}/0-Lobbies");

            if (collab != null)
            {
                AreaData firstMapFromCollab = AreaData.Areas.FirstOrDefault(area => area.GetLevelSet() == $"{collab}/0-Lobbies");
                if (firstMapFromCollab != null)
                {
                    savedLastArea = self.SaveData.LastArea_Safe;
                    self.SaveData.LastArea_Safe = firstMapFromCollab.ToKey();
                    self.Strawberries.CanWiggle = false; // prevent the strawberry collect sound from playing.
                }
            }

            orig(self);

            string collab2 = collabNames.FirstOrDefault(collabName => self.SaveData?.LevelSet == $"{collabName}/0-Lobbies");

            if (collab2 != null)
            {
                // recompute the stats for the collab.
                int totalStrawberries                    = 0;
                int totalGoldenStrawberries              = 0;
                int totalHeartGems                       = 0;
                int totalCassettes                       = 0;
                int maxStrawberryCount                   = 0;
                int maxGoldenStrawberryCount             = 0;
                int maxStrawberryCountIncludingUntracked = 0;
                int maxCassettes     = 0;
                int maxCrystalHearts = 0;
                int maxCrystalHeartsExcludingCSides = 0;

                // aggregate all stats for the collab level sets.
                foreach (LevelSetStats stats in self.SaveData.LevelSets)
                {
                    if (stats.Name.StartsWith($"{collab2}/"))
                    {
                        totalStrawberries                    += stats.TotalStrawberries;
                        totalGoldenStrawberries              += stats.TotalGoldenStrawberries;
                        totalHeartGems                       += countTotalHeartGemsForMapsThatHaveHearts(stats);
                        totalCassettes                       += stats.TotalCassettes;
                        maxStrawberryCount                   += stats.MaxStrawberries;
                        maxGoldenStrawberryCount             += stats.MaxGoldenStrawberries;
                        maxStrawberryCountIncludingUntracked += stats.MaxStrawberriesIncludingUntracked;
                        maxCassettes     += stats.MaxCassettes;
                        maxCrystalHearts += stats.MaxHeartGems;
                        maxCrystalHeartsExcludingCSides += stats.MaxHeartGemsExcludingCSides;
                    }
                }

                DynData <OuiFileSelectSlot> slotData = new DynData <OuiFileSelectSlot>(self);
                slotData["totalGoldenStrawberries"]              = totalGoldenStrawberries;
                slotData["totalHeartGems"]                       = totalHeartGems;
                slotData["totalCassettes"]                       = totalCassettes;
                slotData["maxStrawberryCount"]                   = maxStrawberryCount;
                slotData["maxGoldenStrawberryCount"]             = maxGoldenStrawberryCount;
                slotData["maxStrawberryCountIncludingUntracked"] = maxStrawberryCountIncludingUntracked;
                slotData["maxCassettes"]     = maxCassettes;
                slotData["maxCrystalHearts"] = maxCrystalHearts;
                slotData["maxCrystalHeartsExcludingCSides"] = maxCrystalHeartsExcludingCSides;
                slotData["summitStamp"]   = false;
                slotData["farewellStamp"] = false;

                self.Strawberries.Amount = totalStrawberries;
                self.Strawberries.OutOf  = maxStrawberryCount;
            }

            // Restore the last area if it was replaced at the beginning of this method.
            if (savedLastArea != null)
            {
                self.SaveData.LastArea_Safe = savedLastArea.Value;
            }
        }
Beispiel #13
0
        public static new void Load()
        {
            orig_Load();

            // assign SIDs and CheckpointData.Area for vanilla maps.
            foreach (AreaData area in Areas)
            {
                area.SetSID("Celeste/" + area.Mode[0].Path);

                for (int modeId = 0; modeId < area.Mode.Length; modeId++)
                {
                    ModeProperties mode = area.Mode[modeId];
                    if (mode?.Checkpoints == null)
                    {
                        continue;
                    }

                    foreach (CheckpointData checkpoint in mode.Checkpoints)
                    {
                        checkpoint.SetArea(area.ToKey((AreaMode)modeId));
                    }
                }
            }

            // Separate array as we sort it afterwards.
            List <AreaData> modAreas = new List <AreaData>();

            lock (Everest.Content.Map) {
                foreach (ModAsset asset in Everest.Content.Map.Values.Where(asset => asset.Type == typeof(AssetTypeMap)))
                {
                    string path = asset.PathVirtual.Substring(5);

                    AreaData area = new AreaData();

                    // Default values.

                    area.SetSID(path);
                    area.Name = path;
                    area.Icon = "areas/" + path.ToLowerInvariant();
                    if (!GFX.Gui.Has(area.Icon))
                    {
                        area.Icon = "areas/null";
                    }

                    area.Interlude    = false;
                    area.CanFullClear = true;

                    area.TitleBaseColor   = Calc.HexToColor("6c7c81");
                    area.TitleAccentColor = Calc.HexToColor("2f344b");
                    area.TitleTextColor   = Color.White;

                    area.IntroType = Player.IntroTypes.WakeUp;

                    area.Dreaming   = false;
                    area.ColorGrade = null;

                    area.Mode = new ModeProperties[] {
                        new ModeProperties {
                            Inventory  = PlayerInventory.Default,
                            AudioState = new AudioState(SFX.music_city, SFX.env_amb_00_main)
                        }
                    };

                    area.Wipe = (Scene scene, bool wipeIn, Action onComplete)
                                => new AngledWipe(scene, wipeIn, onComplete);

                    area.DarknessAlpha = 0.05f;
                    area.BloomBase     = 0f;
                    area.BloomStrength = 1f;

                    area.Jumpthru = "wood";

                    area.CassseteNoteColor = Calc.HexToColor("33a9ee");
                    area.CassetteSong      = SFX.cas_01_forsaken_city;

                    // Custom values can be set via the MapMeta.
                    MapMeta meta = new MapMeta();
                    meta.ApplyTo(area);
                    MapMeta metaLoaded = asset.GetMeta <MapMeta>();
                    if (metaLoaded != null)
                    {
                        area.SetMeta(null);
                        metaLoaded.ApplyTo(area);
                        meta = metaLoaded;
                    }

                    if (string.IsNullOrEmpty(area.Mode[0].Path))
                    {
                        area.Mode[0].Path = asset.PathVirtual.Substring(5);
                    }

                    // Some of the game's code checks for [1] / [2] explicitly.
                    // Let's just provide null modes to fill any gaps.
                    meta.Modes = meta.Modes ?? new MapMetaModeProperties[3];
                    if (meta.Modes.Length < 3)
                    {
                        MapMetaModeProperties[] larger = new MapMetaModeProperties[3];
                        for (int i = 0; i < meta.Modes.Length; i++)
                        {
                            larger[i] = meta.Modes[i];
                        }
                        meta.Modes = larger;
                    }
                    if (area.Mode.Length < 3)
                    {
                        ModeProperties[] larger = new ModeProperties[3];
                        for (int i = 0; i < area.Mode.Length; i++)
                        {
                            larger[i] = area.Mode[i];
                        }
                        area.Mode = larger;
                    }

                    // Celeste levelset always appears first.
                    if (area.GetLevelSet() == "Celeste")
                    {
                        Areas.Add(area);
                    }
                    else
                    {
                        modAreas.Add(area);
                    }

                    // Some special handling.
                    area.OnLevelBegin = (level) => {
                        MapMeta levelMeta = AreaData.Get(level.Session).GetMeta();
                        MapMetaModeProperties levelMetaMode = level.Session.MapData.GetMeta();

                        if (levelMetaMode?.SeekerSlowdown ?? false)
                        {
                            level.Add(new SeekerEffectsController());
                        }
                    };
                }
            }


            // Merge modAreas into Areas.
            Areas.AddRange(modAreas);

            // Find duplicates and remove any earlier copies.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area       = Areas[i];
                int      otherIndex = Areas.FindIndex(other => other.GetSID() == area.GetSID());
                if (otherIndex < i)
                {
                    Areas[otherIndex] = area;
                    Areas.RemoveAt(i);
                    i--;
                }
            }

            // Sort areas.
            Areas.Sort(AreaComparison);

            // Remove AreaDatas which are now a mode of another AreaData.
            // This can happen late as the map data (.bin) can contain additional metadata.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area       = Areas[i];
                string   path       = area.Mode[0].Path;
                int      otherIndex = Areas.FindIndex(other => other.Mode.Any(otherMode => otherMode?.Path == path));
                if (otherIndex != -1 && otherIndex != i)
                {
                    Areas.RemoveAt(i);
                    i--;
                    continue;
                }

                int?     order;
                AreaMode side;
                string   name;
                ParseName(path, out order, out side, out name);

                // Also check for .bins possibly belonging to A side .bins by their path and lack of existing modes.
                for (int ii = 0; ii < Areas.Count; ii++)
                {
                    AreaData other = Areas[ii];
                    int?     otherOrder;
                    AreaMode otherSide;
                    string   otherName;
                    ParseName(other.Mode[0].Path, out otherOrder, out otherSide, out otherName);

                    if (area.GetLevelSet() == other.GetLevelSet() && order == otherOrder && name == otherName && side != otherSide &&
                        !other.HasMode(side))
                    {
                        if (other.Mode[(int)side] == null)
                        {
                            other.Mode[(int)side] = new ModeProperties {
                                Inventory  = PlayerInventory.Default,
                                AudioState = new AudioState(SFX.music_city, SFX.env_amb_00_main)
                            }
                        }
                        ;
                        other.Mode[(int)side].Path = path;
                        Areas.RemoveAt(i);
                        i--;
                        break;
                    }
                }
            }

            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area = Areas[i];
                area.ID = i;

                // Clean up non-existing modes.
                int modei = 0;
                for (; modei < area.Mode.Length; modei++)
                {
                    ModeProperties mode = area.Mode[modei];
                    if (mode == null || string.IsNullOrEmpty(mode.Path))
                    {
                        break;
                    }
                }
                Array.Resize(ref area.Mode, modei);

                Logger.Log("AreaData", $"{i}: {area.GetSID()} - {area.Mode.Length} sides");

                // Update old MapData areas and load any new areas.

                // Add the A side MapData or update its area key.
                if (area.Mode[0].MapData != null)
                {
                    area.Mode[0].MapData.Area = area.ToKey();
                }
                else
                {
                    area.Mode[0].MapData = new MapData(area.ToKey());
                }

                if (area.IsInterludeUnsafe())
                {
                    continue;
                }

                // A and (some) B sides have PoemIDs. Can be overridden via empty PoemID.
                if (area.Mode[0].PoemID == null)
                {
                    area.Mode[0].PoemID = area.GetSID().DialogKeyify() + "_A";
                }
                if (area.Mode.Length > 1 &&
                    area.Mode[1] != null &&
                    area.Mode[1].PoemID == null)
                {
                    area.Mode[1].PoemID = area.GetSID().DialogKeyify() + "_B";
                }

                // Update all other existing mode's area keys.
                for (int mode = 1; mode < area.Mode.Length; mode++)
                {
                    if (area.Mode[mode] == null)
                    {
                        continue;
                    }
                    if (area.Mode[mode].MapData != null)
                    {
                        area.Mode[mode].MapData.Area = area.ToKey((AreaMode)mode);
                    }
                    else
                    {
                        area.Mode[mode].MapData = new MapData(area.ToKey((AreaMode)mode));
                    }
                }
            }

            // Load custom mountains
            // This needs to be done after areas are loaded because it depends on the MapMeta
            MTNExt.LoadMod();
            MTNExt.LoadModData();
        }
Beispiel #14
0
        private static void AddExtraModes(OuiChapterPanel self)
        {
            // check map meta for extra sides or side overrides
            //AltSidesHelperMeta meta = new DynData<AreaData>(self.Data).Get<AltSidesHelperMeta>("AltSidesHelperMeta");
            AltSidesHelperMeta meta = GetMetaForAreaData(self.Data);            //AltSidesMetadata[self.Data];

            if (meta?.Sides != null)
            {
                Logger.Log("AltSidesHelper", $"Customising panel UI for \"{self.Data.SID}\".");
                bool[] unlockedSides  = new bool[meta.Sides.Count()];
                int    siblings       = ((IList)modesField.GetValue(self)).Count;
                int    oldModes       = siblings;
                bool   bsidesunlocked = !self.Data.Interlude_Safe && self.Data.HasMode(AreaMode.BSide) && (self.DisplayedStats.Cassette || ((SaveData.Instance.DebugMode || SaveData.Instance.CheatMode) && self.DisplayedStats.Cassette == self.RealStats.Cassette));
                bool   csidesunlocked = !self.Data.Interlude_Safe && self.Data.HasMode(AreaMode.CSide) && SaveData.Instance.UnlockedModes >= 3 && Celeste.Celeste.PlayMode != Celeste.Celeste.PlayModes.Event;
                // find the new total number of unlocked modes
                int unlockedModeCount = 0;
                // if this map has a C-Side, this is whether they have C-sides unlocked. else, if this map has a B-Sides, its whether they have a cassette. else, true.
                bool prevUnlocked = self.Data.HasMode(AreaMode.CSide) ? csidesunlocked : self.Data.HasMode(AreaMode.BSide) ? bsidesunlocked : true;
                // if this map has a C-Side, this is whether they've beaten it; else, if this map has a B-Side, its whether they've completed it; else, its whether they've completed the level.
                bool prevCompleted = self.Data.HasMode(AreaMode.CSide) ? SaveData.Instance.GetAreaStatsFor(self.Data.ToKey()).Modes[(int)AreaMode.CSide].Completed : self.Data.HasMode(AreaMode.BSide) ? SaveData.Instance.GetAreaStatsFor(self.Data.ToKey()).Modes[(int)AreaMode.BSide].Completed : SaveData.Instance.GetAreaStatsFor(self.Data.ToKey()).Modes[(int)AreaMode.Normal].Completed;
                for (int i1 = 0; i1 < meta.Sides.Length; i1++)
                {
                    AltSidesHelperMode mode = meta.Sides[i1];
                    if (!mode.OverrideVanillaSideData)
                    {
                        if ((mode.UnlockMode.Equals("consecutive") && prevCompleted) || (mode.UnlockMode.Equals("with_previous") && prevUnlocked) || (mode.UnlockMode.Equals("triggered") && AltSidesSaveData.UnlockedAltSideIDs.Contains(mode.Map)) || (mode.UnlockMode.Equals("c_sides_unlocked") && csidesunlocked) || mode.UnlockMode.Equals("always") || SaveData.Instance.DebugMode || SaveData.Instance.CheatMode)
                        {
                            unlockedModeCount++;
                            siblings++;
                            prevUnlocked      = true;
                            prevCompleted     = SaveData.Instance.GetAreaStatsFor(AreaData.Get(mode.Map).ToKey()).Modes[(int)AreaMode.Normal].Completed;
                            unlockedSides[i1] = true;
                        }
                        else
                        {
                            prevUnlocked      = prevCompleted = false;
                            unlockedSides[i1] = false;
                        }
                    }
                    else
                    {
                        unlockedSides[i1] = true;
                    }
                }
                // adjust the original options to fit, and attach the map path & mode to the original options
                int origMode = 0;
                foreach (var vmode in (IList)modesField.GetValue(self))
                {
                    DynamicData data = new DynamicData(vmode);
                    if (siblings > 5)
                    {
                        data.Set("Siblings", siblings);
                        data.Set("Large", false);
                    }
                    data.Set("AreaKey", self.Data.ToKey((AreaMode)origMode));
                    origMode++;
                }

                // apply mode settings
                int newSides = 0;
                for (int i = 0; i < meta.Sides.Length /*&& newSides < unlockedModes*/; i++)
                {
                    AltSidesHelperMode mode = meta.Sides[i];
                    // only add if its unlocked
                    if (unlockedSides[i])
                    {
                        if (!mode.OverrideVanillaSideData)
                        {
                            object newOptn;
                            ((IList)modesField.GetValue(self)).Add(
                                newOptn = DynamicData.New(t_OuiChapterPanelOption)(new {
                                Label    = Dialog.Clean(mode.Label),
                                Icon     = GFX.Gui[mode.Icon],
                                ID       = "AltSidesHelperMode_" + i.ToString(),
                                Siblings = siblings > 5 ? siblings : 0
                            })
                                );
                            DynamicData data = new DynamicData(newOptn);
                            AreaData    map  = null;
                            foreach (var area in AreaData.Areas)
                            {
                                if (area.SID.Equals(mode.Map))
                                {
                                    map = area;
                                }
                            }
                            data.Set("AreaKey", map.ToKey());
                            newSides++;
                            Logger.Log("AltSidesHelper", $"Added new side for \"{self.Data.SID}\".");
                        }
                        else
                        {
                            // find the a-side and modify it
                            DynamicData data = new DynamicData(((IList)modesField.GetValue(self))[0]);
                            data.Set("Label", Dialog.Clean(mode.Label));
                            data.Set("Icon", GFX.Gui[mode.Icon]);
                            Logger.Log("AltSidesHelper", $"Modifying A-Side data for \"{self.Data.SID}\".");
                        }
                    }
                }
            }

            int count = ((IList)modesField.GetValue(self)).Count;

            for (int i = 0; i < count; i++)
            {
                //DynamicData data = new DynamicData(((IList)modesField.GetValue(self))[i]);
                //data.Invoke("SlideTowards", count, i);
            }
        }
Beispiel #15
0
        public static List <OuiJournalCollabProgressInLobby> GeneratePages(OuiJournal journal, string levelSet, bool showOnlyDiscovered)
        {
            bool displaySpeedBerryColumn = shouldDisplaySpeedBerryColumn(levelSet);

            List <OuiJournalCollabProgressInLobby> pages = new List <OuiJournalCollabProgressInLobby>();
            int rowCount = 0;

            int  totalStrawberries = 0;
            int  totalDeaths       = 0;
            int  sumOfBestDeaths   = 0;
            int  sumOfBestDashes   = 0;
            long totalTime         = 0;
            long sumOfBestTimes    = 0;

            bool allMapsDone = true;

            bool allLevelsDone       = true;
            bool allSpeedBerriesDone = true;

            string heartTexture = MTN.Journal.Has("CollabUtils2Hearts/" + levelSet) ? "CollabUtils2Hearts/" + levelSet : "heartgem0";

            int mapsPerPage = 12;
            int mapAmount   = SaveData.Instance.Areas_Safe.Where(item => !AreaData.Get(item.ID_Safe).Interlude_Safe &&
                                                                 (!showOnlyDiscovered || item.TotalTimePlayed > 0)).Count();

            // we want to display the map icons if they're not actually all the same. ^^'
            bool displayIcons = AreaData.Areas
                                .Where(area => !area.Interlude_Safe)
                                .Select(area => area.Icon)
                                .Distinct()
                                .Count() > 1;

            OuiJournalCollabProgressInLobby currentPage = new OuiJournalCollabProgressInLobby(journal, levelSet, displayIcons);

            pages.Add(currentPage);

            if (mapAmount >= mapsPerPage)
            {
                // we want the last page to contain at least 2 maps.
                while (mapAmount % mapsPerPage < 2)
                {
                    mapsPerPage--;
                }
            }

            List <AreaStats> sortedMaps = new List <AreaStats>(SaveData.Instance.Areas_Safe)
                                          .Where(map => !AreaData.Get(map).Interlude_Safe)
                                          .ToList();

            // sort maps by icon name if all of their icons start with [number]-...
            // because then we know the ordering is intentional (and not accidental like easy > hard > medium)
            Regex startsWithNumber = new Regex(".*/[0-9]+-.*");

            if (sortedMaps.Select(map => AreaData.Get(map).Icon ?? "").All(icon => startsWithNumber.IsMatch(icon)))
            {
                sortedMaps.Sort((a, b) => {
                    AreaData adata = AreaData.Get(a);
                    AreaData bdata = AreaData.Get(b);

                    bool aHeartSide = LobbyHelper.IsHeartSide(a.GetSID());
                    bool bHeartSide = LobbyHelper.IsHeartSide(b.GetSID());

                    // heart sides should appear last.
                    if (aHeartSide && !bHeartSide)
                    {
                        return(1);
                    }
                    if (!aHeartSide && bHeartSide)
                    {
                        return(-1);
                    }

                    // sort by icon name, then by map bin name.
                    return(adata.Icon == bdata.Icon ? adata.Name.CompareTo(bdata.Name) : adata.Icon.CompareTo(bdata.Icon));
                });
            }

            foreach (AreaStats item in sortedMaps)
            {
                AreaData areaData = AreaData.Get(item.ID_Safe);
                if (LobbyHelper.IsHeartSide(areaData.GetSID()))
                {
                    if (allMapsDone || item.TotalTimePlayed > 0)
                    {
                        // add a separator, like the one between regular maps and Farewell
                        currentPage.table.AddRow();
                    }
                    else
                    {
                        // all maps weren't complete yet, and the heart side was never accessed: hide the heart side for now.
                        continue;
                    }
                }

                if (showOnlyDiscovered && item.TotalTimePlayed <= 0)
                {
                    // skip the map, because it was not discovered yet.
                    // since it wasn't discovered, we can already say all maps weren't done though.
                    allMapsDone         = false;
                    allLevelsDone       = false;
                    allSpeedBerriesDone = false;
                    continue;
                }

                string strawberryText = null;
                if (areaData.Mode[0].TotalStrawberries > 0 || item.TotalStrawberries > 0)
                {
                    strawberryText = item.TotalStrawberries.ToString();
                    if (item.Modes[0].Completed)
                    {
                        strawberryText = strawberryText + "/" + areaData.Mode[0].TotalStrawberries;
                    }
                }
                else
                {
                    strawberryText = "-";
                }

                Row row = currentPage.table.AddRow()
                          .Add(new TextCell(Dialog.Clean(areaData.Name), new Vector2(1f, 0.5f), 0.6f, currentPage.TextColor));

                if (displayIcons)
                {
                    row.Add(null).Add(new IconCellFromGui(GFX.Gui.Has(areaData.Icon) ? areaData.Icon : "areas/null", 60f, 50f));
                }

                row.Add(null)
                .Add(new IconCell(item.Modes[0].HeartGem ? heartTexture : "dot"))
                .Add(new TextCell(strawberryText, currentPage.TextJustify, 0.5f, currentPage.TextColor));

                if (item.TotalTimePlayed > 0)
                {
                    row.Add(new TextCell(Dialog.Deaths(item.Modes[0].Deaths), currentPage.TextJustify, 0.5f, currentPage.TextColor));
                }
                else
                {
                    row.Add(new IconCell("dot"));
                }

                AreaStats stats = SaveData.Instance.GetAreaStatsFor(areaData.ToKey());
                if (CollabMapDataProcessor.SilverBerries.TryGetValue(areaData.GetLevelSet(), out Dictionary <string, EntityID> levelSetBerries) &&
                    levelSetBerries.TryGetValue(areaData.GetSID(), out EntityID berryID) &&
                    stats.Modes[0].Strawberries.Contains(berryID))
                {
                    // silver berry was obtained!
                    row.Add(new IconCell("CollabUtils2/silver_strawberry"));
                }
                else if (stats.Modes[0].Strawberries.Any(berry => areaData.Mode[0].MapData.Goldenberries.Any(golden => golden.ID == berry.ID && golden.Level.Name == berry.Level)))
                {
                    // golden berry was obtained!
                    row.Add(new IconCell("CollabUtils2/golden_strawberry"));
                }
                else if (item.Modes[0].SingleRunCompleted)
                {
                    row.Add(new TextCell(Dialog.Deaths(item.Modes[0].BestDeaths), currentPage.TextJustify, 0.5f, currentPage.TextColor));
                    sumOfBestDeaths += item.Modes[0].BestDeaths;
                }
                else
                {
                    // the player didn't ever do a single run.
                    row.Add(new IconCell("dot"));
                    allLevelsDone = false;
                }

                if (OuiJournalCollabProgressDashCountMod.IsDashCountEnabled())
                {
                    if ((OuiJournalCollabProgressDashCountMod.DisplaysTotalDashes() && item.TotalTimePlayed > 0) || item.Modes[0].SingleRunCompleted)
                    {
                        row.Add(new TextCell(Dialog.Deaths(OuiJournalCollabProgressDashCountMod.GetLevelDashesForJournalProgress(item)),
                                             currentPage.TextJustify, 0.5f, currentPage.TextColor));
                        sumOfBestDashes += OuiJournalCollabProgressDashCountMod.GetLevelDashesForJournalProgress(item);
                    }
                    else
                    {
                        row.Add(new IconCell("dot"));
                    }
                }

                if (item.TotalTimePlayed > 0)
                {
                    row.Add(new TextCell(Dialog.Time(item.TotalTimePlayed), currentPage.TextJustify, 0.5f, currentPage.TextColor));
                }
                else
                {
                    row.Add(new IconCell("dot"));
                }

                if (displaySpeedBerryColumn)
                {
                    if (CollabMapDataProcessor.SpeedBerries.TryGetValue(item.GetSID(), out CollabMapDataProcessor.SpeedBerryInfo speedBerryInfo) &&
                        CollabModule.Instance.SaveData.SpeedBerryPBs.TryGetValue(item.GetSID(), out long speedBerryPB))
                    {
                        row.Add(new TextCell(Dialog.Time(speedBerryPB), currentPage.TextJustify, 0.5f, getRankColor(speedBerryInfo, speedBerryPB)));
                        row.Add(new IconCell(getRankIcon(speedBerryInfo, speedBerryPB)));
                        sumOfBestTimes += speedBerryPB;
                    }
                    else
                    {
                        row.Add(new IconCell("dot")).Add(null);
                        allSpeedBerriesDone = false;
                    }
                }
                else
                {
                    if (item.Modes[0].BestTime > 0f)
                    {
                        row.Add(new TextCell(Dialog.Time(item.Modes[0].BestTime), currentPage.TextJustify, 0.5f, currentPage.TextColor)).Add(null);
                        sumOfBestTimes += item.Modes[0].BestTime;
                    }
                    else
                    {
                        row.Add(new IconCell("dot")).Add(null);
                        allSpeedBerriesDone = false;
                    }
                }

                totalStrawberries += item.TotalStrawberries;
                totalDeaths       += item.Modes[0].Deaths;
                totalTime         += item.TotalTimePlayed;

                if (!item.Modes[0].HeartGem)
                {
                    allMapsDone = false;
                }

                rowCount++;
                if (rowCount >= mapsPerPage)
                {
                    // split the next zones into another page.
                    rowCount    = 0;
                    currentPage = new OuiJournalCollabProgressInLobby(journal, levelSet, displayIcons);
                    pages.Add(currentPage);
                }
            }

            if (currentPage.table.Rows > 1)
            {
                currentPage.table.AddRow();
                Row totalsRow = currentPage.table.AddRow()
                                .Add(new TextCell(Dialog.Clean("journal_totals"), new Vector2(1f, 0.5f), 0.7f, currentPage.TextColor)).Add(null);

                if (displayIcons)
                {
                    totalsRow.Add(null).Add(null);
                }

                totalsRow.Add(null)
                .Add(new TextCell(totalStrawberries.ToString(), currentPage.TextJustify, 0.6f, currentPage.TextColor))
                .Add(new TextCell(Dialog.Deaths(totalDeaths), currentPage.TextJustify, 0.6f, currentPage.TextColor))
                .Add(new TextCell(allLevelsDone ? Dialog.Deaths(sumOfBestDeaths) : "-", currentPage.TextJustify, 0.6f, currentPage.TextColor));

                if (OuiJournalCollabProgressDashCountMod.IsDashCountEnabled())
                {
                    totalsRow.Add(new TextCell(OuiJournalCollabProgressDashCountMod.DisplaysTotalDashes() || allLevelsDone ? Dialog.Deaths(sumOfBestDashes) : "-",
                                               currentPage.TextJustify, 0.6f, currentPage.TextColor));
                }

                totalsRow
                .Add(new TextCell(Dialog.Time(totalTime), currentPage.TextJustify, 0.6f, currentPage.TextColor))
                .Add(new TextCell(allSpeedBerriesDone ? Dialog.Time(sumOfBestTimes) : "-", currentPage.TextJustify, 0.6f, currentPage.TextColor)).Add(null);

                for (int l = 1; l < SaveData.Instance.UnlockedModes; l++)
                {
                    totalsRow.Add(null);
                }
                totalsRow.Add(new TextCell(Dialog.Time(SaveData.Instance.Time), currentPage.TextJustify, 0.6f, currentPage.TextColor));
                currentPage.table.AddRow();
            }

            return(pages);
        }
        private static void onOuiFileSelectSlotShow(On.Celeste.OuiFileSelectSlot.orig_Show orig, OuiFileSelectSlot self)
        {
            // If we are currently in a collab map, display the lobby level set stats instead.
            AreaKey?savedLastArea = null;
            string  collab        = collabNames.FirstOrDefault(collabName => self.SaveData?.LevelSet != null && self.SaveData.LevelSet.StartsWith($"{collabName}/") && self.SaveData.LevelSet != $"{collabName}/0-Lobbies");

            if (collab != null)
            {
                AreaData firstMapFromCollab = AreaData.Areas.FirstOrDefault(area => area.GetLevelSet() == $"{collab}/0-Lobbies");
                if (firstMapFromCollab != null)
                {
                    savedLastArea = self.SaveData.LastArea_Safe;
                    self.SaveData.LastArea_Safe = firstMapFromCollab.ToKey();
                    self.Strawberries.CanWiggle = false; // prevent the strawberry collect sound from playing.
                }
            }

            orig(self);

            string collab2 = collabNames.FirstOrDefault(collabName => self.SaveData?.LevelSet == $"{collabName}/0-Lobbies");

            if (collab2 != null)
            {
                // recompute the stats for the collab.
                int totalStrawberries                    = 0;
                int totalGoldenStrawberries              = 0;
                int totalHeartGems                       = 0;
                int totalCassettes                       = 0;
                int maxStrawberryCount                   = 0;
                int maxGoldenStrawberryCount             = 0;
                int maxStrawberryCountIncludingUntracked = 0;
                int maxCassettes     = 0;
                int maxCrystalHearts = 0;
                int maxCrystalHeartsExcludingCSides = 0;

                // aggregate all stats for the collab level sets.
                foreach (LevelSetStats stats in self.SaveData.LevelSets)
                {
                    if (stats.Name.StartsWith($"{collab2}/"))
                    {
                        totalStrawberries                    += stats.TotalStrawberries;
                        totalGoldenStrawberries              += stats.TotalGoldenStrawberries;
                        totalHeartGems                       += countTotalHeartGemsForMapsThatHaveHearts(stats);
                        totalCassettes                       += stats.TotalCassettes;
                        maxStrawberryCount                   += stats.MaxStrawberries;
                        maxGoldenStrawberryCount             += stats.MaxGoldenStrawberries;
                        maxStrawberryCountIncludingUntracked += stats.MaxStrawberriesIncludingUntracked;
                        maxCassettes     += stats.MaxCassettes;
                        maxCrystalHearts += stats.MaxHeartGems;
                        maxCrystalHeartsExcludingCSides += stats.MaxHeartGemsExcludingCSides;
                    }
                }

                DynData <OuiFileSelectSlot> slotData = new DynData <OuiFileSelectSlot>(self);
                slotData["totalGoldenStrawberries"]              = totalGoldenStrawberries;
                slotData["totalHeartGems"]                       = totalHeartGems;
                slotData["totalCassettes"]                       = totalCassettes;
                slotData["maxStrawberryCount"]                   = maxStrawberryCount;
                slotData["maxGoldenStrawberryCount"]             = maxGoldenStrawberryCount;
                slotData["maxStrawberryCountIncludingUntracked"] = maxStrawberryCountIncludingUntracked;
                slotData["maxCassettes"]     = maxCassettes;
                slotData["maxCrystalHearts"] = maxCrystalHearts;
                slotData["maxCrystalHeartsExcludingCSides"] = maxCrystalHeartsExcludingCSides;
                slotData["summitStamp"]   = false;
                slotData["farewellStamp"] = false;

                self.Strawberries.Amount = totalStrawberries;
                self.Strawberries.OutOf  = maxStrawberryCount;
            }

            // figure out if some hearts are customized, and store it in DynData so that a IL hook can access it later.
            SaveData oldInstance = SaveData.Instance;

            SaveData.Instance = self.SaveData;
            List <string> customJournalHearts = new List <string>();

            if (self.SaveData != null)
            {
                foreach (AreaStats item in self.SaveData.Areas_Safe)
                {
                    if (item.ID_Safe > self.SaveData.UnlockedAreas_Safe)
                    {
                        break;
                    }
                    if (!AreaData.Areas[item.ID_Safe].Interlude_Safe && AreaData.Areas[item.ID_Safe].CanFullClear)
                    {
                        string lobbyLevelSetName = GetLobbyLevelSet(item.GetSID());
                        if (lobbyLevelSetName != null && MTN.Journal.Has("CollabUtils2Hearts/" + lobbyLevelSetName))
                        {
                            customJournalHearts.Add("CollabUtils2Hearts/" + lobbyLevelSetName);
                        }
                        else
                        {
                            customJournalHearts.Add(null);
                        }
                    }
                }
            }
            new DynData <OuiFileSelectSlot>(self)["collabutils2_customhearts"] = customJournalHearts;
            SaveData.Instance = oldInstance;

            // Restore the last area if it was replaced at the beginning of this method.
            if (savedLastArea != null)
            {
                self.SaveData.LastArea_Safe = savedLastArea.Value;
            }
        }
Beispiel #17
0
        public OuiJournalCollabProgressInOverworld(OuiJournal journal)
            : base(journal)
        {
            bool displaySpeedBerryColumn = shouldDisplaySpeedBerryColumn();

            PageTexture = "page";
            table       = new Table()
                          .AddColumn(new TextCell(Dialog.Clean("journal_progress"), new Vector2(0f, 0.5f), 1f, Color.Black * 0.7f, 420f))
                          .AddColumn(new EmptyCell(20f))
                          .AddColumn(new EmptyCell(64f))
                          .AddColumn(new IconCell("strawberry", 150f))
                          .AddColumn(new IconCell("skullblue", 100f))
                          .AddColumn(new IconCell("CollabUtils2MinDeaths/SpringCollab2020/1-Beginner", 100f));

            if (OuiJournalCollabProgressDashCountMod.IsDashCountEnabled())
            {
                table.AddColumn(new IconCell("max480/DashCountMod/dashes", 80f));
            }

            table
            .AddColumn(new IconCell("time", 220f))
            .AddColumn(new IconCell("CollabUtils2/speed_berry_pbs_heading", 220f))
            .AddColumn(new EmptyCell(30f));

            int  totalStrawberries = 0;
            int  totalDeaths       = 0;
            int  sumOfBestDeaths   = 0;
            int  sumOfBestDashes   = 0;
            long totalTime         = 0;
            long sumOfBestTimes    = 0;

            bool allLevelsDone               = true;
            bool allSpeedBerriesDone         = true;
            bool allMapsCompletedInSingleRun = true;

            foreach (AreaStats item in SaveData.Instance.Areas_Safe)
            {
                AreaData areaData = AreaData.Get(item.ID_Safe);
                if (areaData.GetLevelSet() == SaveData.Instance.LevelSet)
                {
                    string        lobbyMapLevelSetName = LobbyHelper.GetLobbyLevelSet(areaData.GetSID());
                    LevelSetStats lobbyMapLevelSet     = null;
                    if (lobbyMapLevelSetName != null)
                    {
                        lobbyMapLevelSet = SaveData.Instance.GetLevelSetStatsFor(lobbyMapLevelSetName);
                    }

                    int  lobbyStrawberries                = item.TotalStrawberries;
                    int  lobbyTotalStrawberries           = areaData.Mode[0].TotalStrawberries;
                    int  lobbyDeaths                      = item.Modes[0].Deaths;
                    int  lobbySumOfBestDeaths             = 0;
                    int  lobbySumOfBestDashes             = OuiJournalCollabProgressDashCountMod.DisplaysTotalDashes() ? OuiJournalCollabProgressDashCountMod.GetLevelDashesForJournalProgress(item) : 0;
                    long lobbyTotalTime                   = item.TotalTimePlayed;
                    long lobbySumOfBestTimes              = 0;
                    bool lobbyLevelsDone                  = true;
                    int  lobbySpeedBerryLevel             = 1;
                    bool lobbySilverBerriesObtained       = true;
                    bool lobbyAllMapsCompletedInSingleRun = true;

                    foreach (AreaStats lobbyMap in lobbyMapLevelSet?.Areas ?? new List <AreaStats>())
                    {
                        AreaData lobbyAreaData = AreaData.Get(lobbyMap.ID_Safe);
                        lobbyStrawberries                += lobbyMap.TotalStrawberries;
                        lobbyTotalStrawberries           += lobbyAreaData.Mode[0].TotalStrawberries;
                        lobbyDeaths                      += lobbyMap.Modes[0].Deaths;
                        lobbyTotalTime                   += lobbyMap.TotalTimePlayed;
                        lobbyAllMapsCompletedInSingleRun &= lobbyMap.Modes[0].SingleRunCompleted;

                        if (displaySpeedBerryColumn)
                        {
                            if (CollabMapDataProcessor.SpeedBerries.TryGetValue(lobbyMap.GetSID(), out CollabMapDataProcessor.SpeedBerryInfo mapSpeedBerryInfo) &&
                                CollabModule.Instance.SaveData.SpeedBerryPBs.TryGetValue(lobbyMap.GetSID(), out long mapSpeedBerryPB))
                            {
                                lobbySpeedBerryLevel = Math.Max(getRankLevel(mapSpeedBerryInfo, mapSpeedBerryPB), lobbySpeedBerryLevel);
                                lobbySumOfBestTimes += mapSpeedBerryPB;
                            }
                            else
                            {
                                lobbySpeedBerryLevel = 4;
                            }
                        }
                        else
                        {
                            if (lobbyMap.Modes[0].BestTime > 0f)
                            {
                                lobbySumOfBestTimes += lobbyMap.Modes[0].BestTime;
                            }
                            else
                            {
                                lobbySpeedBerryLevel = 4;
                            }
                        }

                        bool goldenBerryNotObtained = !lobbyMap.Modes[0].Strawberries.Any(berry => lobbyAreaData.Mode[0].MapData.Goldenberries.Any(golden => golden.ID == berry.ID && golden.Level.Name == berry.Level));
                        bool silverBerryNotObtained = !CollabMapDataProcessor.SilverBerries.TryGetValue(lobbyMap.GetLevelSet(), out Dictionary <string, EntityID> levelSetBerries) ||
                                                      !levelSetBerries.TryGetValue(lobbyMap.GetSID(), out EntityID berryID) ||
                                                      !lobbyMap.Modes[0].Strawberries.Contains(berryID);

                        if (goldenBerryNotObtained && silverBerryNotObtained)
                        {
                            lobbySilverBerriesObtained = false;
                            lobbySumOfBestDeaths      += lobbyMap.Modes[0].BestDeaths;
                        }

                        lobbySumOfBestDashes += OuiJournalCollabProgressDashCountMod.GetLevelDashesForJournalProgress(lobbyMap);

                        if (!lobbyMap.Modes[0].HeartGem)
                        {
                            lobbyLevelsDone = false;
                        }
                    }

                    string strawberryText = null;
                    if (lobbyStrawberries > 0 || lobbyTotalStrawberries > 0)
                    {
                        strawberryText = lobbyStrawberries.ToString();
                        if (lobbyLevelsDone)
                        {
                            strawberryText = strawberryText + "/" + lobbyTotalStrawberries;
                        }
                    }
                    else
                    {
                        strawberryText = "-";
                    }

                    string heartTexturePath = lobbyMapLevelSetName ?? areaData.GetSID();
                    string heartTexture     = MTN.Journal.Has("CollabUtils2Hearts/" + heartTexturePath) ? "CollabUtils2Hearts/" + heartTexturePath : "heartgem0";

                    string areaName = Dialog.Clean(areaData.Name);
                    if (Dialog.Has(areaData.Name + "_journal"))
                    {
                        areaName = Dialog.Clean(areaData.Name + "_journal");
                    }

                    Row row = table.AddRow()
                              .Add(new TextCell(areaName, new Vector2(1f, 0.5f), 0.6f, TextColor))
                              .Add(null)
                              .Add(new IconCell(item.Modes[0].HeartGem ? heartTexture : "dot"))
                              .Add(new TextCell(strawberryText, TextJustify, 0.5f, TextColor));

                    if (lobbyTotalTime > 0)
                    {
                        row.Add(new TextCell(Dialog.Deaths(lobbyDeaths), TextJustify, 0.5f, TextColor));
                    }
                    else
                    {
                        row.Add(new IconCell("dot"));
                    }

                    if (lobbyLevelsDone)
                    {
                        AreaStats stats = SaveData.Instance.GetAreaStatsFor(areaData.ToKey());
                        if (lobbyMapLevelSet == null)
                        {
                            row.Add(new TextCell(Dialog.Deaths(item.Modes[0].BestDeaths), TextJustify, 0.5f, TextColor));
                            sumOfBestDeaths += item.Modes[0].BestDeaths;
                        }
                        else if (lobbySilverBerriesObtained)
                        {
                            row.Add(new IconCell("CollabUtils2/golden_strawberry"));
                        }
                        else if (lobbyAllMapsCompletedInSingleRun)
                        {
                            row.Add(new TextCell(Dialog.Deaths(lobbySumOfBestDeaths), TextJustify, 0.5f, TextColor));
                        }
                        else
                        {
                            row.Add(new IconCell("dot"));
                        }
                    }
                    else
                    {
                        row.Add(new IconCell("dot"));
                        allLevelsDone = false;
                    }


                    if (OuiJournalCollabProgressDashCountMod.IsDashCountEnabled())
                    {
                        if (lobbyMapLevelSet == null)
                        {
                            if ((OuiJournalCollabProgressDashCountMod.DisplaysTotalDashes() && item.TotalTimePlayed > 0) || item.Modes[0].SingleRunCompleted)
                            {
                                row.Add(new TextCell(Dialog.Deaths(OuiJournalCollabProgressDashCountMod.GetLevelDashesForJournalProgress(item)),
                                                     TextJustify, 0.5f, TextColor));
                                sumOfBestDashes += OuiJournalCollabProgressDashCountMod.GetLevelDashesForJournalProgress(item);
                            }
                            else
                            {
                                row.Add(new IconCell("dot"));
                            }
                        }
                        else if ((OuiJournalCollabProgressDashCountMod.DisplaysTotalDashes() && item.TotalTimePlayed > 0) || lobbyAllMapsCompletedInSingleRun)
                        {
                            row.Add(new TextCell(Dialog.Deaths(lobbySumOfBestDashes), TextJustify, 0.5f, TextColor));
                        }
                        else
                        {
                            row.Add(new IconCell("dot"));
                        }
                    }

                    if (lobbyTotalTime > 0)
                    {
                        row.Add(new TextCell(Dialog.Time(lobbyTotalTime), TextJustify, 0.5f, TextColor));
                    }
                    else
                    {
                        row.Add(new IconCell("dot"));
                    }

                    if (lobbyMapLevelSet == null)
                    {
                        row.Add(new TextCell("-", TextJustify, 0.5f, TextColor)).Add(null);
                    }
                    else if (lobbySpeedBerryLevel < 4)
                    {
                        if (displaySpeedBerryColumn)
                        {
                            row.Add(new TextCell(Dialog.Time(lobbySumOfBestTimes), TextJustify, 0.5f, getRankColor(lobbySpeedBerryLevel)));
                            row.Add(new IconCell(getRankIcon(lobbySpeedBerryLevel)));
                            sumOfBestTimes += lobbySumOfBestTimes;
                        }
                        else
                        {
                            row.Add(new TextCell(Dialog.Time(lobbySumOfBestTimes), TextJustify, 0.5f, TextColor)).Add(null);
                            sumOfBestTimes += lobbySumOfBestTimes;
                        }
                    }
                    else
                    {
                        row.Add(new IconCell("dot")).Add(null);
                        allSpeedBerriesDone = false;
                    }

                    totalStrawberries           += lobbyStrawberries;
                    totalDeaths                 += lobbyDeaths;
                    sumOfBestDeaths             += lobbySumOfBestDeaths;
                    sumOfBestDashes             += lobbySumOfBestDashes;
                    totalTime                   += lobbyTotalTime;
                    allMapsCompletedInSingleRun &= lobbyAllMapsCompletedInSingleRun;

                    if (!lobbyLevelsDone)
                    {
                        allLevelsDone = false;
                    }
                }
            }

            table.AddRow();
            Row totalsRow = table.AddRow()
                            .Add(new TextCell(Dialog.Clean("journal_totals"), new Vector2(1f, 0.5f), 0.7f, TextColor)).Add(null)
                            .Add(null)
                            .Add(new TextCell(totalStrawberries.ToString(), TextJustify, 0.6f, TextColor))
                            .Add(new TextCell(Dialog.Deaths(totalDeaths), TextJustify, 0.6f, TextColor))
                            .Add(new TextCell(allLevelsDone && allMapsCompletedInSingleRun ? Dialog.Deaths(sumOfBestDeaths) : "-", TextJustify, 0.6f, TextColor));

            if (OuiJournalCollabProgressDashCountMod.IsDashCountEnabled())
            {
                totalsRow.Add(new TextCell(OuiJournalCollabProgressDashCountMod.DisplaysTotalDashes() || (allLevelsDone && allMapsCompletedInSingleRun) ?
                                           Dialog.Deaths(sumOfBestDashes) : "-", TextJustify, 0.6f, TextColor));
            }

            totalsRow
            .Add(new TextCell(Dialog.Time(totalTime), TextJustify, 0.6f, TextColor))
            .Add(new TextCell(allSpeedBerriesDone ? Dialog.Time(sumOfBestTimes) : "-", TextJustify, 0.6f, TextColor)).Add(null);

            for (int l = 1; l < SaveData.Instance.UnlockedModes; l++)
            {
                totalsRow.Add(null);
            }
            totalsRow.Add(new TextCell(Dialog.Time(SaveData.Instance.Time), TextJustify, 0.6f, TextColor));
            table.AddRow();
        }
Beispiel #18
0
        public static new void Load()
        {
            orig_Load();

            foreach (AreaData area in Areas)
            {
                area.SetSID("Celeste/" + area.Mode[0].Path);
            }

            // Separate array as we sort it afterwards.
            List <AreaData> modAreas = new List <AreaData>();

            foreach (ModAsset asset in Everest.Content.ListMaps)
            {
                string  path = asset.PathMapped.Substring(5);
                MapMeta meta = asset.GetMeta <MapMeta>();

                AreaData area = new AreaData();

                // Default values.

                area.SetSID(path);

                area.Name = path;
                area.Icon = "areas/" + path.ToLowerInvariant();
                if (!GFX.Gui.Has(area.Icon))
                {
                    area.Icon = "areas/null";
                }

                area.TitleBaseColor   = Calc.HexToColor("6c7c81");
                area.TitleAccentColor = Calc.HexToColor("2f344b");
                area.TitleTextColor   = Color.White;

                area.IntroType = Player.IntroTypes.WakeUp;

                area.Dreaming   = false;
                area.ColorGrade = null;

                area.Mode = new ModeProperties[] {
                    new ModeProperties {
                        Path       = asset.PathMapped.Substring(5),
                        Inventory  = PlayerInventory.Default,
                        AudioState = new AudioState(Sfxs.music_city, Sfxs.env_amb_00_main)
                    }
                };

                area.Wipe = (Scene scene, bool wipeIn, Action onComplete)
                            => new AngledWipe(scene, wipeIn, onComplete);

                area.DarknessAlpha = 0.05f;
                area.BloomBase     = 0f;
                area.BloomStrength = 1f;

                area.Jumpthru = "wood";

                area.CassseteNoteColor = Calc.HexToColor("33a9ee");
                area.CassetteSong      = Sfxs.cas_01_forsaken_city;

                // Custom values.
                if (meta != null)
                {
                    if (!string.IsNullOrEmpty(meta.Name))
                    {
                        area.Name = meta.Name;
                    }

                    if (!string.IsNullOrEmpty(meta.SID))
                    {
                        area.SetSID(meta.SID);
                    }

                    if (!string.IsNullOrEmpty(meta.Icon) && GFX.Gui.Has(meta.Icon))
                    {
                        area.Icon = meta.Icon;
                    }

                    area.Interlude = meta.Interlude;
                    if (!string.IsNullOrEmpty(meta.CompleteScreenName))
                    {
                        area.CompleteScreenName = meta.CompleteScreenName;
                    }

                    area.CassetteCheckpointIndex = meta.CassetteCheckpointIndex;

                    if (!string.IsNullOrEmpty(meta.TitleBaseColor))
                    {
                        area.TitleBaseColor = Calc.HexToColor(meta.TitleBaseColor);
                    }
                    if (!string.IsNullOrEmpty(meta.TitleAccentColor))
                    {
                        area.TitleAccentColor = Calc.HexToColor(meta.TitleAccentColor);
                    }
                    if (!string.IsNullOrEmpty(meta.TitleTextColor))
                    {
                        area.TitleTextColor = Calc.HexToColor(meta.TitleTextColor);
                    }

                    area.IntroType = meta.IntroType;

                    area.Dreaming = meta.Dreaming;
                    if (!string.IsNullOrEmpty(meta.ColorGrade))
                    {
                        area.ColorGrade = meta.ColorGrade;
                    }

                    area.Mode = MapMeta.Convert(meta.Modes) ?? area.Mode;

                    if (!string.IsNullOrEmpty(meta.Wipe))
                    {
                        Type            type = Assembly.GetEntryAssembly().GetType(meta.Wipe);
                        ConstructorInfo ctor = type?.GetConstructor(new Type[] { typeof(Scene), typeof(bool), typeof(Action) });
                        if (type != null && ctor != null)
                        {
                            area.Wipe = (scene, wipeIn, onComplete) => ctor.Invoke(new object[] { scene, wipeIn, onComplete });
                        }
                    }

                    area.DarknessAlpha = meta.DarknessAlpha;
                    area.BloomBase     = meta.BloomBase;
                    area.BloomStrength = meta.BloomStrength;

                    if (!string.IsNullOrEmpty(meta.Jumpthru))
                    {
                        area.Jumpthru = meta.Jumpthru;
                    }

                    if (!string.IsNullOrEmpty(meta.CassetteNoteColor))
                    {
                        area.CassseteNoteColor = Calc.HexToColor(meta.CassetteNoteColor);
                    }
                    if (!string.IsNullOrEmpty(meta.CassetteSong))
                    {
                        area.CassetteSong = meta.CassetteSong;
                    }

                    area.MountainIdle   = meta.Mountain?.Idle?.Convert() ?? area.MountainIdle;
                    area.MountainSelect = meta.Mountain?.Select?.Convert() ?? area.MountainSelect;
                    area.MountainZoom   = meta.Mountain?.Zoom?.Convert() ?? area.MountainZoom;
                    area.MountainCursor = meta.Mountain?.Cursor?.ToVector3() ?? area.MountainCursor;
                    area.MountainState  = meta.Mountain?.State ?? area.MountainState;

                    area.SetCompleteScreenMeta(meta.CompleteScreen);
                }

                // Some of the game's code checks for [1] / [2] explicitly.
                // Let's just provide null modes to fill any gaps.
                if (area.Mode.Length < 3)
                {
                    ModeProperties[] larger = new ModeProperties[3];
                    for (int i = 0; i < area.Mode.Length; i++)
                    {
                        larger[i] = area.Mode[i];
                    }
                    area.Mode = larger;
                }

                // Celeste levelset always appears first.
                if (area.GetLevelSet() == "Celeste")
                {
                    Areas.Add(area);
                }
                else
                {
                    modAreas.Add(area);
                }
            }


            // Sort and merge modAreas into Areas. Makes for easier levelset handling.
            Areas.Sort(AreaComparison);
            modAreas.Sort(AreaComparison);
            Areas.AddRange(modAreas);

            // Find duplicates and remove the earlier copy.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area       = Areas[i];
                int      otherIndex = Areas.FindIndex(other => other.GetSID() == area.GetSID());
                if (otherIndex < i)
                {
                    Areas[otherIndex] = area;
                    Areas.RemoveAt(i);
                    i--;
                }
            }

            // Remove AreaDatas which are now a mode of another AreaData.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area       = Areas[i];
                int      otherIndex = Areas.FindIndex(other => other.Mode.Any(otherMode => otherMode?.Path == area.Mode[0].Path));
                if (otherIndex != -1 && otherIndex != i)
                {
                    Areas.RemoveAt(i);
                    i--;
                }
            }

            // Update old MapData areas and load any new areas.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area = Areas[i];
                area.ID = i;
                if (area.Mode[0].MapData != null)
                {
                    area.Mode[0].MapData.Area = area.ToKey();
                }
                else
                {
                    area.Mode[0].MapData = new MapData(area.ToKey());
                }
                if (area.Interlude)
                {
                    continue;
                }
                for (int mode = 1; mode < area.Mode.Length; mode++)
                {
                    if (area.Mode[mode] == null)
                    {
                        continue;
                    }
                    if (area.Mode[mode].MapData != null)
                    {
                        area.Mode[mode].MapData.Area = area.ToKey((AreaMode)mode);
                    }
                    else
                    {
                        area.Mode[mode].MapData = new MapData(area.ToKey((AreaMode)mode));
                    }
                }
            }
        }
        public static List <OuiJournalCollabProgressInLobby> GeneratePages(OuiJournal journal, string levelSet)
        {
            List <OuiJournalCollabProgressInLobby> pages = new List <OuiJournalCollabProgressInLobby>();
            int rowCount = 0;
            OuiJournalCollabProgressInLobby currentPage = new OuiJournalCollabProgressInLobby(journal, levelSet);

            pages.Add(currentPage);

            int  totalStrawberries = 0;
            int  totalDeaths       = 0;
            int  sumOfBestDeaths   = 0;
            long totalTime         = 0;
            long sumOfBestTimes    = 0;

            bool allMapsDone = true;

            bool allLevelsDone       = true;
            bool allSpeedBerriesDone = true;

            string heartTexture = MTN.Journal.Has("CollabUtils2Hearts/" + levelSet) ? "CollabUtils2Hearts/" + levelSet : "heartgem0";

            foreach (AreaStats item in SaveData.Instance.Areas_Safe)
            {
                AreaData areaData = AreaData.Get(item.ID_Safe);
                if (!areaData.Interlude_Safe)
                {
                    if (LobbyHelper.IsHeartSide(areaData.GetSID()))
                    {
                        if (allMapsDone || item.TotalTimePlayed > 0)
                        {
                            // add a separator, like the one between regular maps and Farewell
                            currentPage.table.AddRow();
                        }
                        else
                        {
                            // all maps weren't complete yet, and the heart side was never accessed: hide the heart side for now.
                            continue;
                        }
                    }

                    string strawberryText = null;
                    if (areaData.Mode[0].TotalStrawberries > 0 || item.TotalStrawberries > 0)
                    {
                        strawberryText = item.TotalStrawberries.ToString();
                        if (item.Modes[0].Completed)
                        {
                            strawberryText = strawberryText + "/" + areaData.Mode[0].TotalStrawberries;
                        }
                    }
                    else
                    {
                        strawberryText = "-";
                    }

                    Row row = currentPage.table.AddRow()
                              .Add(new TextCell(Dialog.Clean(areaData.Name), new Vector2(1f, 0.5f), 0.6f, currentPage.TextColor))
                              .Add(null)
                              .Add(new IconCell(item.Modes[0].HeartGem ? heartTexture : "dot"))
                              .Add(new TextCell(strawberryText, currentPage.TextJustify, 0.5f, currentPage.TextColor));

                    if (item.TotalTimePlayed > 0)
                    {
                        row.Add(new TextCell(Dialog.Deaths(item.Modes[0].Deaths), currentPage.TextJustify, 0.5f, currentPage.TextColor));
                    }
                    else
                    {
                        row.Add(new IconCell("dot"));
                    }


                    AreaStats stats = SaveData.Instance.GetAreaStatsFor(areaData.ToKey());
                    if (CollabMapDataProcessor.SilverBerries.TryGetValue(areaData.GetLevelSet(), out Dictionary <string, EntityID> levelSetBerries) &&
                        levelSetBerries.TryGetValue(areaData.GetSID(), out EntityID berryID) &&
                        stats.Modes[0].Strawberries.Contains(berryID))
                    {
                        // silver berry was obtained!
                        row.Add(new IconCell("CollabUtils2/silver_strawberry"));
                    }
                    else if (stats.Modes[0].Strawberries.Any(berry => areaData.Mode[0].MapData.Goldenberries.Any(golden => golden.ID == berry.ID && golden.Level.Name == berry.Level)))
                    {
                        // golden berry was obtained!
                        row.Add(new IconCell("CollabUtils2/golden_strawberry"));
                    }
                    else if (item.Modes[0].SingleRunCompleted)
                    {
                        row.Add(new TextCell(Dialog.Deaths(item.Modes[0].BestDeaths), currentPage.TextJustify, 0.5f, currentPage.TextColor));
                        sumOfBestDeaths += item.Modes[0].BestDeaths;
                    }
                    else
                    {
                        // the player didn't ever do a single run.
                        row.Add(new IconCell("dot"));
                        allLevelsDone = false;
                    }

                    if (item.TotalTimePlayed > 0)
                    {
                        row.Add(new TextCell(Dialog.Time(item.TotalTimePlayed), currentPage.TextJustify, 0.5f, currentPage.TextColor));
                    }
                    else
                    {
                        row.Add(new IconCell("dot"));
                    }

                    if (CollabModule.Instance.Settings.BestTimeToDisplayInJournal == CollabSettings.BestTimeInJournal.SpeedBerry)
                    {
                        if (CollabMapDataProcessor.SpeedBerries.TryGetValue(item.GetSID(), out CollabMapDataProcessor.SpeedBerryInfo speedBerryInfo) &&
                            CollabModule.Instance.SaveData.SpeedBerryPBs.TryGetValue(item.GetSID(), out long speedBerryPB))
                        {
                            row.Add(new TextCell(Dialog.Time(speedBerryPB), currentPage.TextJustify, 0.5f, getRankColor(speedBerryInfo, speedBerryPB)));
                            row.Add(new IconCell(getRankIcon(speedBerryInfo, speedBerryPB)));
                            sumOfBestTimes += speedBerryPB;
                        }
                        else
                        {
                            row.Add(new IconCell("dot")).Add(null);
                            allSpeedBerriesDone = false;
                        }
                    }
                    else
                    {
                        if (item.Modes[0].BestTime > 0f)
                        {
                            row.Add(new TextCell(Dialog.Time(item.Modes[0].BestTime), currentPage.TextJustify, 0.5f, currentPage.TextColor)).Add(null);
                            sumOfBestTimes += item.Modes[0].BestTime;
                        }
                        else
                        {
                            row.Add(new IconCell("dot")).Add(null);
                            allSpeedBerriesDone = false;
                        }
                    }

                    totalStrawberries += item.TotalStrawberries;
                    totalDeaths       += item.Modes[0].Deaths;
                    totalTime         += item.TotalTimePlayed;

                    if (!item.Modes[0].HeartGem)
                    {
                        allMapsDone = false;
                    }

                    rowCount++;
                    if (rowCount > 11)
                    {
                        // split the next zones into another page.
                        rowCount    = 0;
                        currentPage = new OuiJournalCollabProgressInLobby(journal, levelSet);
                        pages.Add(currentPage);
                    }
                }
            }

            if (currentPage.table.Rows > 1)
            {
                currentPage.table.AddRow();
                Row totalsRow = currentPage.table.AddRow()
                                .Add(new TextCell(Dialog.Clean("journal_totals"), new Vector2(1f, 0.5f), 0.7f, currentPage.TextColor)).Add(null)
                                .Add(null)
                                .Add(new TextCell(totalStrawberries.ToString(), currentPage.TextJustify, 0.6f, currentPage.TextColor))
                                .Add(new TextCell(Dialog.Deaths(totalDeaths), currentPage.TextJustify, 0.6f, currentPage.TextColor))
                                .Add(new TextCell(allLevelsDone ? Dialog.Deaths(sumOfBestDeaths) : "-", currentPage.TextJustify, 0.6f, currentPage.TextColor))
                                .Add(new TextCell(Dialog.Time(totalTime), currentPage.TextJustify, 0.6f, currentPage.TextColor))
                                .Add(new TextCell(allSpeedBerriesDone ? Dialog.Time(sumOfBestTimes) : "-", currentPage.TextJustify, 0.6f, currentPage.TextColor)).Add(null);

                for (int l = 1; l < SaveData.Instance.UnlockedModes; l++)
                {
                    totalsRow.Add(null);
                }
                totalsRow.Add(new TextCell(Dialog.Time(SaveData.Instance.Time), currentPage.TextJustify, 0.6f, currentPage.TextColor));
                currentPage.table.AddRow();
            }

            return(pages);
        }
Beispiel #20
0
        public override IEnumerator Enter(Oui from)
        {
            // Fix "out of bounds" level selection.
            GetMinMaxArea(out int areaOffs, out int areaMax);
            int areaUnclamp = area;

            area = Calc.Clamp(area, areaOffs, areaMax);

            Visible = true;
            EaseCamera();
            display = true;

            currentLevelSet = SaveData.Instance?.GetLevelSet() ?? "Celeste";

            journalEnabled = string.IsNullOrEmpty(currentLevelSet) || Celeste.PlayMode == Celeste.PlayModes.Debug || (SaveData.Instance?.CheatMode ?? false);
            for (int i = 0; i <= SaveData.Instance.UnlockedAreas && !journalEnabled; i++)
            {
                if (SaveData.Instance.Areas[i].Modes[0].TimePlayed > 0L && !AreaData.Get(i).Interlude)
                {
                    journalEnabled = true;
                }
            }

            OuiChapterSelectIcon unselected = null;

            if (from is OuiChapterPanel)
            {
                (unselected = icons[areaUnclamp]).Unselect();
                if (areaUnclamp != area)
                {
                    unselected.Hide();
                }
            }

            bool isVanilla = currentLevelSet == "Celeste";

            foreach (OuiChapterSelectIcon icon in icons)
            {
                AreaData area = AreaData.Get(icon.Area);
                if (area == null || area.GetLevelSet() != currentLevelSet)
                {
                    continue;
                }

                int index = area.ToKey().ID;
                if ((string.IsNullOrEmpty(currentLevelSet) || index <= Math.Max(1, SaveData.Instance.UnlockedAreas)) &&
                    icon != unselected)
                {
                    icon.Position = icon.HiddenPosition;
                    icon.Show();
                    icon.AssistModeUnlockable = false;
                }
                else if (SaveData.Instance.AssistMode && index == SaveData.Instance.UnlockedAreas + 1)
                {
                    icon.Position = icon.HiddenPosition;
                    icon.Show();
                    icon.AssistModeUnlockable = true;
                }

                if (isVanilla)
                {
                    yield return(0.01f);
                }
            }

            if (from is OuiChapterPanel)
            {
                yield return(0.25f);
            }
        }