Пример #1
0
        public override void Update(Scene scene)
        {
            AreaData area = -1 < Area && Area < (AreaData.Areas?.Count ?? 0) ? AreaData.Get(Area) : null;
            MapMeta  meta = area?.GetMeta();

            bool wasFreeCam = inFreeCameraDebugMode;

            if (meta?.Mountain?.ShowCore ?? false)
            {
                Area = 9;
                orig_Update(scene);
                Area = area.ID;
            }
            else
            {
                orig_Update(scene);
            }

            Overworld overworld = scene as Overworld;

            if (!wasFreeCam && inFreeCameraDebugMode && (
                    ((overworld.Current ?? overworld.Next) is patch_OuiFileNaming naming && naming.UseKeyboardInput) ||
                    ((overworld.Current ?? overworld.Next) is OuiModOptionString stringInput && stringInput.UseKeyboardInput)))
            {
                // we turned on free cam mode (by pressing Space) while on an text entry screen using keyboard input... we should turn it back off.
                inFreeCameraDebugMode = false;
            }
        }
Пример #2
0
        public override void Update()
        {
            lock (AssetReloadHelper.AreaReloadLock) {
                orig_Update();

                // if the mountain model is currently fading, use the one currently displayed, not the one currently selected, which is different if the fade isn't done yet.
                AreaData currentAreaData       = null;
                string   currentlyDisplayedSID = (Mountain?.Model as patch_MountainModel)?.PreviousSID;
                if (currentlyDisplayedSID != null)
                {
                    // use the settings of the currently displayed mountain
                    currentAreaData = patch_AreaData.Get(currentlyDisplayedSID);
                }
                else if (SaveData.Instance != null)
                {
                    // use the settings of the currently selected map
                    currentAreaData = AreaData.Get(SaveData.Instance.LastArea);
                }
                MapMetaMountain mountainMetadata = currentAreaData?.GetMeta()?.Mountain;

                Snow3D.Visible = mountainMetadata?.ShowSnow ?? true;

                if (string.IsNullOrEmpty(Audio.CurrentMusic))
                {
                    // don't change music if no music is currently playing
                    return;
                }

                if (SaveData.Instance != null && (IsCurrent <OuiChapterSelect>() || IsCurrent <OuiChapterPanel>() ||
                                                  IsCurrent <OuiMapList>() || IsCurrent <OuiMapSearch>() || IsCurrent <OuiJournal>()))
                {
                    string backgroundMusic    = mountainMetadata?.BackgroundMusic;
                    string backgroundAmbience = mountainMetadata?.BackgroundAmbience;
                    if (backgroundMusic != null || backgroundAmbience != null)
                    {
                        // current map has custom background music
                        Audio.SetMusic(backgroundMusic ?? "event:/music/menu/level_select");
                        Audio.SetAmbience(backgroundAmbience ?? "event:/env/amb/worldmap");
                        customizedChapterSelectMusic = true;
                    }
                    else
                    {
                        // current map has no custom background music
                        restoreNormalMusicIfCustomized();
                    }

                    foreach (KeyValuePair <string, float> musicParam in mountainMetadata?.BackgroundMusicParams ?? new Dictionary <string, float>())
                    {
                        Audio.SetMusicParam(musicParam.Key, musicParam.Value);
                    }
                }
                else
                {
                    // no save is loaded or we are not in chapter select
                    restoreNormalMusicIfCustomized();
                }
            }
        }
Пример #3
0
        public override bool IsStart(Overworld overworld, Overworld.StartMode start)
        {
            if (start == Overworld.StartMode.AreaComplete || start == Overworld.StartMode.AreaQuit)
            {
                AreaData area = AreaData.Get(SaveData.Instance.LastArea.ID);
                area = AreaDataExt.Get(area?.GetMeta()?.Parent) ?? area;
                if (area != null)
                {
                    SaveData.Instance.LastArea.ID = area.ID;
                }
            }

            return(orig_IsStart(overworld, start));
        }
Пример #4
0
        public override void Update(Scene scene)
        {
            AreaData area = -1 < Area && Area < (AreaData.Areas?.Count ?? 0) ? AreaData.Get(Area) : null;
            MapMeta  meta = area?.GetMeta();

            if (meta?.Mountain?.ShowCore ?? false)
            {
                Area = 9;
                orig_Update(scene);
                Area = area.ID;
            }
            else
            {
                orig_Update(scene);
            }
        }
Пример #5
0
        public override void Added(Scene scene)
        {
            orig_Added(scene);

            SaveData save = SaveData.Instance;

            for (int i = icons.Count - 1; i > -1; --i)
            {
                OuiChapterSelectIcon icon = icons[i];
                AreaData             area = AreaData.Get(icon.Area);

                if (!string.IsNullOrEmpty(area?.GetMeta()?.Parent))
                {
                    icons[i].Area = -1;
                    icons[i].Hide();
                    continue;
                }
            }
        }
