void RefreshSpellsList() { // Clear existing list spellsListBox.ClearItems(); // Add spells based on mode if (buyMode) { // Load spells for sale offeredSpells.Clear(); List <SpellRecord.SpellRecordData> standardSpells = DaggerfallSpellReader.ReadSpellsFile(Path.Combine(DaggerfallUnity.Arena2Path, spellsFilename)); if (standardSpells == null || standardSpells.Count == 0) { Debug.LogError("Failed to load SPELLS.STD for spellbook in buy mode."); return; } for (int i = 0; i < standardSpells.Count; i++) { // Filter internal spells starting with exclamation point '!' if (standardSpells[i].spellName.StartsWith("!")) { continue; } // NOTE: Classic allows purchase of duplicate spells // If ever changing this, must ensure spell is an *exact* duplicate (i.e. not a custom spell with same name) // Just allowing duplicates for now as per classic and let user manage preference // Get effect bundle settings from classic spell EffectBundleSettings bundle; if (!GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(standardSpells[i], BundleTypes.Spell, out bundle)) { continue; } // Store offered spell and add to list box offeredSpells.Add(bundle); spellsListBox.AddItem(standardSpells[i].spellName); } } else { // Add player spells to list EffectBundleSettings[] spellbook = GameManager.Instance.PlayerEntity.GetSpells(); if (spellbook != null) { for (int i = 0; i < spellbook.Length; i++) { // Show spell name and cost // Costs can change based on player skills and stats so must be calculated each time int goldCost, spellPointCost; FormulaHelper.CalculateTotalEffectCosts(spellbook[i].Effects, spellbook[i].TargetType, out goldCost, out spellPointCost); spellsListBox.AddItem(string.Format("{0} - {1}", spellPointCost, spellbook[i].Name)); } } } }
/// <summary> /// Rebuilds dictionary of classic spells by re-reading SPELLS.STD. /// </summary> void RebuildClassicSpellsDict() { classicSpells.Clear(); List <SpellRecord.SpellRecordData> spells = DaggerfallSpellReader.ReadSpellsFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, DaggerfallSpellReader.DEFAULT_FILENAME)); foreach (SpellRecord.SpellRecordData spell in spells) { // "Holy Touch" and "Holy Word" have same ID but different properties // Not sure of best way to handle - just ignoring duplicate for now if (classicSpells.ContainsKey(spell.index)) { //Debug.LogErrorFormat("RebuildClassicSpellsDict found duplicate key {0} for spell {1}. Existing spell={2}", spell.index, spell.spellName, classicSpells[spell.index].spellName); continue; } classicSpells.Add(spell.index, spell); } }
private void LoadSpellsForSale() { // Load spells for sale offeredSpells.Clear(); List <SpellRecord.SpellRecordData> standardSpells = DaggerfallSpellReader.ReadSpellsFile(Path.Combine(DaggerfallUnity.Arena2Path, spellsFilename)); if (standardSpells == null || standardSpells.Count == 0) { Debug.LogError("Failed to load SPELLS.STD for spellbook in buy mode."); return; } // Add standard spell bundles to offer for (int i = 0; i < standardSpells.Count; i++) { // Filter internal spells starting with exclamation point '!' if (standardSpells[i].spellName.StartsWith("!")) { continue; } // NOTE: Classic allows purchase of duplicate spells // If ever changing this, must ensure spell is an *exact* duplicate (i.e. not a custom spell with same name) // Just allowing duplicates for now as per classic and let user manage preference // Get effect bundle settings from classic spell EffectBundleSettings bundle; if (!GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(standardSpells[i], BundleTypes.Spell, out bundle)) { continue; } // Store offered spell and add to list box offeredSpells.Add(bundle); } // Add custom spells for sale bundles to list of offered spells offeredSpells.AddRange(GameManager.Instance.EntityEffectBroker.GetCustomSpellBundles(EntityEffectBroker.CustomSpellBundleOfferUsage.SpellsForSale)); // Sort spells for easier finding offeredSpells = offeredSpells.OrderBy(x => x.Name).ToList(); }
public override TextFile.Token[] MagicPowers(TextFile.Formatting format) { // %mpw if (parent.IsArtifact) { // Use appropriate artifact description message. (8700-8721) try { ArtifactsSubTypes artifactType = ItemHelper.GetArtifactSubType(parent.shortName); return(DaggerfallUnity.Instance.TextProvider.GetRSCTokens(8700 + (int)artifactType)); } catch (KeyNotFoundException e) { Debug.Log(e.Message); return(null); } } else if (!parent.IsIdentified) { // Powers unknown. TextFile.Token nopowersToken = TextFile.CreateTextToken(HardStrings.powersUnknown); return(new TextFile.Token[] { nopowersToken }); } else { // List item powers. List <TextFile.Token> magicPowersTokens = new List <TextFile.Token>(); for (int i = 0; i < parent.legacyMagic.Length; i++) { // Also 65535 to handle saves from when the type was read as an unsigned value if (parent.legacyMagic[i].type == EnchantmentTypes.None || (int)parent.legacyMagic[i].type == 65535) { break; } string firstPart = HardStrings.itemPowers[(int)parent.legacyMagic[i].type] + " "; if (parent.legacyMagic[i].type == EnchantmentTypes.SoulBound && parent.legacyMagic[i].param != -1) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.enemyNames[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.ExtraSpellPts) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.extraSpellPtsTimes[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.PotentVs || parent.legacyMagic[i].type == EnchantmentTypes.LowDamageVs) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.enemyGroupNames[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.RegensHealth) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.regensHealthTimes[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.VampiricEffect) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.vampiricEffectRanges[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.IncreasedWeightAllowance) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.increasedWeightAllowances[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.EnhancesSkill) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + DaggerfallUnity.Instance.TextProvider.GetSkillName((DaggerfallConnect.DFCareer.Skills)parent.legacyMagic[i].param))); } else if (parent.legacyMagic[i].type == EnchantmentTypes.ImprovesTalents) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.improvedTalents[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.GoodRepWith || parent.legacyMagic[i].type == EnchantmentTypes.BadRepWith) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.repWithGroups[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.ItemDeteriorates) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.itemDeteriorateLocations[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.UserTakesDamage) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.userTakesDamageLocations[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.HealthLeech) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.healthLeechStopConditions[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type == EnchantmentTypes.BadReactionsFrom) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + HardStrings.badReactionFromEnemyGroups[parent.legacyMagic[i].param])); } else if (parent.legacyMagic[i].type <= EnchantmentTypes.CastWhenStrikes) { List <DaggerfallConnect.Save.SpellRecord.SpellRecordData> spells = DaggerfallSpellReader.ReadSpellsFile(); bool found = false; foreach (DaggerfallConnect.Save.SpellRecord.SpellRecordData spell in spells) { if (spell.index == parent.legacyMagic[i].param) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + spell.spellName)); found = true; break; } } if (!found) { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart + "ERROR")); } } else { magicPowersTokens.Add(TextFile.CreateTextToken(firstPart)); } magicPowersTokens.Add(TextFile.CreateFormatToken(format)); } return(magicPowersTokens.ToArray()); } }
static void CreateStartingSpellsJSON(string fallExePath, string outputPath) { const int recordLength = 6; // Length of starting spells record per career const int casterRecordCount = 7; // Number of caster career spell records const long startingSpellsOffset = 0x1B064F; // Offset into FALL.EXE for starting spell data (can be different based on .EXE version) /* * Alternate offset: 0x1B513F * Offset data in FALL.EXE should start like so (credit to Allofich for information) * 01 25 02 61 08 FF // Mage * 08 2C 25 FF FF FF // Spellsword / Custom class (if any of the primary or major skills is a magic skill) * 08 02 25 FF FF FF // Battlemage * 01 25 02 61 08 FF // Sorcerer * 61 02 01 25 FF FF // Healer * 2C 02 FF FF FF FF // Nightblade * 25 FF FF FF FF FF // Bard * ... */ // Read all CLASS*.CFG files List <DFCareer> classList = new List <DFCareer>(); string[] files = Directory.GetFiles(DaggerfallUnity.Instance.Arena2Path, "CLASS*.CFG"); if (files != null && files.Length > 0) { for (int i = 0; i < files.Length - 1; i++) { ClassFile classFile = new ClassFile(files[i]); classList.Add(classFile.Career); } } // Get list of spells List <SpellRecord.SpellRecordData> standardSpells = DaggerfallSpellReader.ReadSpellsFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, spellsStd)); // Read starting spell records for these classes byte[] record; FileProxy exeFile = new FileProxy(fallExePath, FileUsage.UseDisk, true); BinaryReader reader = exeFile.GetReader(startingSpellsOffset); List <CareerStartingSpells> careerList = new List <CareerStartingSpells>(); for (int i = 0; i < casterRecordCount; i++) { CareerStartingSpells careerItem = new CareerStartingSpells() { CareerIndex = i, CareerName = classList[i].Name, }; List <StartingSpell> spellsList = new List <StartingSpell>(); record = reader.ReadBytes(recordLength); for (int j = 0; j < recordLength; j++) { if (record[j] == 0xff) { continue; } // Get spell record data // Some careers reference spells that don't exist in SPELLS.STD - skipping over these SpellRecord.SpellRecordData spellRecordData; if (!FindSpellByID(record[j], standardSpells, out spellRecordData)) { //Debug.LogErrorFormat("Spell ID {0} not found while reading career '{1}'", record[j], careerItem.CareerName); continue; } // Barbarian has !Nux Vomica (a poison) in their starting spell list? - skipping for now if (spellRecordData.spellName.StartsWith("!")) { continue; } StartingSpell spellItem = new StartingSpell() { SpellID = record[j], SpellName = spellRecordData.spellName, }; spellsList.Add(spellItem); } careerItem.SpellsList = spellsList.ToArray(); careerList.Add(careerItem); } // Output JSON file string json = SaveLoadManager.Serialize(careerList.GetType(), careerList); File.WriteAllText(outputPath, json); }