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; } }
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(); } } }
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)); }
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); } }
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; } } }
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); }
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; } } } } }
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; } } } } }
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; } } }
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); }
[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(); } }
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; } }
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); }
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(); } }