Пример #6
0
        public override bool IsStart(Overworld overworld, Overworld.StartMode start)
        {
            if (SaveData.Instance != null && SaveData.Instance.LastArea.ID == AreaKey.None.ID)
            {
                SaveData.Instance.LastArea = AreaKey.Default;
                instantClose = true;
            }

            if (start == Overworld.StartMode.AreaComplete || start == Overworld.StartMode.AreaQuit)
            {
                AreaData area = AreaData.Get(SaveData.Instance.LastArea.ID);
                area = AreaDataExt.Get(area?.GetMeta()?.Parent) ?? area;
                if (area != null)
                {
                    SaveData.Instance.LastArea.ID = area.ID;
                }
            }

            bool isStart = orig_IsStart(overworld, start);

            if (isStart && option >= options.Count && options.Count == 1)
            {
                // we are coming back from a B/C-side and we didn't unlock B-sides. Force-add it.
                AddRemixButton();
            }
            if (isStart && option >= options.Count && options.Count == 2)
            {
                // we are coming back from a C-side we did not unlock. Force-add it.
                options.Add(new Option {
                    Label = Dialog.Clean("overworld_remix2"),
                    Icon  = GFX.Gui["menu/rmx2"],
                    ID    = "C"
                });
            }

            return(isStart);
        }
