private static void OnAnalyze(object sender, AnalyzeEventArgs e) { var farmer = sender as Farmer; if (farmer != Game1.player) { return; } SpellBook spellBook = farmer.GetSpellBook(); List <string> spellsLearnt = new List <string>(); if (farmer.CurrentItem != null) { if (farmer.CurrentTool != null) { if (farmer.CurrentTool is StardewValley.Tools.Axe || farmer.CurrentTool is StardewValley.Tools.Pickaxe) { spellsLearnt.Add("toil:cleardebris"); } else if (farmer.CurrentTool is StardewValley.Tools.Hoe) { spellsLearnt.Add("toil:till"); } else if (farmer.CurrentTool is StardewValley.Tools.WateringCan) { spellsLearnt.Add("toil:water"); } } else if (farmer.CurrentItem is Boots) { spellsLearnt.Add("life:evac"); } else if (farmer.ActiveObject != null) { if (!farmer.ActiveObject.bigCraftable.Value) { int index = farmer.ActiveObject.ParentSheetIndex; if (index == 395) // Coffee { spellsLearnt.Add("life:haste"); } else if (index == 773) // Life elixir { spellsLearnt.Add("life:heal"); } else if (index == 86) // Earth crystal { spellsLearnt.Add("nature:shockwave"); } else if (index == 82) // Fire quartz { spellsLearnt.Add("elemental:fireball"); } else if (index == 161) // Ice Pip { spellsLearnt.Add("elemental:frostbolt"); } } } } foreach (var lightSource in farmer.currentLocation.sharedLights.Values) { if (Utility.distance(e.TargetX, lightSource.position.X, e.TargetY, lightSource.position.Y) < lightSource.radius.Value * Game1.tileSize) { spellsLearnt.Add("nature:lantern"); break; } } var tilePos = new Vector2(e.TargetX / Game1.tileSize, e.TargetY / Game1.tileSize); if (farmer.currentLocation.terrainFeatures.TryGetValue(tilePos, out TerrainFeature feature) && feature is HoeDirt dirt && dirt.crop != null) { spellsLearnt.Add("nature:tendrils"); } // TODO: Add proper tilesheet check var tile = farmer.currentLocation.map.GetLayer("Buildings").Tiles[(int)tilePos.X, (int)tilePos.Y]; if (tile != null && tile.TileIndex == 173) { spellsLearnt.Add("elemental:descend"); } if (farmer.currentLocation is Farm farm) { foreach (var clump in farm.resourceClumps) { if (clump.parentSheetIndex.Value == 622 && new Rectangle((int)clump.tile.Value.X, (int)clump.tile.Value.Y, clump.width.Value, clump.height.Value).Contains((int)tilePos.X, (int)tilePos.Y)) { spellsLearnt.Add("eldritch:meteor"); } } } if (farmer.currentLocation.doesTileHaveProperty((int)tilePos.X, (int)tilePos.Y, "Action", "Buildings") == "EvilShrineLeft") { spellsLearnt.Add("eldritch:lucksteal"); } if (farmer.currentLocation is StardewValley.Locations.MineShaft { mineLevel : 100 } ms&& ms.waterTiles[(int)tilePos.X, (int)tilePos.Y]) { spellsLearnt.Add("eldritch:bloodmana"); } for (int i = spellsLearnt.Count - 1; i >= 0; --i) { if (spellBook.KnowsSpell(spellsLearnt[i], 0)) { spellsLearnt.RemoveAt(i); } } if (spellsLearnt.Count > 0) { Game1.playSound("secret1"); foreach (string spell in spellsLearnt) { Log.Debug("Player learnt spell: " + spell); spellBook.LearnSpell(spell, 0, true); //Game1.drawObjectDialogue(Mod.instance.Helper.Translation.Get("spell.learn", new { spellName = Mod.instance.Helper.Translation.Get("spell." + spell + ".name") })); Game1.addHUDMessage(new HUDMessage(Mod.Instance.Helper.Translation.Get("spell.learn", new { spellName = SpellManager.Get(spell).GetTranslatedName() }))); } } // Temporary - 0.3.0 will add dungeons to get these bool knowsAll = true; foreach (string schoolId in School.GetSchoolList()) { var school = School.GetSchool(schoolId); bool knowsAllSchool = true; foreach (var spell in school.GetSpellsTier1()) { if (!spellBook.KnowsSpell(spell, 0)) { knowsAll = knowsAllSchool = false; break; } } foreach (var spell in school.GetSpellsTier2()) { if (!spellBook.KnowsSpell(spell, 0)) { knowsAll = knowsAllSchool = false; break; } } // Have to know all other spells for the arcane one if (schoolId == SchoolId.Arcane) { continue; } var ancientSpell = school.GetSpellsTier3()[0]; if (knowsAllSchool && !spellBook.KnowsSpell(ancientSpell, 0)) { Log.Debug("Player learnt ancient spell: " + ancientSpell); spellBook.LearnSpell(ancientSpell, 0, true); Game1.addHUDMessage(new HUDMessage(Mod.Instance.Helper.Translation.Get("spell.learn.ancient", new { spellName = ancientSpell.GetTranslatedName() }))); } } var rewindSpell = School.GetSchool(SchoolId.Arcane).GetSpellsTier3()[0]; if (knowsAll && !spellBook.KnowsSpell(rewindSpell, 0)) { Log.Debug("Player learnt ancient spell: " + rewindSpell); spellBook.LearnSpell(rewindSpell, 0, true); Game1.addHUDMessage(new HUDMessage(Mod.Instance.Helper.Translation.Get("spell.learn.ancient", new { spellName = rewindSpell.GetTranslatedName() }))); } }
/********* ** Private methods *********/ /// <summary>Apply legacy save data to the player's current fields, if valid and the field doesn't already have a value.</summary> /// <param name="legacyData">The save data to apply.</param> /// <returns>Returns the player IDs whose fields were changed.</returns> private IEnumerable <long> TryApply(LegacySaveData legacyData) { foreach (var pair in legacyData?.Players ?? new()) { // get player spellbook Farmer player = Game1.getFarmerMaybeOffline(pair.Key); if (player == null) { continue; } SpellBook book = player.GetSpellBook(); // apply data bool changed = false; book.Mutate(data => { // free spell point if (data.FreePoints <= 0) { int freePoints = pair.Value.FreePoints; if (freePoints > 0) { data.FreePoints = Math.Max(0, freePoints); changed = true; } } // known spells if (!data.KnownSpells.Any()) { PreparedSpell[] knownSpells = (pair.Value.SpellBook?.KnownSpells ?? new()) .Select(p => new PreparedSpell(p.Key, p.Value)) .ToArray(); if (knownSpells.Any()) { data.KnownSpells = knownSpells.ToDictionary(p => p.SpellId); changed = true; } } // prepared spells if (!data.Prepared.Any()) { var preparedSpells = (pair.Value.SpellBook?.Prepared ?? new PreparedSpell[][] { }) .Select(spells => new PreparedSpellBar { Spells = spells.ToList() }) .ToArray(); if (preparedSpells.Any(bar => bar.Spells.Any(spell => spell != null))) { data.Prepared = preparedSpells; changed = true; } } // prepared index if (data.SelectedPrepared <= 0) { int index = pair.Value.SpellBook?.SelectedPrepared ?? 0; if (index > 0) { data.SelectedPrepared = index; changed = true; } } }); if (changed) { yield return(pair.Key); } } }