Пример #7
0
        public new void AfterInitialize()
        {
            // Vanilla / new saves don't have the LevelSets list.
            if (LevelSets == null)
            {
                LevelSets = new List <LevelSetStats>();
            }

            if (LevelSetRecycleBin == null)
            {
                LevelSetRecycleBin = new List <LevelSetStats>();
            }

            if (LevelSets.Count <= 1 && LevelSetRecycleBin.Count == 0 && !HasModdedSaveData)
            {
                // the save file doesn't have any mod save data (just created, overwritten by vanilla, or Everest just updated).
                // we want to carry mod save data that was backed up in the mod save file, if any.
                ModSaveData modSaveData = UserIO.Load <ModSaveData>(GetFilename(FileSlot) + "-modsavedata");
                if (modSaveData != null)
                {
                    modSaveData.CopyToCelesteSaveData(this);
                    Logger.Log(LogLevel.Warn, "SaveData", $"{LevelSets.Count} level set(s) were restored from mod backup for save slot {FileSlot}");
                }
            }

            HasModdedSaveData = true;

            if (Areas_Unsafe == null)
            {
                Areas_Unsafe = new List <AreaStats>();
            }

            // Add missing LevelSetStats.
            foreach (AreaData area in AreaData.Areas)
            {
                string set = area.GetLevelSet();
                if (!LevelSets.Exists(other => other.Name == set))
                {
                    LevelSetStats recycleBinLevelSet = LevelSetRecycleBin.FirstOrDefault(other => other.Name == set);
                    if (recycleBinLevelSet != null)
                    {
                        // the level set is actually in the recycle bin - restore it.
                        LevelSets.Add(recycleBinLevelSet);
                        LevelSetRecycleBin.Remove(recycleBinLevelSet);
                    }
                    else
                    {
                        // create a new LevelSetStats entry.
                        LevelSets.Add(new LevelSetStats {
                            Name          = set,
                            UnlockedAreas = set == "Celeste" ? UnlockedAreas_Unsafe : 0
                        });
                    }
                }
            }

            // Fill each LevelSetStats with its areas.
            for (int lsi = 0; lsi < LevelSets.Count; lsi++)
            {
                LevelSetStats set = LevelSets[lsi];
                set.SaveData = this;
                List <AreaStats> areas = set.Areas;
                if (set.Name == "Celeste")
                {
                    areas = Areas_Unsafe;
                }

                int offset = set.AreaOffset;
                if (offset == -1)
                {
                    // LevelSet gone - let's move it to the recycle bin.
                    LevelSetStats levelSetAlreadyInRecycleBin = LevelSetRecycleBin.FirstOrDefault(other => other.Name == set.Name);
                    if (levelSetAlreadyInRecycleBin != null)
                    {
                        // a level set with the same name already exists in the recycle bin - replace it.
                        LevelSetRecycleBin.Remove(levelSetAlreadyInRecycleBin);
                    }
                    LevelSetRecycleBin.Add(set);

                    // now, remove it to prevent any unwanted access.
                    LevelSets.RemoveAt(lsi);
                    lsi--;
                    continue;
                }

                // Refresh all stat IDs based on their SIDs, sort, fill and remove leftovers.
                // Temporarily use ID_Unsafe; later ID_Safe to ID_Unsafe to resync the SIDs.
                // This keeps the stats bound to their SIDs, not their indices, while removing non-existent areas.
                int countRoots = AreaData.Areas.Count(other => other.GetLevelSet() == set.Name && string.IsNullOrEmpty(other?.GetMeta()?.Parent));
                int countAll   = AreaData.Areas.Count(other => other.GetLevelSet() == set.Name);

                // Fix IDs
                for (int i = 0; i < areas.Count; i++)
                {
                    AreaData area = AreaDataExt.Get(areas[i]);
                    if (!string.IsNullOrEmpty(area?.GetMeta()?.Parent))
                    {
                        area = null;
                    }
                    ((patch_AreaStats)areas[i]).ID_Unsafe = area?.ID ?? int.MaxValue;
                }

                // Sort
                areas.Sort((a, b) => ((patch_AreaStats)a).ID_Unsafe - ((patch_AreaStats)b).ID_Unsafe);

                // Remove leftovers
                while (areas.Count > 0 && ((patch_AreaStats)areas[areas.Count - 1]).ID_Unsafe == int.MaxValue)
                {
                    areas.RemoveAt(areas.Count - 1);
                }

                // Fill gaps
                for (int i = 0; i < countRoots; i++)
                {
                    if (i >= areas.Count || ((patch_AreaStats)areas[i]).ID_Unsafe != offset + i)
                    {
                        areas.Insert(i, new AreaStats(offset + i));
                    }
                }

                // Duplicate parent stat refs into their respective children slots.
                for (int i = countRoots; i < countAll; i++)
                {
                    if (i >= areas.Count)
                    {
                        areas.Insert(i, areas[AreaDataExt.Get(AreaData.Get(offset + i).GetMeta().Parent).ID - offset]);
                    }
                }

                // Resync SIDs
                for (int i = 0; i < areas.Count; i++)
                {
                    ((patch_AreaStats)areas[i]).ID_Safe = ((patch_AreaStats)areas[i]).ID_Unsafe;
                }

                int lastCompleted = -1;
                for (int i = 0; i < countRoots; i++)
                {
                    if (areas[i].Modes[0].Completed)
                    {
                        lastCompleted = i;
                    }
                }

                if (set.Name == "Celeste")
                {
                    if (UnlockedAreas_Unsafe < lastCompleted + 1 && set.MaxArea >= lastCompleted + 1)
                    {
                        UnlockedAreas_Unsafe = lastCompleted + 1;
                    }
                    if (DebugMode)
                    {
                        UnlockedAreas_Unsafe = set.MaxArea;
                    }
                }
                else
                {
                    if (set.UnlockedAreas < lastCompleted + 1 && set.MaxArea >= lastCompleted + 1)
                    {
                        set.UnlockedAreas = lastCompleted + 1;
                    }
                    if (DebugMode)
                    {
                        set.UnlockedAreas = set.MaxArea;
                    }
                }

                foreach (AreaStats area in areas)
                {
                    area.CleanCheckpoints();
                }
            }

            // Assign SaveData for the level sets in the recycle bin to prevent crashes.
            foreach (LevelSetStats set in LevelSetRecycleBin)
            {
                set.SaveData = this;
            }

            // Order the levelsets to appear just as their areas appear in AreaData.Areas
            LevelSets.Sort((set1, set2) => set1.AreaOffset.CompareTo(set2.AreaOffset));

            // If there is no mod progress, carry over any progress from vanilla saves.
            if (LastArea_Safe.ID == 0)
            {
                LastArea_Safe = LastArea_Unsafe;
            }
            if (CurrentSession_Safe == null)
            {
                CurrentSession_Safe = CurrentSession_Unsafe;
            }

            // Trick unmodded instances of Celeste to thinking that we last selected prologue / played no level.
            LastArea_Unsafe       = AreaKey.Default;
            CurrentSession_Unsafe = null;

            // Fix areas with missing SID (f.e. deleted or renamed maps).
            if (AreaData.Get(LastArea) == null)
            {
                LastArea = AreaKey.Default;
            }

            // Fix out of bounds areas.
            if (LastArea.ID < 0 || LastArea.ID >= AreaData.Areas.Count)
            {
                LastArea = AreaKey.Default;
            }

            if (string.IsNullOrEmpty(TheoSisterName))
            {
                TheoSisterName = Dialog.Clean("THEO_SISTER_NAME", null);
                if (Name.IndexOf(TheoSisterName, StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    TheoSisterName = Dialog.Clean("THEO_SISTER_ALT_NAME", null);
                }
            }

            AssistModeChecks();

            if (Version != null)
            {
                Version v = new Version(Version);

                if (v < new Version(1, 2, 1, 1))
                {
                    for (int id = 0; id < Areas_Unsafe.Count; id++)
                    {
                        AreaStats area = Areas_Unsafe[id];
                        if (area == null)
                        {
                            continue;
                        }
                        for (int modei = 0; modei < area.Modes.Length; modei++)
                        {
                            AreaModeStats mode = area.Modes[modei];
                            if (mode == null)
                            {
                                continue;
                            }
                            if (mode.BestTime > 0L)
                            {
                                mode.SingleRunCompleted = true;
                            }
                            mode.BestTime          = 0L;
                            mode.BestFullClearTime = 0L;
                        }
                    }
                }
            }
        }
Пример #8
0
        public new void AfterInitialize()
        {
            // Vanilla / new saves don't have the LevelSets list.
            if (LevelSets == null)
            {
                LevelSets = new List <LevelSetStats>();
            }

            if (Areas_Unsafe == null)
            {
                Areas_Unsafe = new List <AreaStats>();
            }

            // Add missing LevelSetStats.
            foreach (AreaData area in AreaData.Areas)
            {
                string set = area.GetLevelSet();
                if (!LevelSets.Exists(other => other.Name == set))
                {
                    LevelSets.Add(new LevelSetStats {
                        Name          = set,
                        UnlockedAreas = set == "Celeste" ? UnlockedAreas_Unsafe : 0
                    });
                }
            }

            // Fill each LevelSetStats with its areas.
            for (int lsi = 0; lsi < LevelSets.Count; lsi++)
            {
                LevelSetStats set = LevelSets[lsi];
                set.SaveData = this;
                List <AreaStats> areas = set.Areas;
                if (set.Name == "Celeste")
                {
                    areas = Areas_Unsafe;
                }

                int offset = set.AreaOffset;
                if (offset == -1)
                {
                    // LevelSet gone - let's remove it to prevent any unwanted accesses.
                    // We previously kept the LevelSetStats around in case the levelset resurfaces later on, but as it turns out, this breaks some stuff.
                    LevelSets.RemoveAt(lsi);
                    lsi--;
                    continue;
                }

                // Refresh all stat IDs based on their SIDs, sort, fill and remove leftovers.
                // Temporarily use ID_Unsafe; later ID_Safe to ID_Unsafe to resync the SIDs.
                // This keeps the stats bound to their SIDs, not their indices, while removing non-existent areas.
                int countRoots = AreaData.Areas.Count(other => other.GetLevelSet() == set.Name && string.IsNullOrEmpty(other?.GetMeta()?.Parent));
                int countAll   = AreaData.Areas.Count(other => other.GetLevelSet() == set.Name);

                // Fix IDs
                for (int i = 0; i < areas.Count; i++)
                {
                    AreaData area = AreaDataExt.Get(areas[i]);
                    if (!string.IsNullOrEmpty(area?.GetMeta()?.Parent))
                    {
                        area = null;
                    }
                    ((patch_AreaStats)areas[i]).ID_Unsafe = area?.ID ?? int.MaxValue;
                }

                // Sort
                areas.Sort((a, b) => ((patch_AreaStats)a).ID_Unsafe - ((patch_AreaStats)b).ID_Unsafe);

                // Remove leftovers
                while (areas.Count > 0 && ((patch_AreaStats)areas[areas.Count - 1]).ID_Unsafe == int.MaxValue)
                {
                    areas.RemoveAt(areas.Count - 1);
                }

                // Fill gaps
                for (int i = 0; i < countRoots; i++)
                {
                    if (i >= areas.Count || ((patch_AreaStats)areas[i]).ID_Unsafe != offset + i)
                    {
                        areas.Insert(i, new AreaStats(offset + i));
                    }
                }

                // Duplicate parent stat refs into their respective children slots.
                for (int i = countRoots; i < countAll; i++)
                {
                    if (i >= areas.Count)
                    {
                        areas.Insert(i, areas[AreaDataExt.Get(AreaData.Get(offset + i).GetMeta().Parent).ID - offset]);
                    }
                }

                // Resync SIDs
                for (int i = 0; i < areas.Count; i++)
                {
                    ((patch_AreaStats)areas[i]).ID_Safe = ((patch_AreaStats)areas[i]).ID_Unsafe;
                }

                int lastCompleted = -1;
                for (int i = 0; i < countRoots; i++)
                {
                    if (areas[i].Modes[0].Completed)
                    {
                        lastCompleted = i;
                    }
                }

                if (set.Name == "Celeste")
                {
                    if (UnlockedAreas_Unsafe < lastCompleted + 1 && set.MaxArea >= lastCompleted + 1)
                    {
                        UnlockedAreas_Unsafe = lastCompleted + 1;
                    }
                    if (DebugMode)
                    {
                        UnlockedAreas_Unsafe = set.MaxArea;
                    }
                }
                else
                {
                    if (set.UnlockedAreas < lastCompleted + 1 && set.MaxArea >= lastCompleted + 1)
                    {
                        set.UnlockedAreas = lastCompleted + 1;
                    }
                    if (DebugMode)
                    {
                        set.UnlockedAreas = set.MaxArea;
                    }
                }

                foreach (AreaStats area in areas)
                {
                    area.CleanCheckpoints();
                }
            }

            // Order the levelsets to appear just as their areas appear in AreaData.Areas
            LevelSets.Sort((set1, set2) => set1.AreaOffset.CompareTo(set2.AreaOffset));

            // If there is no mod progress, carry over any progress from vanilla saves.
            if (LastArea_Safe.ID == 0)
            {
                LastArea_Safe = LastArea_Unsafe;
            }
            if (CurrentSession_Safe == null)
            {
                CurrentSession_Safe = CurrentSession_Unsafe;
            }

            // Trick unmodded instances of Celeste to thinking that we last selected prologue / played no level.
            LastArea_Unsafe       = AreaKey.Default;
            CurrentSession_Unsafe = null;

            // Fix areas with missing SID (f.e. deleted or renamed maps).
            if (AreaData.Get(LastArea) == null)
            {
                LastArea = AreaKey.Default;
            }

            // Fix out of bounds areas.
            if (LastArea.ID < 0 || LastArea.ID >= AreaData.Areas.Count)
            {
                LastArea = AreaKey.Default;
            }

            if (string.IsNullOrEmpty(TheoSisterName))
            {
                TheoSisterName = Dialog.Clean("THEO_SISTER_NAME", null);
                if (Name.IndexOf(TheoSisterName, StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    TheoSisterName = Dialog.Clean("THEO_SISTER_ALT_NAME", null);
                }
            }

            AssistModeChecks();

            if (Version != null)
            {
                Version v = new Version(Version);

                if (v < new Version(1, 2, 1, 1))
                {
                    for (int id = 0; id < Areas_Unsafe.Count; id++)
                    {
                        AreaStats area = Areas_Unsafe[id];
                        if (area == null)
                        {
                            continue;
                        }
                        for (int modei = 0; modei < area.Modes.Length; modei++)
                        {
                            AreaModeStats mode = area.Modes[modei];
                            if (mode == null)
                            {
                                continue;
                            }
                            if (mode.BestTime > 0L)
                            {
                                mode.SingleRunCompleted = true;
                            }
                            mode.BestTime          = 0L;
                            mode.BestFullClearTime = 0L;
                        }
                    }
                }
            }
        }
Пример #9
0
        public void ApplyTo(AreaData area)
        {
            if (!string.IsNullOrEmpty(Icon) && GFX.Gui.Has(Icon))
            {
                area.Icon = Icon;
            }

            if (Interlude != null)
            {
                area.Interlude = Interlude.Value;
            }

            if (CassetteCheckpointIndex != null)
            {
                area.CassetteCheckpointIndex = CassetteCheckpointIndex.Value;
            }

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

            if (IntroType != null)
            {
                area.IntroType = IntroType.Value;
            }

            if (Dreaming != null)
            {
                area.Dreaming = Dreaming.Value;
            }

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

            if (!string.IsNullOrEmpty(Wipe))
            {
                Type            type = Assembly.GetEntryAssembly().GetType(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 });
                }
            }

            if (DarknessAlpha != null)
            {
                area.DarknessAlpha = DarknessAlpha.Value;
            }
            if (BloomBase != null)
            {
                area.BloomBase = BloomBase.Value;
            }
            if (BloomStrength != null)
            {
                area.BloomStrength = BloomStrength.Value;
            }

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

            if (CoreMode != null)
            {
                area.CoreMode = CoreMode.Value;
            }

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

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

            ModeProperties[] modes = area.Mode;
            area.Mode = Convert(Modes) ?? modes;
            if (modes != null)
            {
                for (int i = 0; i < area.Mode.Length && i < modes.Length; i++)
                {
                    if (area.Mode[i] == null)
                    {
                        area.Mode[i] = modes[i];
                    }
                }
            }

            MapMeta meta = area.GetMeta();

            if (meta == null)
            {
                area.SetMeta(this);
            }
            else
            {
                if (!string.IsNullOrEmpty(Parent))
                {
                    meta.Parent = Parent;
                }

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

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

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

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

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

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

                if (OverrideASideMeta != null)
                {
                    meta.OverrideASideMeta = OverrideASideMeta;
                }

                if ((Modes?.Length ?? 0) != 0 && Modes.Any(mode => mode != null))
                {
                    meta.Modes = Modes;
                }

                if (Mountain != null)
                {
                    meta.Mountain = Mountain;
                }

                if (CompleteScreen != null)
                {
                    meta.CompleteScreen = CompleteScreen;
                }

                if (LoadingVignetteScreen != null)
                {
                    meta.LoadingVignetteScreen = LoadingVignetteScreen;
                }

                if (LoadingVignetteText != null)
                {
                    meta.LoadingVignetteText = LoadingVignetteText;
                }

                if (CassetteModifier != null)
                {
                    meta.CassetteModifier = CassetteModifier;
                }
            }
        }
Пример #10
0
        public void ctor(Session session, Vector2?startPosition = default(Vector2?))
        {
            if (CoreModule.Settings.LazyLoading)
            {
                MainThreadHelper.Do(() => VirtualContentExt.UnloadOverworld());
            }

            // Vanilla TileToIndex mappings.
            SurfaceIndex.TileToIndex = new Dictionary <char, int> {
                { '1', 3 },
                { '3', 4 },
                { '4', 7 },
                { '5', 8 },
                { '6', 8 },
                { '7', 8 },
                { '8', 8 },
                { '9', 13 },
                { 'a', 8 },
                { 'b', 23 },
                { 'c', 8 },
                { 'd', 8 },
                { 'e', 8 },
                { 'f', 8 },
                { 'g', 8 },
                { 'h', 33 },
                { 'i', 4 },
                { 'j', 8 },
                { 'k', 3 },
                { 'l', 25 },
                { 'm', 44 },
                { 'n', 40 },
                { 'o', 43 }
            };

            AreaData area = AreaData.Get(session);
            MapMeta  meta = area.GetMeta();
            string   path;

            path = meta?.BackgroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "BackgroundTiles.xml");
            }
            GFX.BGAutotiler = new Autotiler(path);

            path = meta?.ForegroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "ForegroundTiles.xml");
            }
            GFX.FGAutotiler = new Autotiler(path);

            path = meta?.AnimatedTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "AnimatedTiles.xml");
            }
            GFX.AnimatedTilesBank = new AnimatedTilesBank();
            XmlElement animatedData = Calc.LoadContentXML(path)["Data"];

            foreach (XmlElement el in animatedData)
            {
                if (el != null)
                {
                    GFX.AnimatedTilesBank.Add(
                        el.Attr("name"),
                        el.AttrFloat("delay", 0f),
                        el.AttrVector2("posX", "posY", Vector2.Zero),
                        el.AttrVector2("origX", "origY", Vector2.Zero),
                        GFX.Game.GetAtlasSubtextures(el.Attr("path"))
                        );
                }
            }

            GFX.SpriteBank = new SpriteBank(GFX.Game, Path.Combine("Graphics", "Sprites.xml"));

            path = meta?.Sprites;
            if (!string.IsNullOrEmpty(path))
            {
                SpriteBank bankOrig = GFX.SpriteBank;
                SpriteBank bankMod  = new SpriteBank(GFX.Game, path);

                foreach (KeyValuePair <string, SpriteData> kvpBank in bankMod.SpriteData)
                {
                    string     key      = kvpBank.Key;
                    SpriteData valueMod = kvpBank.Value;

                    if (bankOrig.SpriteData.TryGetValue(key, out SpriteData valueOrig))
                    {
                        IDictionary animsOrig = valueOrig.Sprite.GetAnimations();
                        IDictionary animsMod  = valueMod.Sprite.GetAnimations();

                        foreach (DictionaryEntry kvpAnim in animsMod)
                        {
                            animsOrig[kvpAnim.Key] = kvpAnim.Value;
                        }
                    }
                    else
                    {
                        bankOrig.SpriteData[key] = valueMod;
                    }
                }
            }

            path = meta?.Portraits;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "Portraits.xml");
            }
            GFX.PortraitsSpriteBank = new SpriteBank(GFX.Portraits, path);

            orig_ctor(session, startPosition);
        }
Пример #11
0
        [PatchMapDataLoader] // Manually manipulate the method via MonoModRules
        private void Load()
        {
            // reset those fields to prevent them from stacking up when reloading the map.
            DetectedStrawberries  = 0;
            DetectedHeartGem      = false;
            DetectedRemixNotes    = false;
            Goldenberries         = new List <EntityData>();
            DashlessGoldenberries = new List <EntityData>();
            DetectedCassette      = false;
            DetectedStrawberriesIncludingUntracked = 0;

            try {
                orig_Load();

                foreach (LevelData level in Levels)
                {
                    foreach (EntityData entity in level.Entities)
                    {
                        if (entity.Name == "memorialTextController") // aka "dashless golden"
                        {
                            DashlessGoldenberries.Add(entity);
                        }
                    }
                }

                AreaData       area       = AreaData.Get(Area);
                AreaData       parentArea = AreaDataExt.Get(area.GetMeta()?.Parent);
                ModeProperties parentMode = parentArea?.Mode?.ElementAtOrDefault((int)Area.Mode);
                if (parentMode != null)
                {
                    MapData parentMapData = parentMode.MapData;
                    if (parentMapData == null)
                    {
                        Mod.Logger.Log(LogLevel.Warn, "misc", $"Failed auto-assigning data from {Area} to its unloaded parent");
                        return;
                    }

                    parentMapData.Strawberries.AddRange(Strawberries);

                    // Recount everything berry-related for the parent map data, just like in orig_Load.
                    parentMode.TotalStrawberries        = 0;
                    parentMode.StartStrawberries        = 0;
                    parentMode.StrawberriesByCheckpoint = new EntityData[10, 25];

                    for (int i = 0; parentMode.Checkpoints != null && i < parentMode.Checkpoints.Length; i++)
                    {
                        if (parentMode.Checkpoints[i] != null)
                        {
                            parentMode.Checkpoints[i].Strawberries = 0;
                        }
                    }

                    foreach (EntityData entity in parentMapData.Strawberries)
                    {
                        if (!entity.Bool("moon"))
                        {
                            int checkpointID = entity.Int("checkpointIDParented", entity.Int("checkpointID"));
                            int order        = entity.Int("order");

                            if (_GrowAndGet(ref parentMode.StrawberriesByCheckpoint, checkpointID, order) == null)
                            {
                                parentMode.StrawberriesByCheckpoint[checkpointID, order] = entity;
                            }

                            if (checkpointID == 0)
                            {
                                parentMode.StartStrawberries++;
                            }
                            else if (parentMode.Checkpoints != null)
                            {
                                parentMode.Checkpoints[checkpointID - 1].Strawberries++;
                            }

                            parentMode.TotalStrawberries++;
                        }
                    }
                }
            } catch (Exception e) when(e is not OutOfMemoryException)    // OOM errors are currently unrecoverable
            {
                Mod.Logger.Log(LogLevel.Warn, "misc", $"Failed loading MapData {Area}");
                e.LogDetailed();
            }
        }
Пример #12
0
        private void ReloadItems()
        {
            foreach (TextMenu.Item item in items)
            {
                menu.Remove(item);
            }
            items.Clear();

            string filterSet = null;

            if (type == 0)
            {
                filterSet = "Celeste";
            }
            else if (type >= 3)
            {
                filterSet = sets[type - 3];
            }

            string        lastLevelSet          = null;
            LevelSetStats levelSetStats         = null;
            int           levelSetAreaOffset    = 0;
            int           levelSetUnlockedAreas = int.MaxValue;
            int           levelSetUnlockedModes = int.MaxValue;
            string        name;

            SaveData         save         = SaveData.Instance;
            List <AreaStats> areaStatsAll = save.Areas;

            for (int i = 0; i < AreaData.Areas.Count; i++)
            {
                AreaData area = AreaData.Get(i);
                if (area == null || !area.HasMode((AreaMode)side))
                {
                    continue;
                }

                // TODO: Make subchapters hidden by default in the map list, even in debug mode.
                if (!save.DebugMode && !string.IsNullOrEmpty(area.GetMeta()?.Parent))
                {
                    continue;
                }

                string levelSet = area.GetLevelSet();

                if (type != 1 && ((filterSet == null && levelSet == "Celeste") || (filterSet != null && filterSet != levelSet)))
                {
                    continue;
                }

                name = area.Name;
                name = name.DialogCleanOrNull() ?? name.SpacedPascalCase();

                if (lastLevelSet != levelSet)
                {
                    lastLevelSet          = levelSet;
                    levelSetStats         = SaveData.Instance.GetLevelSetStatsFor(levelSet);
                    levelSetAreaOffset    = levelSetStats.AreaOffset;
                    levelSetUnlockedAreas = levelSetStats.UnlockedAreas;
                    levelSetUnlockedModes = levelSetStats.UnlockedModes;
                    string setname = DialogExt.CleanLevelSet(levelSet);
                    TextMenuExt.SubHeaderExt levelSetHeader = new TextMenuExt.SubHeaderExt(setname);
                    levelSetHeader.Alpha = 0f;
                    menu.Add(levelSetHeader);
                    items.Add(levelSetHeader);
                }

                TextMenuExt.ButtonExt button = new TextMenuExt.ButtonExt(name);
                button.Alpha = 0f;

                if (area.Icon != "areas/null")
                {
                    button.Icon = area.Icon;
                }
                button.IconWidth = 64f;

                if (levelSet == "Celeste" && i > levelSetAreaOffset + levelSetUnlockedAreas)
                {
                    button.Disabled = true;
                }
                if (side == 1 && !areaStatsAll[i].Cassette)
                {
                    button.Disabled = true;
                }
                if (side >= 2 && levelSetUnlockedModes < (side + 1))
                {
                    button.Disabled = true;
                }

                menu.Add(button.Pressed(() => {
                    Inspect(area, (AreaMode)side);
                }));
                items.Add(button);
            }

            // compute a delay so that options don't take more than a second to show up if many mods are installed.
            float delayBetweenOptions = 0.03f;

            if (items.Count > 0)
            {
                delayBetweenOptions = Math.Min(0.03f, 1f / items.Count);
            }

            // Do this afterwards as the menu has now properly updated its size.
            for (int i = 0; i < items.Count; i++)
            {
                Add(new Coroutine(FadeIn(i, delayBetweenOptions, items[i])));
            }

            if (menu.Height > menu.ScrollableMinSize)
            {
                menu.Position.Y = menu.ScrollTargetY;
            }
        }
Пример #13
0
        public void ctor(Session session, Vector2?startPosition = default(Vector2?))
        {
            if (CoreModule.Settings.LazyLoading)
            {
                VirtualContentExt.UnloadOverworld();
            }

            // Vanilla TileToIndex mappings.
            SurfaceIndex.TileToIndex = new Dictionary <char, int> {
                { '1', 3 },
                { '3', 4 },
                { '4', 7 },
                { '5', 8 },
                { '6', 8 },
                { '7', 8 },
                { '8', 8 },
                { '9', 13 },
                { 'a', 8 },
                { 'b', 23 },
                { 'c', 8 },
                { 'd', 8 },
                { 'e', 8 },
                { 'f', 8 },
                { 'g', 8 },
                { 'h', 33 },
                { 'i', 4 },
                { 'j', 8 },
                { 'k', 3 },
                { 'l', 33 },
                { 'm', 3 }
            };

            AreaData area = AreaData.Get(session);
            MapMeta  meta = area.GetMeta();
            string   path;

            path = meta?.BackgroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "BackgroundTiles.xml");
            }
            GFX.BGAutotiler = new Autotiler(path);

            path = meta?.ForegroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "ForegroundTiles.xml");
            }
            GFX.FGAutotiler = new Autotiler(path);

            path = meta?.AnimatedTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "AnimatedTiles.xml");
            }
            GFX.AnimatedTilesBank = new AnimatedTilesBank();
            XmlElement animatedData = Calc.LoadContentXML(path)["Data"];

            foreach (XmlElement el in animatedData)
            {
                if (el != null)
                {
                    GFX.AnimatedTilesBank.Add(
                        el.Attr("name"),
                        el.AttrFloat("delay", 0f),
                        el.AttrVector2("posX", "posY", Vector2.Zero),
                        el.AttrVector2("origX", "origY", Vector2.Zero),
                        GFX.Game.GetAtlasSubtextures(el.Attr("path"))
                        );
                }
            }

            path = meta?.Sprites;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "Sprites.xml");
            }
            GFX.SpriteBank = new SpriteBank(GFX.Game, path);

            path = meta?.Portraits;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "Portraits.xml");
            }
            GFX.PortraitsSpriteBank = new SpriteBank(GFX.Portraits, path);

            orig_ctor(session, startPosition);
        }
Пример #14
0
        public void ctor(Session session, Vector2?startPosition = default)
        {
            Logger.Log(LogLevel.Info, "LevelLoader", "Loading level " + session?.Area.GetSID());

            if (LastLoadingThread != null &&
                LastLoadingThread.TryGetTarget(out Thread lastThread) &&
                (lastThread?.IsAlive ?? false))
            {
                lastThread?.Abort();
            }

            if (CoreModule.Settings.LazyLoading)
            {
                MainThreadHelper.Do(() => VirtualContentExt.UnloadOverworld());
            }

            // Vanilla TileToIndex mappings.
            SurfaceIndex.TileToIndex = new Dictionary <char, int> {
                { '1', 3 },
                { '3', 4 },
                { '4', 7 },
                { '5', 8 },
                { '6', 8 },
                { '7', 8 },
                { '8', 8 },
                { '9', 13 },
                { 'a', 8 },
                { 'b', 23 },
                { 'c', 8 },
                { 'd', 8 },
                { 'e', 8 },
                { 'f', 8 },
                { 'g', 8 },
                { 'G', 8 }, // Reflection alt - unassigned in vanilla.
                { 'h', 33 },
                { 'i', 4 },
                { 'j', 8 },
                { 'k', 3 },
                { 'l', 25 },
                { 'm', 44 },
                { 'n', 40 },
                { 'o', 43 }
            };

            AreaData area = AreaData.Get(session);
            MapMeta  meta = area.GetMeta();
            string   path;

            path = meta?.BackgroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "BackgroundTiles.xml");
            }
            GFX.BGAutotiler = new Autotiler(path);

            path = meta?.ForegroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "ForegroundTiles.xml");
            }
            GFX.FGAutotiler = new Autotiler(path);

            path = meta?.AnimatedTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "AnimatedTiles.xml");
            }
            GFX.AnimatedTilesBank = new AnimatedTilesBank();
            XmlElement animatedData = Calc.LoadContentXML(path)["Data"];

            foreach (XmlElement el in animatedData)
            {
                if (el != null)
                {
                    GFX.AnimatedTilesBank.Add(
                        el.Attr("name"),
                        el.AttrFloat("delay", 0f),
                        el.AttrVector2("posX", "posY", Vector2.Zero),
                        el.AttrVector2("origX", "origY", Vector2.Zero),
                        GFX.Game.GetAtlasSubtextures(el.Attr("path"))
                        );
                }
            }

            GFX.SpriteBank = new SpriteBank(GFX.Game, Path.Combine("Graphics", "Sprites.xml"));

            path = meta?.Sprites;
            if (!string.IsNullOrEmpty(path))
            {
                SpriteBank bankOrig = GFX.SpriteBank;
                SpriteBank bankMod  = new SpriteBank(GFX.Game, getModdedSpritesXml(path));

                foreach (KeyValuePair <string, SpriteData> kvpBank in bankMod.SpriteData)
                {
                    string     key      = kvpBank.Key;
                    SpriteData valueMod = kvpBank.Value;

                    if (bankOrig.SpriteData.TryGetValue(key, out SpriteData valueOrig))
                    {
                        IDictionary animsOrig = valueOrig.Sprite.GetAnimations();
                        IDictionary animsMod  = valueMod.Sprite.GetAnimations();
                        foreach (DictionaryEntry kvpAnim in animsMod)
                        {
                            animsOrig[kvpAnim.Key] = kvpAnim.Value;
                        }

                        valueOrig.Sources.AddRange(valueMod.Sources);

                        // replay the starting animation to be sure it is referring to the new sprite.
                        valueOrig.Sprite.Stop();
                        if (valueMod.Sprite.CurrentAnimationID != "")
                        {
                            valueOrig.Sprite.Play(valueMod.Sprite.CurrentAnimationID);
                        }
                    }
                    else
                    {
                        bankOrig.SpriteData[key] = valueMod;
                    }
                }
            }

            // This is done exactly once in the vanilla GFX.LoadData method.
            PlayerSprite.ClearFramesMetadata();
            PlayerSprite.CreateFramesMetadata("player");
            PlayerSprite.CreateFramesMetadata("player_no_backpack");
            PlayerSprite.CreateFramesMetadata("badeline");
            PlayerSprite.CreateFramesMetadata("player_badeline");
            PlayerSprite.CreateFramesMetadata("player_playback");

            path = meta?.Portraits;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "Portraits.xml");
            }
            GFX.PortraitsSpriteBank = new SpriteBank(GFX.Portraits, path);

            orig_ctor(session, startPosition);

            LastLoadingThread = patch_RunThread.Current;

            // get rid of all entities in the pooler to make sure they don't keep references to the previous level.
            foreach (Queue <Entity> entities in ((patch_Pooler)Engine.Pooler).Pools.Values)
            {
                entities.Clear();
            }
        }