Example #1
0
        /// <summary>
        /// Load monster record into memory and decompose it for use.
        /// </summary>
        /// <param name="monster">Monster index.</param>
        /// <returns>True if successful.</returns>
        public bool LoadMonster(int monster, out DFCareer monsterClassOut)
        {
            monsterClassOut = new DFCareer();

            // Generate name from index
            string name = string.Format("ENEMY{0:000}.CFG", monster);

            // Attempt to load record
            int index = bsaFile.GetRecordIndex(name);

            if (index == -1)
            {
                return(false);
            }

            // Read monster class data
            ClassFile classFile = new ClassFile();

            byte[]       data   = bsaFile.GetRecordBytes(index);
            MemoryStream stream = new MemoryStream(data);
            BinaryReader reader = new BinaryReader(stream);

            classFile.Load(reader);
            reader.Close();

            // Set output class
            monsterClassOut = classFile.Career;

            return(true);
        }
Example #2
0
        public void Reroll(DFCareer dfClass)
        {
            // Assign base stats from class template
            DaggerfallStats rolledStats = CharacterDocument.GetClassBaseStats(dfClass);

            // Roll bonus value for each base stat
            // Using maxBonusRoll + 1 as Unity's Random.Range(int,int) is exclusive
            // of maximum value and we want to be inclusive of maximum value
            rolledStats.Strength     += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Intelligence += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Willpower    += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Agility      += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Endurance    += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Personality  += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Speed        += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);
            rolledStats.Luck         += UnityEngine.Random.Range(minBonusRoll, maxBonusRoll + 1);

            // Roll bonus pool for player to distribute
            // Using maxBonusPool + 1 for inclusive range as above
            int bonusPool = UnityEngine.Random.Range(minBonusPool, maxBonusPool + 1);

            // Apply stats to control
            SetStats(rolledStats, rolledStats, bonusPool);
            UpdateStatLabels();

            // Play "rolling dice" sound
            DaggerfallUI.Instance.PlayOneShot(SoundClips.DiceRoll);
        }
        protected override void Setup()
        {
            base.Setup();

            // Read all CLASS*.CFG files and add to listbox
            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]);
                    if (classFile.Career.Name == "Spellsword")
                    {
                        DFCareer c = PopulateCareer();
                        classList.Add(c);
                        listBox.AddItem(c.Name);
                    }
                    else
                    {
                        classList.Add(classFile.Career);
                        listBox.AddItem(classFile.Career.Name);
                    }
                }
            }

            // Last option is for creating custom classes
            listBox.AddItem("Custom");

            OnItemPicked += DaggerfallClassSelectWindow_OnItemPicked;
        }
 public CreateCharSpecialAdvantageWindow(IUserInterfaceManager uiManager, List <SpecialAdvDis> advDisList, DFCareer careerData, IUserInterfaceWindow previous = null, bool isDisadvantages = false)
     : base(uiManager, previous)
 {
     this.isDisadvantages = isDisadvantages;
     this.advDisList      = advDisList;
     this.advantageData   = careerData;
 }
        void DaggerfallClassSelectWindow_OnItemPicked(int index, string className)
        {
            if (index == classList.Count) // "Custom" option selected
            {
                selectedClass      = null;
                selectedClassIndex = -1;
                CloseWindow();
            }
            else
            {
                selectedClass      = classList[index];
                selectedClassIndex = index;

                TextFile.Token[]     textTokens = DaggerfallUnity.Instance.TextProvider.GetRSCTokens(startClassDescriptionID + index);
                DaggerfallMessageBox messageBox = new DaggerfallMessageBox(uiManager, this);
                messageBox.SetTextTokens(textTokens);
                messageBox.AddButton(DaggerfallMessageBox.MessageBoxButtons.Yes);
                Button noButton = messageBox.AddButton(DaggerfallMessageBox.MessageBoxButtons.No);
                noButton.ClickSound       = DaggerfallUI.Instance.GetAudioClip(SoundClips.ButtonClick);
                messageBox.OnButtonClick += ConfirmClassPopup_OnButtonClick;
                uiManager.PushWindow(messageBox);

                AudioClip clip = DaggerfallUnity.Instance.SoundReader.GetAudioClip(SoundClips.SelectClassDrums);
                DaggerfallUI.Instance.AudioSource.PlayOneShot(clip, DaggerfallUnity.Settings.SoundVolume);
            }
        }
Example #6
0
        void OnGUI()
        {
            if (!IsReady())
            {
                EditorGUILayout.HelpBox("DaggerfallUnity instance not ready. Have you set your Arena2 path?", MessageType.Info);
                return;
            }

            // Select class source
            EditorGUILayout.Space();
            careerSource = (CareerSource)EditorGUILayout.EnumPopup(new GUIContent("Source"), (CareerSource)careerSource);

            // Select class from specified source
            selectedCareer = null;
            if (careerSource == CareerSource.PlayerClasses && classNames != null && classNames.Length > 0)
            {
                if (selectedTemplate > classNames.Length)
                {
                    selectedTemplate = 0;
                }
                selectedTemplate = EditorGUILayout.Popup(new GUIContent("Class"), selectedTemplate, classNames);
                selectedCareer   = classTemplates[selectedTemplate];
            }
            else if (careerSource == CareerSource.Monsters && monsterNames != null && monsterNames.Length > 0)
            {
                if (selectedTemplate > monsterNames.Length)
                {
                    selectedTemplate = 0;
                }
                selectedTemplate = EditorGUILayout.Popup(new GUIContent("Class"), selectedTemplate, monsterNames);
                selectedCareer   = monsterTemplates[selectedTemplate];
            }
            else
            {
                return;
            }

            // Show foldouts
            if (selectedCareer != null)
            {
                scrollPos = GUILayoutHelper.ScrollView(scrollPos, () =>
                {
                    ShowAdvancementGUI();
                    ShowAttributesGUI();
                    ShowSecondaryAttributesGUI();
                    ShowSkillsGUI();
                    ShowTolerancesGUI();
                    ShowProficienciesGUI();
                    ShowForbiddenMaterialsGUI();
                    ShowForbiddenArmorGUI();
                    ShowForbiddenShieldsGUI();
                    ShowMagickaGUI();
                    ShowMiscellaneousGUI();
                    //ShowUnknownGUI();
                });
            }
        }
 // Set some default values for testing during development
 void SetDefaultValues()
 {
     race     = GetRaceTemplate(Races.Breton);
     gender   = Genders.Male;
     career   = DaggerfallEntity.GetClassCareerTemplate(ClassCareers.Mage);
     name     = "Nameless";
     reflexes = PlayerReflexes.Average;
     workingSkills.SetDefaults();
     workingStats.SetFromCareer(career);
     faceIndex = 0;
 }
 void ConfirmClassPopup_OnButtonClick(DaggerfallMessageBox sender, DaggerfallMessageBox.MessageBoxButtons messageBoxButton)
 {
     if (messageBoxButton == DaggerfallMessageBox.MessageBoxButtons.Yes)
     {
         sender.CloseWindow();
         CloseWindow();
     }
     else if (messageBoxButton == DaggerfallMessageBox.MessageBoxButtons.No)
     {
         selectedClass = null;
         sender.CancelWindow();
     }
 }
Example #9
0
 // Set some default values for testing during development
 void SetDefaultValues()
 {
     raceTemplate = GetRaceTemplate(Races.Breton);
     gender       = Genders.Male;
     career       = DaggerfallEntity.GetClassCareerTemplate(ClassCareers.Mage);
     name         = "Nameless";
     reflexes     = PlayerReflexes.Average;
     workingSkills.SetDefaults();
     workingStats.SetFromCareer(career);
     startingLevelUpSkillSum = 0;
     faceIndex = 0;
     skillUses = new short[DaggerfallSkills.Count];
 }
 /// <summary>
 /// Set permanent stat values from career, does not change effect mods.
 /// </summary>
 /// <param name="career">Career to set stats from.</param>
 public void SetPermanentFromCareer(DFCareer career)
 {
     if (career != null)
     {
         Strength     = career.Strength;
         Intelligence = career.Intelligence;
         Willpower    = career.Willpower;
         Agility      = career.Agility;
         Endurance    = career.Endurance;
         Personality  = career.Personality;
         Speed        = career.Speed;
         Luck         = career.Luck;
     }
 }
Example #11
0
        public static DaggerfallStats GetClassBaseStats(DFCareer dfClass)
        {
            DaggerfallStats stats = new DaggerfallStats();

            stats.SetPermanentStatValue(DFCareer.Stats.Strength, dfClass.Strength);
            stats.SetPermanentStatValue(DFCareer.Stats.Intelligence, dfClass.Intelligence);
            stats.SetPermanentStatValue(DFCareer.Stats.Willpower, dfClass.Willpower);
            stats.SetPermanentStatValue(DFCareer.Stats.Agility, dfClass.Agility);
            stats.SetPermanentStatValue(DFCareer.Stats.Endurance, dfClass.Endurance);
            stats.SetPermanentStatValue(DFCareer.Stats.Personality, dfClass.Personality);
            stats.SetPermanentStatValue(DFCareer.Stats.Speed, dfClass.Speed);
            stats.SetPermanentStatValue(DFCareer.Stats.Luck, dfClass.Luck);

            return(stats);
        }
        public static DaggerfallStats GetClassBaseStats(DFCareer dfClass)
        {
            DaggerfallStats stats = new DaggerfallStats();

            stats.Strength     = dfClass.Strength;
            stats.Intelligence = dfClass.Intelligence;
            stats.Willpower    = dfClass.Willpower;
            stats.Agility      = dfClass.Agility;
            stats.Endurance    = dfClass.Endurance;
            stats.Personality  = dfClass.Personality;
            stats.Speed        = dfClass.Speed;
            stats.Luck         = dfClass.Luck;

            return(stats);
        }
        public void SetClassSkills(DFCareer dfClass)
        {
            // Set primary, major, minor skills from class template
            primarySkills[0] = dfClass.PrimarySkill1;
            primarySkills[1] = dfClass.PrimarySkill2;
            primarySkills[2] = dfClass.PrimarySkill3;
            majorSkills[0]   = dfClass.MajorSkill1;
            majorSkills[1]   = dfClass.MajorSkill2;
            majorSkills[2]   = dfClass.MajorSkill3;
            minorSkills[0]   = dfClass.MinorSkill1;
            minorSkills[1]   = dfClass.MinorSkill2;
            minorSkills[2]   = dfClass.MinorSkill3;
            minorSkills[3]   = dfClass.MinorSkill4;
            minorSkills[4]   = dfClass.MinorSkill5;
            minorSkills[5]   = dfClass.MinorSkill6;

            UpdateSkillLabels();
            Reroll();
        }
Example #14
0
        void DaggerfallClassSelectWindow_OnItemPicked(int index)
        {
            selectedClass = classList[index];

            TextFile.Token[]     textTokens = DaggerfallUnity.Instance.TextProvider.GetRSCTokens(startClassDescriptionID + index);
            DaggerfallMessageBox messageBox = new DaggerfallMessageBox(uiManager, this);

            messageBox.SetTextTokens(textTokens);
            messageBox.AddButton(DaggerfallMessageBox.MessageBoxButtons.Yes);
            Button noButton = messageBox.AddButton(DaggerfallMessageBox.MessageBoxButtons.No);

            noButton.ClickSound       = DaggerfallUI.Instance.GetAudioClip(SoundClips.ButtonClick);
            messageBox.OnButtonClick += ConfirmClassPopup_OnButtonClick;
            uiManager.PushWindow(messageBox);

            AudioClip clip = DaggerfallUnity.Instance.SoundReader.GetAudioClip(SoundClips.SelectClassDrums);

            DaggerfallUI.Instance.AudioSource.PlayOneShot(clip);
        }
 // Set some default values for testing during development
 void SetDefaultValues()
 {
     raceTemplate = GetRaceTemplate(Races.Breton);
     gender       = Genders.Male;
     career       = DaggerfallEntity.GetClassCareerTemplate(ClassCareers.Mage);
     name         = "Nameless";
     reflexes     = PlayerReflexes.Average;
     workingSkills.SetDefaults();
     workingStats.SetPermanentFromCareer(career);
     startingLevelUpSkillSum = 0;
     faceIndex = 0;
     skillUses = new short[DaggerfallSkills.Count];
     skillsRaisedThisLevel1 = 0;
     skillsRaisedThisLevel2 = 0;
     for (int i = 0; i < armorValues.Length; i++)
     {
         armorValues[i] = 100;
     }
 }
        private void SaveLoadManager_OnStartLoad(SaveData_v1 saveData)
        {
            PlayerEntityData_v1 pData = saveData.playerData.playerEntity;

            // sync health bar
            healthBarLoss.Amount = pData.currentHealth / (float)pData.maxHealth;
            healthBar.Amount     = healthBarLoss.Amount;
            // sync fatigue bar
            int maxFatigue = (pData.stats.LiveStrength + pData.stats.LiveEndurance) * 64;

            fatigueBarLoss.Amount = pData.currentFatigue / (float)maxFatigue;
            fatigueBar.Amount     = fatigueBarLoss.Amount;

            // sync magicka bar
            DFCareer career     = pData.careerTemplate;
            int      maxMagicka = FormulaHelper.SpellPoints(pData.stats.LiveIntelligence, career.SpellPointMultiplierValue);

            magickaBarLoss.Amount = pData.currentMagicka / (float)maxMagicka;
            magickaBar.Amount     = magickaBarLoss.Amount;
        }
Example #17
0
        /// <summary>
        /// Sets enemy career and prepares entity settings.
        /// </summary>
        public void SetEnemyCareer(MobileEnemy mobileEnemy, EntityTypes entityType)
        {
            if (entityType == EntityTypes.EnemyMonster)
            {
                careerIndex = (int)mobileEnemy.ID;
                career      = GetMonsterCareerTemplate((MonsterCareers)careerIndex);
                stats.SetFromCareer(career);

                // Enemy monster has predefined level and health
                level     = career.HitPointsPerLevelOrMonsterLevel;
                maxHealth = UnityEngine.Random.Range(mobileEnemy.MinHealth, mobileEnemy.MaxHealth + 1);
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                careerIndex = (int)mobileEnemy.ID - 128;
                career      = GetClassCareerTemplate((ClassCareers)careerIndex);
                stats.SetFromCareer(career);

                // Enemy class is levelled to player and uses same health rules
                level     = GameManager.Instance.PlayerEntity.Level;
                maxHealth = FormulaHelper.RollMaxHealth(level, stats.Endurance, career.HitPointsPerLevelOrMonsterLevel);

                // Enemy class damage is temporarily set by a fudged level multiplier
                // This will change once full entity setup and items are available
                const float damageMultiplier = 4f;
                mobileEnemy.MinDamage = (int)(level * damageMultiplier);
                mobileEnemy.MaxDamage = (int)((level + 2) * damageMultiplier);
            }
            else
            {
                career      = new DFCareer();
                careerIndex = -1;
                return;
            }

            this.mobileEnemy = mobileEnemy;
            this.entityType  = entityType;
            name             = career.Name;

            FillVitalSigns();
        }
Example #18
0
        /// <summary>
        /// Load monster record into memory and decompose it for use.
        /// </summary>
        /// <param name="monster">Monster index.</param>
        /// <returns>True if successful.</returns>
        public bool LoadMonster(int monster, out DFCareer monsterClassOut)
        {
            monsterClassOut = new DFCareer();

            // Generate name from index
            string name = string.Format("ENEMY{0:000}.CFG", monster);

            // Attempt to load record
            int index = bsaFile.GetRecordIndex(name);
            if (index == -1)
                return false;

            // Read monster class data
            ClassFile classFile = new ClassFile();
            byte[] data = bsaFile.GetRecordBytes(index);
            MemoryStream stream = new MemoryStream(data);
            BinaryReader reader = new BinaryReader(stream);
            classFile.Load(reader);
            reader.Close();

            // Set output class
            monsterClassOut = classFile.Career;

            return true;
        }
        void SetStartingSpells(PlayerEntity playerEntity)
        {
            if (characterDocument.classIndex > 6 && !characterDocument.isCustom) // Class does not have starting spells
            {
                return;
            }

            // Get starting set based on class
            int spellSetIndex = -1;

            if (characterDocument.isCustom)
            {
                DFCareer dfc = characterDocument.career;

                // Custom class uses Spellsword starting spells if it has at least 1 primary or major magic skill
                if (Enum.IsDefined(typeof(DFCareer.MagicSkills), (int)dfc.PrimarySkill1) ||
                    Enum.IsDefined(typeof(DFCareer.MagicSkills), (int)dfc.PrimarySkill2) ||
                    Enum.IsDefined(typeof(DFCareer.MagicSkills), (int)dfc.PrimarySkill3) ||
                    Enum.IsDefined(typeof(DFCareer.MagicSkills), (int)dfc.MajorSkill1) ||
                    Enum.IsDefined(typeof(DFCareer.MagicSkills), (int)dfc.MajorSkill2) ||
                    Enum.IsDefined(typeof(DFCareer.MagicSkills), (int)dfc.MajorSkill3))
                {
                    spellSetIndex = 1;
                }
            }
            else
            {
                spellSetIndex = characterDocument.classIndex;
            }

            if (spellSetIndex == -1)
            {
                return;
            }

            // Get the set's spell indices
            TextAsset spells = Resources.Load <TextAsset>("StartingSpells") as TextAsset;
            List <CareerStartingSpells> startingSpells = SaveLoadManager.Deserialize(typeof(List <CareerStartingSpells>), spells.text) as List <CareerStartingSpells>;
            List <StartingSpell>        spellsToAdd    = new List <StartingSpell>();

            for (int i = 0; i < startingSpells[spellSetIndex].SpellsList.Length; i++)
            {
                spellsToAdd.Add(startingSpells[spellSetIndex].SpellsList[i]);
            }

            // Add spells to player from standard list
            foreach (StartingSpell spell in spellsToAdd)
            {
                SpellRecord.SpellRecordData spellData;
                GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(spell.SpellID, out spellData);
                if (spellData.index == -1)
                {
                    Debug.LogError("Failed to locate starting spell in standard spells list.");
                    continue;
                }

                EffectBundleSettings bundle;
                if (!GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spellData, BundleTypes.Spell, out bundle))
                {
                    Debug.LogError("Failed to create effect bundle for starting spell.");
                    continue;
                }
                playerEntity.AddSpell(bundle);
            }
        }
Example #20
0
        protected override void Setup()
        {
            if (IsSetup)
            {
                return;
            }

            // Load native textures
            nativeTexture       = DaggerfallUI.GetTextureFromImg(nativeImgName);
            nativeDaggerTexture = DaggerfallUI.GetTextureFromImg(nativeDaggerImgName);
            if (!nativeTexture || !nativeDaggerTexture)
            {
                throw new Exception("CreateCharCustomClass: Could not load native texture.");
            }

            // Setup native panel background
            NativePanel.BackgroundTexture = nativeTexture;

            // Add stats rollout
            statsRollout          = new StatsRollout(false, true);
            statsRollout.Position = new Vector2(0, 0);
            NativePanel.Components.Add(statsRollout);

            // Add name textbox
            nameTextBox.Position = new Vector2(100, 5);
            nameTextBox.Size     = new Vector2(214, 7);
            NativePanel.Components.Add(nameTextBox);

            // Initialize character class
            createdClass = new DFCareer();
            createdClass.HitPointsPerLevel         = defaultHpPerLevel;
            createdClass.SpellPointMultiplier      = DFCareer.SpellPointMultipliers.Times_0_50;
            createdClass.SpellPointMultiplierValue = .5f;

            // Initiate UI components
            font = DaggerfallUI.DefaultFont;
            SetupButtons();
            hpLabel          = DaggerfallUI.AddTextLabel(font, new Vector2(285, 55), createdClass.HitPointsPerLevel.ToString(), NativePanel);
            daggerPanel.Size = new Vector2(24, 9);
            daggerPanel.BackgroundTexture = nativeDaggerTexture;
            NativePanel.Components.Add(daggerPanel);
            UpdateDifficulty();

            // Setup help dictionary
            helpDict = new Dictionary <string, int>
            {
                { HardStrings.helpAttributes, 2402 },
                { HardStrings.helpClassName, 2401 },
                { HardStrings.helpGeneral, 2400 },
                { HardStrings.helpReputations, 2406 },
                { HardStrings.helpSkillAdvancement, 2407 },
                { HardStrings.helpSkills, 2403 },
                { HardStrings.helpSpecialAdvantages, 2404 },
                { HardStrings.helpSpecialDisadvantages, 2405 }
            };

            // Setup skills dictionary
            skillsDict = new Dictionary <string, DFCareer.Skills>();
            foreach (DFCareer.Skills skill in Enum.GetValues(typeof(DFCareer.Skills)))
            {
                skillsDict.Add(DaggerfallUnity.Instance.TextProvider.GetSkillName(skill), skill);
            }
            skillsDict.Remove(string.Empty); // Don't include "none" skill value.
            skillsList = new List <string>(skillsDict.Keys);
            skillsList.Sort();               // Sort skills alphabetically a la classic.

            IsSetup = true;
        }
Example #21
0
        /// <summary>
        /// Sets enemy career and prepares entity settings.
        /// </summary>
        public void SetEnemyCareer(MobileEnemy mobileEnemy, EntityTypes entityType)
        {
            if (entityType == EntityTypes.EnemyMonster)
            {
                careerIndex = (int)mobileEnemy.ID;
                career      = GetMonsterCareerTemplate((MonsterCareers)careerIndex);
                stats.SetFromCareer(career);

                // Enemy monster has predefined level, health and armor values.
                // Armor values can be modified below by equipment.
                level     = mobileEnemy.Level;
                maxHealth = UnityEngine.Random.Range(mobileEnemy.MinHealth, mobileEnemy.MaxHealth + 1);
                for (int i = 0; i < ArmorValues.Length; i++)
                {
                    ArmorValues[i] = (sbyte)(mobileEnemy.ArmorValue * 5);
                }
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                careerIndex = (int)mobileEnemy.ID - 128;
                career      = GetClassCareerTemplate((ClassCareers)careerIndex);
                stats.SetFromCareer(career);

                // Enemy class is levelled to player and uses similar health rules
                level     = GameManager.Instance.PlayerEntity.Level;
                maxHealth = FormulaHelper.RollEnemyClassMaxHealth(level, career.HitPointsPerLevel);
            }
            else
            {
                career      = new DFCareer();
                careerIndex = -1;
                return;
            }

            this.mobileEnemy = mobileEnemy;
            this.entityType  = entityType;
            name             = career.Name;
            minMetalToHit    = mobileEnemy.MinMetalToHit;

            short skillsLevel = (short)((level * 5) + 30);

            if (skillsLevel > 100)
            {
                skillsLevel = 100;
            }

            for (int i = 0; i <= DaggerfallSkills.Count; i++)
            {
                skills.SetSkillValue(i, skillsLevel);
            }

            // Enemy classes and some monsters use equipment
            if (careerIndex == (int)MonsterCareers.Orc || careerIndex == (int)MonsterCareers.OrcShaman)
            {
                SetEnemyEquipment(0);
            }
            else if (careerIndex == (int)MonsterCareers.Centaur || careerIndex == (int)MonsterCareers.OrcSergeant)
            {
                SetEnemyEquipment(1);
            }
            else if (careerIndex == (int)MonsterCareers.OrcWarlord)
            {
                SetEnemyEquipment(2);
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                SetEnemyEquipment(UnityEngine.Random.Range(0, 2)); // 0 or 1
            }

            FillVitalSigns();
        }
Example #22
0
        /// <summary>
        /// Sets enemy career and prepares entity settings.
        /// </summary>
        public void SetEnemyCareer(MobileEnemy mobileEnemy, EntityTypes entityType)
        {
            // Try custom career first
            career = GetCustomCareerTemplate(mobileEnemy.ID);

            if (career != null)
            {
                // Custom enemy
                careerIndex = mobileEnemy.ID;
                stats.SetPermanentFromCareer(career);

                if (entityType == EntityTypes.EnemyMonster)
                {
                    // Default like a monster
                    level     = mobileEnemy.Level;
                    maxHealth = Random.Range(mobileEnemy.MinHealth, mobileEnemy.MaxHealth + 1);
                    for (int i = 0; i < ArmorValues.Length; i++)
                    {
                        ArmorValues[i] = (sbyte)(mobileEnemy.ArmorValue * 5);
                    }
                }
                else
                {
                    // Default like a class enemy
                    level     = GameManager.Instance.PlayerEntity.Level;
                    maxHealth = FormulaHelper.RollEnemyClassMaxHealth(level, career.HitPointsPerLevel);
                }
            }
            else if (entityType == EntityTypes.EnemyMonster)
            {
                careerIndex = mobileEnemy.ID;
                career      = GetMonsterCareerTemplate((MonsterCareers)careerIndex);
                stats.SetPermanentFromCareer(career);

                // Enemy monster has predefined level, health and armor values.
                // Armor values can be modified below by equipment.
                level     = mobileEnemy.Level;
                maxHealth = UnityEngine.Random.Range(mobileEnemy.MinHealth, mobileEnemy.MaxHealth + 1);
                for (int i = 0; i < ArmorValues.Length; i++)
                {
                    ArmorValues[i] = (sbyte)(mobileEnemy.ArmorValue * 5);
                }
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                careerIndex = mobileEnemy.ID - 128;
                career      = GetClassCareerTemplate((ClassCareers)careerIndex);
                stats.SetPermanentFromCareer(career);

                // Enemy class is levelled to player and uses similar health rules
                // City guards are 3 to 6 levels above the player
                level = GameManager.Instance.PlayerEntity.Level;
                if (careerIndex == (int)MobileTypes.Knight_CityWatch - 128)
                {
                    level += UnityEngine.Random.Range(3, 7);
                }

                maxHealth = FormulaHelper.RollEnemyClassMaxHealth(level, career.HitPointsPerLevel);
            }
            else
            {
                career      = new DFCareer();
                careerIndex = -1;
                return;
            }

            this.mobileEnemy = mobileEnemy;
            this.entityType  = entityType;
            name             = career.Name;
            minMetalToHit    = mobileEnemy.MinMetalToHit;
            team             = mobileEnemy.Team;

            short skillsLevel = (short)((level * 5) + 30);

            if (skillsLevel > 100)
            {
                skillsLevel = 100;
            }

            for (int i = 0; i <= DaggerfallSkills.Count; i++)
            {
                skills.SetPermanentSkillValue(i, skillsLevel);
            }

            // Generate loot table items
            DaggerfallLoot.GenerateItems(mobileEnemy.LootTableKey, items);

            // Enemy classes and some monsters use equipment
            if (careerIndex == (int)MonsterCareers.Orc || careerIndex == (int)MonsterCareers.OrcShaman)
            {
                SetEnemyEquipment(0);
            }
            else if (careerIndex == (int)MonsterCareers.Centaur || careerIndex == (int)MonsterCareers.OrcSergeant)
            {
                SetEnemyEquipment(1);
            }
            else if (careerIndex == (int)MonsterCareers.OrcWarlord)
            {
                SetEnemyEquipment(2);
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                SetEnemyEquipment(UnityEngine.Random.Range(0, 2)); // 0 or 1
            }

            // Assign spell lists
            if (entityType == EntityTypes.EnemyMonster)
            {
                if (careerIndex == (int)MonsterCareers.Imp)
                {
                    SetEnemySpells(ImpSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Ghost)
                {
                    SetEnemySpells(GhostSpells);
                }
                else if (careerIndex == (int)MonsterCareers.OrcShaman)
                {
                    SetEnemySpells(OrcShamanSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Wraith)
                {
                    SetEnemySpells(WraithSpells);
                }
                else if (careerIndex == (int)MonsterCareers.FrostDaedra)
                {
                    SetEnemySpells(FrostDaedraSpells);
                }
                else if (careerIndex == (int)MonsterCareers.FireDaedra)
                {
                    SetEnemySpells(FireDaedraSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Daedroth)
                {
                    SetEnemySpells(DaedrothSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Vampire)
                {
                    SetEnemySpells(VampireSpells);
                }
                else if (careerIndex == (int)MonsterCareers.DaedraSeducer)
                {
                    SetEnemySpells(SeducerSpells);
                }
                else if (careerIndex == (int)MonsterCareers.VampireAncient)
                {
                    SetEnemySpells(VampireAncientSpells);
                }
                else if (careerIndex == (int)MonsterCareers.DaedraLord)
                {
                    SetEnemySpells(DaedraLordSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Lich)
                {
                    SetEnemySpells(LichSpells);
                }
                else if (careerIndex == (int)MonsterCareers.AncientLich)
                {
                    SetEnemySpells(AncientLichSpells);
                }
            }
            else if (entityType == EntityTypes.EnemyClass && (mobileEnemy.CastsMagic))
            {
                int spellListLevel = level / 3;
                if (spellListLevel > 6)
                {
                    spellListLevel = 6;
                }
                SetEnemySpells(EnemyClassSpells[spellListLevel]);
            }

            // Chance of adding map
            DaggerfallLoot.RandomlyAddMap(mobileEnemy.MapChance, items);

            if (!string.IsNullOrEmpty(mobileEnemy.LootTableKey))
            {
                // Chance of adding potion
                DaggerfallLoot.RandomlyAddPotion(3, items);
                // Chance of adding potion recipe
                DaggerfallLoot.RandomlyAddPotionRecipe(2, items);
            }

            OnLootSpawned?.Invoke(this, new EnemyLootSpawnedEventArgs {
                MobileEnemy = mobileEnemy, EnemyCareer = career, Items = items
            });

            FillVitalSigns();
        }
        string[] GetClassSpecials()
        {
            List <string> specials = new List <string>();
            DFCareer      career   = GameManager.Instance.PlayerEntity.Career;
            RaceTemplate  race     = GameManager.Instance.PlayerEntity.RaceTemplate;

            // Tolerances
            Dictionary <DFCareer.Tolerance, string> tolerances = new Dictionary <DFCareer.Tolerance, string>
            {
                { DFCareer.Tolerance.CriticalWeakness, TextManager.Instance.GetLocalizedText(HardStrings.criticalWeakness) },
                { DFCareer.Tolerance.Immune, TextManager.Instance.GetLocalizedText(HardStrings.immunity) },
                { DFCareer.Tolerance.LowTolerance, TextManager.Instance.GetLocalizedText(HardStrings.lowTolerance) },
                { DFCareer.Tolerance.Resistant, TextManager.Instance.GetLocalizedText(HardStrings.resistance) }
            };

            if (career.Paralysis != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Paralysis] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toParalysis));
            }

            if (career.Magic != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Magic] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toMagic));
            }

            if (career.Poison != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Poison] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toPoison));
            }

            if (career.Fire != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Fire] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toFire));
            }

            if (career.Frost != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Frost] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toFrost));
            }

            if (career.Shock != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Shock] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toShock));
            }

            if (career.Disease != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Disease] + " " + TextManager.Instance.GetLocalizedText(HardStrings.toDisease));
            }

            // Weapon Proficiencies
            Dictionary <DFCareer.Proficiency, string> profs = new Dictionary <DFCareer.Proficiency, string>
            {
                { DFCareer.Proficiency.Expert, TextManager.Instance.GetLocalizedText(HardStrings.expertiseIn) },
                { DFCareer.Proficiency.Forbidden, TextManager.Instance.GetLocalizedText(HardStrings.forbiddenWeaponry) }
            };

            if (career.ShortBlades != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.ShortBlades] + " " + TextManager.Instance.GetLocalizedText(HardStrings.shortBlade));
            }

            if (career.LongBlades != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.LongBlades] + " " + TextManager.Instance.GetLocalizedText(HardStrings.longBlade));
            }

            if (career.HandToHand != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.HandToHand] + " " + TextManager.Instance.GetLocalizedText(HardStrings.handToHand));
            }

            if (career.Axes != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.Axes] + " " + TextManager.Instance.GetLocalizedText(HardStrings.axe));
            }

            if (career.BluntWeapons != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.BluntWeapons] + " " + TextManager.Instance.GetLocalizedText(HardStrings.bluntWeapon));
            }

            if (career.MissileWeapons != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.MissileWeapons] + " " + TextManager.Instance.GetLocalizedText(HardStrings.missileWeapon));
            }

            // Attack modifiers
            Dictionary <DFCareer.AttackModifier, string> atkMods = new Dictionary <DFCareer.AttackModifier, string>
            {
                { DFCareer.AttackModifier.Bonus, TextManager.Instance.GetLocalizedText(HardStrings.bonusToHit) },
                { DFCareer.AttackModifier.Phobia, TextManager.Instance.GetLocalizedText(HardStrings.phobia) }
            };

            if (career.UndeadAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.UndeadAttackModifier] + " " + TextManager.Instance.GetLocalizedText(HardStrings.undead));
            }

            if (career.DaedraAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.DaedraAttackModifier] + " " + TextManager.Instance.GetLocalizedText(HardStrings.daedra));
            }

            if (career.HumanoidAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.HumanoidAttackModifier] + " " + TextManager.Instance.GetLocalizedText(HardStrings.humanoid));
            }

            if (career.AnimalsAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.AnimalsAttackModifier] + " " + TextManager.Instance.GetLocalizedText(HardStrings.animals));
            }

            // Darkness/light powered magery
            if (career.DarknessPoweredMagery != DFCareer.DarknessMageryFlags.Normal)
            {
                if ((career.DarknessPoweredMagery & DFCareer.DarknessMageryFlags.ReducedPowerInLight) == DFCareer.DarknessMageryFlags.ReducedPowerInLight)
                {
                    specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.darknessPoweredMagery) + " " + TextManager.Instance.GetLocalizedText(HardStrings.lowerMagicAbilityDaylight));
                }
                if ((career.DarknessPoweredMagery & DFCareer.DarknessMageryFlags.UnableToCastInLight) == DFCareer.DarknessMageryFlags.UnableToCastInLight)
                {
                    specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.darknessPoweredMagery) + " " + TextManager.Instance.GetLocalizedText(HardStrings.unableToUseMagicInDaylight));
                }
            }

            if (career.LightPoweredMagery != DFCareer.LightMageryFlags.Normal)
            {
                if ((career.LightPoweredMagery & DFCareer.LightMageryFlags.ReducedPowerInDarkness) == DFCareer.LightMageryFlags.ReducedPowerInDarkness)
                {
                    specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.lightPoweredMagery) + " " + TextManager.Instance.GetLocalizedText(HardStrings.lowerMagicAbilityDarkness));
                }
                if ((career.LightPoweredMagery & DFCareer.LightMageryFlags.UnableToCastInDarkness) == DFCareer.LightMageryFlags.UnableToCastInDarkness)
                {
                    specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.lightPoweredMagery) + " " + TextManager.Instance.GetLocalizedText(HardStrings.unableToUseMagicInDarkness));
                }
            }

            // Forbidden materials (multiple)
            if (career.ForbiddenMaterials != 0)
            {
                Dictionary <DFCareer.MaterialFlags, string> forbMaterials = new Dictionary <DFCareer.MaterialFlags, string>
                {
                    { DFCareer.MaterialFlags.Adamantium, TextManager.Instance.GetLocalizedText(HardStrings.adamantium) },
                    { DFCareer.MaterialFlags.Daedric, TextManager.Instance.GetLocalizedText(HardStrings.daedric) },
                    { DFCareer.MaterialFlags.Dwarven, TextManager.Instance.GetLocalizedText(HardStrings.dwarven) },
                    { DFCareer.MaterialFlags.Ebony, TextManager.Instance.GetLocalizedText(HardStrings.ebony) },
                    { DFCareer.MaterialFlags.Elven, TextManager.Instance.GetLocalizedText(HardStrings.elven) },
                    { DFCareer.MaterialFlags.Iron, TextManager.Instance.GetLocalizedText(HardStrings.iron) },
                    { DFCareer.MaterialFlags.Mithril, TextManager.Instance.GetLocalizedText(HardStrings.mithril) },
                    { DFCareer.MaterialFlags.Orcish, TextManager.Instance.GetLocalizedText(HardStrings.orcish) },
                    { DFCareer.MaterialFlags.Silver, TextManager.Instance.GetLocalizedText(HardStrings.silver) },
                    { DFCareer.MaterialFlags.Steel, TextManager.Instance.GetLocalizedText(HardStrings.steel) }
                };
                foreach (DFCareer.MaterialFlags flag in Enum.GetValues(typeof(DFCareer.MaterialFlags)))
                {
                    if ((career.ForbiddenMaterials & flag) == flag)
                    {
                        specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.forbiddenMaterial) + " " + forbMaterials[flag]);
                    }
                }
            }

            // Forbidden shields (multiple)
            if (career.ForbiddenShields != 0)
            {
                Dictionary <DFCareer.ShieldFlags, string> forbShields = new Dictionary <DFCareer.ShieldFlags, string>
                {
                    { DFCareer.ShieldFlags.Buckler, TextManager.Instance.GetLocalizedText(HardStrings.buckler) },
                    { DFCareer.ShieldFlags.KiteShield, TextManager.Instance.GetLocalizedText(HardStrings.kiteShield) },
                    { DFCareer.ShieldFlags.RoundShield, TextManager.Instance.GetLocalizedText(HardStrings.roundShield) },
                    { DFCareer.ShieldFlags.TowerShield, TextManager.Instance.GetLocalizedText(HardStrings.towerShield) }
                };
                foreach (DFCareer.ShieldFlags flag in Enum.GetValues(typeof(DFCareer.ShieldFlags)))
                {
                    if ((career.ForbiddenShields & flag) == flag)
                    {
                        specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.forbiddenShieldTypes) + " " + forbShields[flag]);
                    }
                }
            }

            // Forbidden armor (multiple)
            if (career.ForbiddenArmors != 0)
            {
                Dictionary <DFCareer.ArmorFlags, string> forbArmors = new Dictionary <DFCareer.ArmorFlags, string>
                {
                    { DFCareer.ArmorFlags.Chain, TextManager.Instance.GetLocalizedText(HardStrings.chain) },
                    { DFCareer.ArmorFlags.Leather, TextManager.Instance.GetLocalizedText(HardStrings.leather) },
                    { DFCareer.ArmorFlags.Plate, TextManager.Instance.GetLocalizedText(HardStrings.plate) }
                };
                foreach (DFCareer.ArmorFlags flag in Enum.GetValues(typeof(DFCareer.ArmorFlags)))
                {
                    if ((career.ForbiddenArmors & flag) == flag)
                    {
                        specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.forbiddenArmorType) + " " + forbArmors[flag]);
                    }
                }
            }

            // Forbidden proficiencies (flags)
            // Expert proficiencies (flags)
            // Omitted - redundant

            // Spell point multiplier
            if (career.SpellPointMultiplier != DFCareer.SpellPointMultipliers.Times_0_50)
            {
                Dictionary <DFCareer.SpellPointMultipliers, string> spellPtMults = new Dictionary <DFCareer.SpellPointMultipliers, string>
                {
                    { DFCareer.SpellPointMultipliers.Times_1_00, TextManager.Instance.GetLocalizedText(HardStrings.intInSpellPoints) },
                    { DFCareer.SpellPointMultipliers.Times_1_50, TextManager.Instance.GetLocalizedText(HardStrings.intInSpellPoints15) },
                    { DFCareer.SpellPointMultipliers.Times_1_75, TextManager.Instance.GetLocalizedText(HardStrings.intInSpellPoints175) },
                    { DFCareer.SpellPointMultipliers.Times_2_00, TextManager.Instance.GetLocalizedText(HardStrings.intInSpellPoints2) },
                    { DFCareer.SpellPointMultipliers.Times_3_00, TextManager.Instance.GetLocalizedText(HardStrings.intInSpellPoints3) },
                };
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.increasedMagery) + " " + spellPtMults[career.SpellPointMultiplier]);
            }

            // Spell absorption
            if (career.SpellAbsorption != DFCareer.SpellAbsorptionFlags.None)
            {
                Dictionary <DFCareer.SpellAbsorptionFlags, string> absorbConds = new Dictionary <DFCareer.SpellAbsorptionFlags, string>
                {
                    { DFCareer.SpellAbsorptionFlags.Always, TextManager.Instance.GetLocalizedText(HardStrings.general) },
                    { DFCareer.SpellAbsorptionFlags.InDarkness, TextManager.Instance.GetLocalizedText(HardStrings.inDarkness) },
                    { DFCareer.SpellAbsorptionFlags.InLight, TextManager.Instance.GetLocalizedText(HardStrings.inLight) }
                };
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.spellAbsorption) + " " + absorbConds[career.SpellAbsorption]);
            }

            // Spell point regeneration
            if (career.NoRegenSpellPoints)
            {
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.inabilityToRegen));
            }

            // Talents
            if (career.AcuteHearing)
            {
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.acuteHearing));
            }

            if (career.Athleticism)
            {
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.athleticism));
            }

            if (career.AdrenalineRush)
            {
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.adrenalineRush));
            }

            // Regeneration and rapid healing
            if (career.Regeneration != DFCareer.RegenerationFlags.None)
            {
                Dictionary <DFCareer.RegenerationFlags, string> regenConds = new Dictionary <DFCareer.RegenerationFlags, string>
                {
                    { DFCareer.RegenerationFlags.Always, TextManager.Instance.GetLocalizedText(HardStrings.general) },
                    { DFCareer.RegenerationFlags.InDarkness, TextManager.Instance.GetLocalizedText(HardStrings.inDarkness) },
                    { DFCareer.RegenerationFlags.InLight, TextManager.Instance.GetLocalizedText(HardStrings.inLight) },
                    { DFCareer.RegenerationFlags.InWater, TextManager.Instance.GetLocalizedText(HardStrings.whileImmersed) }
                };
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.regenerateHealth) + " " + regenConds[career.Regeneration]);
            }

            if (career.RapidHealing != DFCareer.RapidHealingFlags.None)
            {
                Dictionary <DFCareer.RapidHealingFlags, string> rapidHealingConds = new Dictionary <DFCareer.RapidHealingFlags, string>
                {
                    { DFCareer.RapidHealingFlags.Always, TextManager.Instance.GetLocalizedText(HardStrings.general) },
                    { DFCareer.RapidHealingFlags.InDarkness, TextManager.Instance.GetLocalizedText(HardStrings.inDarkness) },
                    { DFCareer.RapidHealingFlags.InLight, TextManager.Instance.GetLocalizedText(HardStrings.inLight) }
                };
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.rapidHealing) + " " + rapidHealingConds[career.RapidHealing]);
            }

            // Damage
            if (career.DamageFromSunlight)
            {
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.damage) + " " + TextManager.Instance.GetLocalizedText(HardStrings.fromSunlight));
            }

            if (career.DamageFromHolyPlaces)
            {
                specials.Add(TextManager.Instance.GetLocalizedText(HardStrings.damage) + " " + TextManager.Instance.GetLocalizedText(HardStrings.fromHolyPlaces));
            }

            // Add racial tolerances and abilities
            Dictionary <DFCareer.EffectFlags, string> raceEffectMods = new Dictionary <DFCareer.EffectFlags, string>
            {
                { DFCareer.EffectFlags.Paralysis, TextManager.Instance.GetLocalizedText(HardStrings.toParalysis) },
                { DFCareer.EffectFlags.Magic, TextManager.Instance.GetLocalizedText(HardStrings.toMagic) },
                { DFCareer.EffectFlags.Poison, TextManager.Instance.GetLocalizedText(HardStrings.toPoison) },
                { DFCareer.EffectFlags.Fire, TextManager.Instance.GetLocalizedText(HardStrings.toFire) },
                { DFCareer.EffectFlags.Frost, TextManager.Instance.GetLocalizedText(HardStrings.toFrost) },
                { DFCareer.EffectFlags.Shock, TextManager.Instance.GetLocalizedText(HardStrings.toShock) },
                { DFCareer.EffectFlags.Disease, TextManager.Instance.GetLocalizedText(HardStrings.toDisease) },
            };

            foreach (DFCareer.EffectFlags effectFlag in Enum.GetValues(typeof(DFCareer.EffectFlags)))
            {
                if (effectFlag != DFCareer.EffectFlags.None)
                {
                    // Resistances
                    if ((race.ResistanceFlags & effectFlag) == effectFlag)
                    {
                        string toAdd = TextManager.Instance.GetLocalizedText(HardStrings.resistance) + " " + raceEffectMods[effectFlag];
                        if (!specials.Contains(toAdd)) // prevent duplicates from career
                        {
                            specials.Add(toAdd);
                        }
                    }
                    // Immunities
                    if ((race.ImmunityFlags & effectFlag) == effectFlag)
                    {
                        string toAdd = TextManager.Instance.GetLocalizedText(HardStrings.immunity) + " " + raceEffectMods[effectFlag];
                        if (!specials.Contains(toAdd))
                        {
                            specials.Add(toAdd);
                        }
                    }
                    // Low tolerances
                    if ((race.LowToleranceFlags & effectFlag) == effectFlag)
                    {
                        string toAdd = TextManager.Instance.GetLocalizedText(HardStrings.lowTolerance) + " " + raceEffectMods[effectFlag];
                        if (!specials.Contains(toAdd))
                        {
                            specials.Add(toAdd);
                        }
                    }
                    // Critical weaknesses
                    if ((race.CriticalWeaknessFlags & effectFlag) == effectFlag)
                    {
                        string toAdd = TextManager.Instance.GetLocalizedText(HardStrings.criticalWeakness) + " " + raceEffectMods[effectFlag];
                        if (!specials.Contains(toAdd))
                        {
                            specials.Add(toAdd);
                        }
                    }
                }
            }

            Dictionary <DFCareer.SpecialAbilityFlags, string> raceAbilities = new Dictionary <DFCareer.SpecialAbilityFlags, string>
            {
                { DFCareer.SpecialAbilityFlags.AcuteHearing, TextManager.Instance.GetLocalizedText(HardStrings.acuteHearing) },
                { DFCareer.SpecialAbilityFlags.Athleticism, TextManager.Instance.GetLocalizedText(HardStrings.acuteHearing) },
                { DFCareer.SpecialAbilityFlags.AdrenalineRush, TextManager.Instance.GetLocalizedText(HardStrings.adrenalineRush) },
                { DFCareer.SpecialAbilityFlags.NoRegenSpellPoints, TextManager.Instance.GetLocalizedText(HardStrings.inabilityToRegen) },
                { DFCareer.SpecialAbilityFlags.SunDamage, TextManager.Instance.GetLocalizedText(HardStrings.damage) + " " + TextManager.Instance.GetLocalizedText(HardStrings.fromSunlight) },
                { DFCareer.SpecialAbilityFlags.HolyDamage, TextManager.Instance.GetLocalizedText(HardStrings.damage) + " " + TextManager.Instance.GetLocalizedText(HardStrings.fromHolyPlaces) }
            };

            foreach (DFCareer.SpecialAbilityFlags abilityFlag in Enum.GetValues(typeof(DFCareer.SpecialAbilityFlags)))
            {
                if (abilityFlag != DFCareer.SpecialAbilityFlags.None && (race.SpecialAbilities & abilityFlag) == abilityFlag)
                {
                    string toAdd = raceAbilities[abilityFlag];
                    if (!specials.Contains(toAdd))
                    {
                        specials.Add(toAdd);
                    }
                }
            }

            return(specials.ToArray());
        }
Example #24
0
        /// <summary>
        /// Sets enemy career and prepares entity settings.
        /// </summary>
        public void SetEnemyCareer(MobileEnemy mobileEnemy, EntityTypes entityType)
        {
            if (entityType == EntityTypes.EnemyMonster)
            {
                careerIndex = mobileEnemy.ID;
                career      = GetMonsterCareerTemplate((MonsterCareers)careerIndex);
                stats.SetPermanentFromCareer(career);

                // Enemy monster has predefined level, health and armor values.
                // Armor values can be modified below by equipment.
                level     = mobileEnemy.Level;
                maxHealth = UnityEngine.Random.Range(mobileEnemy.MinHealth, mobileEnemy.MaxHealth + 1);
                for (int i = 0; i < ArmorValues.Length; i++)
                {
                    ArmorValues[i] = (sbyte)(mobileEnemy.ArmorValue * 5);
                }
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                careerIndex = mobileEnemy.ID - 128;
                career      = GetClassCareerTemplate((ClassCareers)careerIndex);
                stats.SetPermanentFromCareer(career); // I may have a better way to alter the attributes of individual enemy entities, this seems to be where it originates from, will possibly alter later on.

                // Enemy class is levelled to player and uses similar health rules
                // City guards are 3 to 6 levels above the player
                //level = GameManager.Instance.PlayerEntity.Level; // Definitely going to want to mess with this a lot eventually, this is apparently what makes the human enemies equal to the player level, will alter that.
                level = UnityEngine.Random.Range(1, 31);
                if (careerIndex == (int)MobileTypes.Knight_CityWatch)
                {
                    level += UnityEngine.Random.Range(3, 7);
                }

                maxHealth = FormulaHelper.RollEnemyClassMaxHealth(level, career.HitPointsPerLevel);
            }
            else
            {
                career      = new DFCareer();
                careerIndex = -1;
                return;
            }

            this.mobileEnemy = mobileEnemy;
            this.entityType  = entityType;
            name             = career.Name;
            minMetalToHit    = mobileEnemy.MinMetalToHit;
            team             = mobileEnemy.Team;

            short skillsLevel = (short)((level * 5) + 30);

            if (skillsLevel > 100)
            {
                skillsLevel = 100;
            }

            for (int i = 0; i <= DaggerfallSkills.Count; i++)
            {
                skills.SetPermanentSkillValue(i, skillsLevel);
            }

            int[] personalityTraits = DaggerfallWorkshop.Utility.EnemyBasics.EnemyPersonalityTraitGenerator(this);
            // May put the method for the "context based" inventory modifiers here, but first i'll have to figure out how i'm going to do that exactly first.

            DaggerfallLoot.GenerateEnemyItems(items, personalityTraits, this);

            // Enemy classes and some monsters use equipment
            if (EquipmentUser())
            {
                SetEnemyEquipment(personalityTraits);
            }

            // Assign spell lists
            if (entityType == EntityTypes.EnemyMonster)
            {
                if (careerIndex == (int)MonsterCareers.Imp)
                {
                    SetEnemySpells(ImpSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Ghost)
                {
                    SetEnemySpells(GhostSpells);
                }
                else if (careerIndex == (int)MonsterCareers.OrcShaman)
                {
                    SetEnemySpells(OrcShamanSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Wraith)
                {
                    SetEnemySpells(WraithSpells);
                }
                else if (careerIndex == (int)MonsterCareers.FrostDaedra)
                {
                    SetEnemySpells(FrostDaedraSpells);
                }
                else if (careerIndex == (int)MonsterCareers.FireDaedra)
                {
                    SetEnemySpells(FireDaedraSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Daedroth)
                {
                    SetEnemySpells(DaedrothSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Vampire)
                {
                    SetEnemySpells(VampireSpells);
                }
                else if (careerIndex == (int)MonsterCareers.DaedraSeducer)
                {
                    SetEnemySpells(SeducerSpells);
                }
                else if (careerIndex == (int)MonsterCareers.VampireAncient)
                {
                    SetEnemySpells(VampireAncientSpells);
                }
                else if (careerIndex == (int)MonsterCareers.DaedraLord)
                {
                    SetEnemySpells(DaedraLordSpells);
                }
                else if (careerIndex == (int)MonsterCareers.Lich)
                {
                    SetEnemySpells(LichSpells);
                }
                else if (careerIndex == (int)MonsterCareers.AncientLich)
                {
                    SetEnemySpells(AncientLichSpells);
                }
            }
            else if (entityType == EntityTypes.EnemyClass && (mobileEnemy.CastsMagic))
            {
                int spellListLevel = level / 3;
                if (spellListLevel > 6)
                {
                    spellListLevel = 6;
                }
                SetEnemySpells(EnemyClassSpells[spellListLevel]);
            }

            FillVitalSigns(); // Could use this to set enemies health and other vitals at a lower level when they first spawn, to simulate them being already wounded or something.
        }
        void ReadFile(BinaryReader reader)
        {
            // Read class resist, etc. flags
            DFCareer.CFGData cfg = new DFCareer.CFGData();
            cfg.ResistanceFlags = reader.ReadByte();
            cfg.ImmunityFlags = reader.ReadByte();
            cfg.LowToleranceFlags = reader.ReadByte();
            cfg.CriticalWeaknessFlags = reader.ReadByte();

            // Read class special ability and spell point bitfield
            cfg.AbilityFlagsAndSpellPointsBitfield = reader.ReadUInt16();

            // Read rapid healing flags
            cfg.RapidHealing = reader.ReadByte();

            // Read regeneration flags
            cfg.Regeneration = reader.ReadByte();

            // Unknown value
            cfg.Unknown1 = reader.ReadByte();

            // Spell absorption flags
            cfg.SpellAbsorptionFlags = reader.ReadByte();

            // Attack modifier against major enemy groups
            cfg.AttackModifierFlags = reader.ReadByte();

            // Read forbidden material flags
            cfg.ForbiddenMaterialsFlags = reader.ReadUInt16();

            // Read weapon, armor, shields bitfield
            Byte a = reader.ReadByte();
            Byte b = reader.ReadByte();
            Byte c = reader.ReadByte();
            cfg.WeaponArmorShieldsBitfield = (UInt32)((a << 16) | (c << 8) | b);

            // Read primary skills
            cfg.PrimarySkill1 = reader.ReadByte();
            cfg.PrimarySkill2 = reader.ReadByte();
            cfg.PrimarySkill3 = reader.ReadByte();

            // Read major skills
            cfg.MajorSkill1 = reader.ReadByte();
            cfg.MajorSkill2 = reader.ReadByte();
            cfg.MajorSkill3 = reader.ReadByte();

            // Read minor skills
            cfg.MinorSkill1 = reader.ReadByte();
            cfg.MinorSkill2 = reader.ReadByte();
            cfg.MinorSkill3 = reader.ReadByte();
            cfg.MinorSkill4 = reader.ReadByte();
            cfg.MinorSkill5 = reader.ReadByte();
            cfg.MinorSkill6 = reader.ReadByte();

            // Read class name
            cfg.Name = file.ReadCStringSkip(reader, 0, 16);

            // Read 8 unknown bytes
            cfg.Unknown2 = reader.ReadBytes(8);

            // Hit points per level
            cfg.HitPointsPerLevelOrMonsterLevel = reader.ReadUInt16();

            // Read advancement multiplier
            cfg.AdvancementMultiplier = reader.ReadUInt32();

            // Read attributes
            cfg.Attributes = new UInt16[8];
            for (int i = 0; i < 8; i++)
            {
                cfg.Attributes[i] = reader.ReadUInt16();
            }

            // Structure data
            career = new DFCareer(cfg);
        }
        public static int GetClassAffinityIndex(DFCareer custom, List <DFCareer> classes)
        {
            int highestAffinity = 0;
            int selectedIndex   = 0;

            for (int i = 0; i < classes.Count; i++)
            {
                int affinity = 0;
                List <DFCareer.Skills> classSkills = new List <DFCareer.Skills>();
                classSkills.Add(classes[i].PrimarySkill1);
                classSkills.Add(classes[i].PrimarySkill2);
                classSkills.Add(classes[i].PrimarySkill3);
                classSkills.Add(classes[i].MajorSkill1);
                classSkills.Add(classes[i].MajorSkill2);
                classSkills.Add(classes[i].MajorSkill3);
                classSkills.Add(classes[i].MinorSkill1);
                classSkills.Add(classes[i].MinorSkill2);
                classSkills.Add(classes[i].MinorSkill3);
                classSkills.Add(classes[i].MinorSkill4);
                classSkills.Add(classes[i].MinorSkill5);
                classSkills.Add(classes[i].MinorSkill6);
                if (classSkills.Contains(custom.PrimarySkill1))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.PrimarySkill2))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.PrimarySkill3))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MajorSkill1))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MajorSkill2))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MajorSkill3))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MinorSkill1))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MinorSkill2))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MinorSkill3))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MinorSkill4))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MinorSkill5))
                {
                    affinity++;
                }
                if (classSkills.Contains(custom.MinorSkill6))
                {
                    affinity++;
                }
                if (affinity > highestAffinity)
                {
                    highestAffinity = affinity;
                    selectedIndex   = i;
                }
            }

            return(selectedIndex);
        }
        void ReadFile(BinaryReader reader)
        {
            // Read class resist, etc. flags
            DFCareer.CFGData cfg = new DFCareer.CFGData();
            cfg.ResistanceFlags       = reader.ReadByte();
            cfg.ImmunityFlags         = reader.ReadByte();
            cfg.LowToleranceFlags     = reader.ReadByte();
            cfg.CriticalWeaknessFlags = reader.ReadByte();

            // Read class special ability and spell point bitfield
            cfg.AbilityFlagsAndSpellPointsBitfield = reader.ReadUInt16();

            // Read rapid healing flags
            cfg.RapidHealing = reader.ReadByte();

            // Read regeneration flags
            cfg.Regeneration = reader.ReadByte();

            // Unknown value
            cfg.Unknown1 = reader.ReadByte();

            // Spell absorption flags
            cfg.SpellAbsorptionFlags = reader.ReadByte();

            // Attack modifier against major enemy groups
            cfg.AttackModifierFlags = reader.ReadByte();

            // Read forbidden material flags
            cfg.ForbiddenMaterialsFlags = reader.ReadUInt16();

            // Read weapon, armor, shields bitfield
            Byte a = reader.ReadByte();
            Byte b = reader.ReadByte();
            Byte c = reader.ReadByte();

            cfg.WeaponArmorShieldsBitfield = (UInt32)((a << 16) | (c << 8) | b);

            // Read primary skills
            cfg.PrimarySkill1 = reader.ReadByte();
            cfg.PrimarySkill2 = reader.ReadByte();
            cfg.PrimarySkill3 = reader.ReadByte();

            // Read major skills
            cfg.MajorSkill1 = reader.ReadByte();
            cfg.MajorSkill2 = reader.ReadByte();
            cfg.MajorSkill3 = reader.ReadByte();

            // Read minor skills
            cfg.MinorSkill1 = reader.ReadByte();
            cfg.MinorSkill2 = reader.ReadByte();
            cfg.MinorSkill3 = reader.ReadByte();
            cfg.MinorSkill4 = reader.ReadByte();
            cfg.MinorSkill5 = reader.ReadByte();
            cfg.MinorSkill6 = reader.ReadByte();

            // Read class name
            cfg.Name = file.ReadCStringSkip(reader, 0, 16);

            // Read 8 unknown bytes
            cfg.Unknown2 = reader.ReadBytes(8);

            // Hit points per level
            cfg.HitPointsPerLevel = reader.ReadUInt16();

            // Read advancement multiplier
            cfg.AdvancementMultiplier = reader.ReadUInt32();

            // Read attributes
            cfg.Attributes = new UInt16[8];
            for (int i = 0; i < 8; i++)
            {
                cfg.Attributes[i] = reader.ReadUInt16();
            }

            // Structure data
            career = new DFCareer(cfg);
        }
Example #28
0
        string[] GetClassSpecials()
        {
            List <string> specials = new List <string>();
            DFCareer      career   = GameManager.Instance.PlayerEntity.Career;

            // Tolerances
            Dictionary <DFCareer.Tolerance, string> tolerances = new Dictionary <DFCareer.Tolerance, string>
            {
                { DFCareer.Tolerance.CriticalWeakness, HardStrings.criticalWeakness },
                { DFCareer.Tolerance.Immune, HardStrings.immunity },
                { DFCareer.Tolerance.LowTolerance, HardStrings.lowTolerance },
                { DFCareer.Tolerance.Resistant, HardStrings.resistance }
            };

            if (career.Paralysis != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Paralysis] + " " + HardStrings.toParalysis);
            }

            if (career.Magic != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Magic] + " " + HardStrings.toMagic);
            }

            if (career.Poison != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Poison] + " " + HardStrings.toPoison);
            }

            if (career.Fire != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Fire] + " " + HardStrings.toFire);
            }

            if (career.Frost != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Frost] + " " + HardStrings.toFrost);
            }

            if (career.Shock != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Shock] + " " + HardStrings.toShock);
            }

            if (career.Disease != DFCareer.Tolerance.Normal)
            {
                specials.Add(tolerances[career.Disease] + " " + HardStrings.toDisease);
            }

            // Weapon Proficiencies
            Dictionary <DFCareer.Proficiency, string> profs = new Dictionary <DFCareer.Proficiency, string>
            {
                { DFCareer.Proficiency.Expert, HardStrings.expertiseIn },
                { DFCareer.Proficiency.Forbidden, HardStrings.forbiddenWeaponry }
            };

            if (career.ShortBlades != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.ShortBlades] + " " + HardStrings.shortBlade);
            }

            if (career.LongBlades != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.LongBlades] + " " + HardStrings.longBlade);
            }

            if (career.HandToHand != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.HandToHand] + " " + HardStrings.handToHand);
            }

            if (career.Axes != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.Axes] + " " + HardStrings.axe);
            }

            if (career.BluntWeapons != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.BluntWeapons] + " " + HardStrings.bluntWeapon);
            }

            if (career.MissileWeapons != DFCareer.Proficiency.Normal)
            {
                specials.Add(profs[career.MissileWeapons] + " " + HardStrings.missileWeapon);
            }

            // Attack modifiers
            Dictionary <DFCareer.AttackModifier, string> atkMods = new Dictionary <DFCareer.AttackModifier, string>
            {
                { DFCareer.AttackModifier.Bonus, HardStrings.bonusToHit },
                { DFCareer.AttackModifier.Phobia, HardStrings.phobia }
            };

            if (career.UndeadAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.UndeadAttackModifier] + " " + HardStrings.undead);
            }

            if (career.DaedraAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.DaedraAttackModifier] + " " + HardStrings.daedra);
            }

            if (career.HumanoidAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.HumanoidAttackModifier] + " " + HardStrings.humanoid);
            }

            if (career.AnimalsAttackModifier != DFCareer.AttackModifier.Normal)
            {
                specials.Add(atkMods[career.AnimalsAttackModifier] + " " + HardStrings.animals);
            }

            // Darkness/light powered magery
            if (career.DarknessPoweredMagery != DFCareer.DarknessMageryFlags.Normal)
            {
                if ((career.DarknessPoweredMagery & DFCareer.DarknessMageryFlags.ReducedPowerInLight) == DFCareer.DarknessMageryFlags.ReducedPowerInLight)
                {
                    specials.Add(HardStrings.darknessPoweredMagery + " " + HardStrings.lowerMagicAbilityDaylight);
                }
                if ((career.DarknessPoweredMagery & DFCareer.DarknessMageryFlags.UnableToCastInLight) == DFCareer.DarknessMageryFlags.UnableToCastInLight)
                {
                    specials.Add(HardStrings.darknessPoweredMagery + " " + HardStrings.unableToUseMagicInDaylight);
                }
            }

            if (career.LightPoweredMagery != DFCareer.LightMageryFlags.Normal)
            {
                if ((career.LightPoweredMagery & DFCareer.LightMageryFlags.ReducedPowerInDarkness) == DFCareer.LightMageryFlags.ReducedPowerInDarkness)
                {
                    specials.Add(HardStrings.lightPoweredMagery + " " + HardStrings.lowerMagicAbilityDarkness);
                }
                if ((career.LightPoweredMagery & DFCareer.LightMageryFlags.UnableToCastInDarkness) == DFCareer.LightMageryFlags.UnableToCastInDarkness)
                {
                    specials.Add(HardStrings.lightPoweredMagery + " " + HardStrings.unableToUseMagicInDarkness);
                }
            }

            // Forbidden materials (multiple)
            if (career.ForbiddenMaterials != 0)
            {
                Dictionary <DFCareer.MaterialFlags, string> forbMaterials = new Dictionary <DFCareer.MaterialFlags, string>
                {
                    { DFCareer.MaterialFlags.Adamantium, HardStrings.adamantium },
                    { DFCareer.MaterialFlags.Daedric, HardStrings.daedric },
                    { DFCareer.MaterialFlags.Dwarven, HardStrings.dwarven },
                    { DFCareer.MaterialFlags.Ebony, HardStrings.ebony },
                    { DFCareer.MaterialFlags.Elven, HardStrings.elven },
                    { DFCareer.MaterialFlags.Iron, HardStrings.iron },
                    { DFCareer.MaterialFlags.Mithril, HardStrings.mithril },
                    { DFCareer.MaterialFlags.Orcish, HardStrings.orcish },
                    { DFCareer.MaterialFlags.Silver, HardStrings.silver },
                    { DFCareer.MaterialFlags.Steel, HardStrings.steel }
                };
                foreach (DFCareer.MaterialFlags flag in Enum.GetValues(typeof(DFCareer.MaterialFlags)))
                {
                    if ((career.ForbiddenMaterials & flag) == flag)
                    {
                        specials.Add(HardStrings.forbiddenMaterial + " " + forbMaterials[flag]);
                    }
                }
            }

            // Forbidden shields (multiple)
            if (career.ForbiddenShields != 0)
            {
                Dictionary <DFCareer.ShieldFlags, string> forbShields = new Dictionary <DFCareer.ShieldFlags, string>
                {
                    { DFCareer.ShieldFlags.Buckler, HardStrings.buckler },
                    { DFCareer.ShieldFlags.KiteShield, HardStrings.kiteShield },
                    { DFCareer.ShieldFlags.RoundShield, HardStrings.roundShield },
                    { DFCareer.ShieldFlags.TowerShield, HardStrings.towerShield }
                };
                foreach (DFCareer.ShieldFlags flag in Enum.GetValues(typeof(DFCareer.ShieldFlags)))
                {
                    if ((career.ForbiddenShields & flag) == flag)
                    {
                        specials.Add(HardStrings.forbiddenShieldTypes + " " + forbShields[flag]);
                    }
                }
            }

            // Forbidden armor (multiple)
            if (career.ForbiddenArmors != 0)
            {
                Dictionary <DFCareer.ArmorFlags, string> forbArmors = new Dictionary <DFCareer.ArmorFlags, string>
                {
                    { DFCareer.ArmorFlags.Chain, HardStrings.chain },
                    { DFCareer.ArmorFlags.Leather, HardStrings.leather },
                    { DFCareer.ArmorFlags.Plate, HardStrings.plate }
                };
                foreach (DFCareer.ArmorFlags flag in Enum.GetValues(typeof(DFCareer.ArmorFlags)))
                {
                    if ((career.ForbiddenArmors & flag) == flag)
                    {
                        specials.Add(HardStrings.forbiddenArmorType + " " + forbArmors[flag]);
                    }
                }
            }

            // Forbidden proficiencies (flags)
            // Expert proficiencies (flags)
            // Omitted - redundant

            // Spell point multiplier
            if (career.SpellPointMultiplier != DFCareer.SpellPointMultipliers.Times_0_50)
            {
                Dictionary <DFCareer.SpellPointMultipliers, string> spellPtMults = new Dictionary <DFCareer.SpellPointMultipliers, string>
                {
                    { DFCareer.SpellPointMultipliers.Times_1_00, HardStrings.intInSpellPoints },
                    { DFCareer.SpellPointMultipliers.Times_1_50, HardStrings.intInSpellPoints15 },
                    { DFCareer.SpellPointMultipliers.Times_1_75, HardStrings.intInSpellPoints175 },
                    { DFCareer.SpellPointMultipliers.Times_2_00, HardStrings.intInSpellPoints2 },
                    { DFCareer.SpellPointMultipliers.Times_3_00, HardStrings.intInSpellPoints3 },
                };
                specials.Add(HardStrings.increasedMagery + " " + spellPtMults[career.SpellPointMultiplier]);
            }

            // Spell absorption
            if (career.SpellAbsorption != DFCareer.SpellAbsorptionFlags.None)
            {
                Dictionary <DFCareer.SpellAbsorptionFlags, string> absorbConds = new Dictionary <DFCareer.SpellAbsorptionFlags, string>
                {
                    { DFCareer.SpellAbsorptionFlags.Always, HardStrings.general },
                    { DFCareer.SpellAbsorptionFlags.InDarkness, HardStrings.inDarkness },
                    { DFCareer.SpellAbsorptionFlags.InLight, HardStrings.inLight }
                };
                specials.Add(HardStrings.spellAbsorption + " " + absorbConds[career.SpellAbsorption]);
            }

            // Spell point regeneration
            if (career.NoRegenSpellPoints)
            {
                specials.Add(HardStrings.inabilityToRegen);
            }

            // Talents
            if (career.AcuteHearing)
            {
                specials.Add(HardStrings.acuteHearing);
            }

            if (career.Athleticism)
            {
                specials.Add(HardStrings.athleticism);
            }

            if (career.AdrenalineRush)
            {
                specials.Add(HardStrings.adrenalineRush);
            }

            // Regeneration and rapid healing
            if (career.Regeneration != DFCareer.RegenerationFlags.None)
            {
                Dictionary <DFCareer.RegenerationFlags, string> regenConds = new Dictionary <DFCareer.RegenerationFlags, string>
                {
                    { DFCareer.RegenerationFlags.Always, HardStrings.general },
                    { DFCareer.RegenerationFlags.InDarkness, HardStrings.inDarkness },
                    { DFCareer.RegenerationFlags.InLight, HardStrings.inLight },
                    { DFCareer.RegenerationFlags.InWater, HardStrings.whileImmersed }
                };
                specials.Add(HardStrings.regenerateHealth + " " + regenConds[career.Regeneration]);
            }

            if (career.RapidHealing != DFCareer.RapidHealingFlags.None)
            {
                Dictionary <DFCareer.RapidHealingFlags, string> rapidHealingConds = new Dictionary <DFCareer.RapidHealingFlags, string>
                {
                    { DFCareer.RapidHealingFlags.Always, HardStrings.general },
                    { DFCareer.RapidHealingFlags.InDarkness, HardStrings.inDarkness },
                    { DFCareer.RapidHealingFlags.InLight, HardStrings.inLight }
                };
                specials.Add(HardStrings.rapidHealing + " " + rapidHealingConds[career.RapidHealing]);
            }

            // Damage
            if (career.DamageFromSunlight)
            {
                specials.Add(HardStrings.damage + " " + HardStrings.fromSunlight);
            }

            if (career.DamageFromHolyPlaces)
            {
                specials.Add(HardStrings.damage + " " + HardStrings.fromHolyPlaces);
            }

            return(specials.ToArray());
        }
Example #29
0
 void SetClass(DFCareer dfClass)
 {
     Setup();
     this.dfClass = dfClass;
     skillsRollout.SetClassSkills(dfClass);
 }
 /// <summary>
 /// Sets the career template for a custom (ie: mod-provided) enemy type.
 /// </summary>
 /// <param name="enemyId">ID, as defined in EnemyBasics.Enemies</param>
 /// <param name="career">The custom DFCareer template to register</param>
 public static void RegisterCustomCareerTemplate(int enemyId, DFCareer career)
 {
     // Use indexer so that mods can overwrite previous values added by mods
     // ex: mod 1 provides new enemies, mod 2 rebalances them
     CustomCareerTemplates[enemyId] = career;
 }
        DFCareer PopulateCareer()
        {
            DFCareer c = new DFCareer
            {
                AcuteHearing          = false,
                AdrenalineRush        = false,
                AdvancementMultiplier = 1.546154f,
                Agility = 45,
                AnimalsAttackModifier = DFCareer.AttackModifier.Normal,
                Athleticism           = false,
                Axes                      = DFCareer.Proficiency.Normal,
                BluntWeapons              = DFCareer.Proficiency.Normal,
                DaedraAttackModifier      = DFCareer.AttackModifier.Normal,
                DamageFromHolyPlaces      = false,
                DamageFromSunlight        = false,
                DarknessPoweredMagery     = DFCareer.DarknessMageryFlags.Normal,
                Disease                   = DFCareer.Tolerance.Normal,
                Endurance                 = 40,
                Fire                      = DFCareer.Tolerance.Normal,
                ForbiddenMaterials        = (DFCareer.MaterialFlags) 0,
                Frost                     = DFCareer.Tolerance.Normal,
                HandToHand                = DFCareer.Proficiency.Normal,
                HitPointsPerLevel         = 30,
                HumanoidAttackModifier    = DFCareer.AttackModifier.Normal,
                Intelligence              = 65,
                LightPoweredMagery        = DFCareer.LightMageryFlags.Normal,
                LongBlades                = DFCareer.Proficiency.Normal,
                Luck                      = 50,
                Magic                     = DFCareer.Tolerance.Normal,
                MajorSkill1               = DFCareer.Skills.Restoration,
                MajorSkill2               = DFCareer.Skills.Archery,
                MajorSkill3               = DFCareer.Skills.ShortBlade,
                MinorSkill1               = DFCareer.Skills.Alteration,
                MinorSkill2               = DFCareer.Skills.CriticalStrike,
                MinorSkill3               = DFCareer.Skills.Medical,
                MinorSkill4               = DFCareer.Skills.Illusion,
                MinorSkill5               = DFCareer.Skills.Mysticism,
                MinorSkill6               = DFCareer.Skills.Thaumaturgy,
                MissileWeapons            = DFCareer.Proficiency.Normal,
                Name                      = "Spellsword",
                NoRegenSpellPoints        = false,
                Paralysis                 = DFCareer.Tolerance.Normal,
                Personality               = 35,
                Poison                    = DFCareer.Tolerance.Normal,
                PrimarySkill1             = DFCareer.Skills.Destruction,
                PrimarySkill2             = DFCareer.Skills.Daedric,
                PrimarySkill3             = DFCareer.Skills.LongBlade,
                RapidHealing              = DFCareer.RapidHealingFlags.None,
                Regeneration              = DFCareer.RegenerationFlags.None,
                Shock                     = DFCareer.Tolerance.Normal,
                ShortBlades               = DFCareer.Proficiency.Normal,
                Speed                     = 50,
                SpellAbsorption           = DFCareer.SpellAbsorptionFlags.None,
                SpellPointMultiplier      = DFCareer.SpellPointMultipliers.Times_0_50,
                SpellPointMultiplierValue = 0.5f,
                Strength                  = 75,
                UndeadAttackModifier      = DFCareer.AttackModifier.Normal,
                Willpower                 = 40
            };

            return(c);
        }
Example #32
0
        /// <summary>
        /// Sets enemy career and prepares entity settings.
        /// </summary>
        public void SetEnemyCareer(MobileEnemy mobileEnemy, EntityTypes entityType)
        {
            if (entityType == EntityTypes.EnemyMonster)
            {
                careerIndex = (int)mobileEnemy.ID;
                career      = GetMonsterCareerTemplate((MonsterCareers)careerIndex);
                stats.SetFromCareer(career);

                // Enemy monster has predefined level, health and armor values
                level     = mobileEnemy.Level;
                maxHealth = UnityEngine.Random.Range(mobileEnemy.MinHealth, mobileEnemy.MaxHealth + 1);

                // Monsters have the same armor value for all body parts
                for (int i = 0; i < ArmorValues.Length; i++)
                {
                    ArmorValues[i] = (sbyte)(mobileEnemy.ArmorValue * 5);
                }
            }
            else if (entityType == EntityTypes.EnemyClass)
            {
                careerIndex = (int)mobileEnemy.ID - 128;
                career      = GetClassCareerTemplate((ClassCareers)careerIndex);
                stats.SetFromCareer(career);

                // Enemy class is levelled to player and uses similar health rules
                level     = GameManager.Instance.PlayerEntity.Level;
                maxHealth = FormulaHelper.RollEnemyClassMaxHealth(level, career.HitPointsPerLevel);

                // Enemy classes may be able to equip armor. Not sure yet how classic does this.
                // For now, using fudge value of 60.
                for (int i = 0; i < ArmorValues.Length; i++)
                {
                    ArmorValues[i] = 60;
                }

                // Enemy class damage is temporarily set by a fudged level multiplier
                // This will change once full entity setup and items are available
                const float damageMultiplier = 4f;
                mobileEnemy.MinDamage = (int)(level * damageMultiplier);
                mobileEnemy.MaxDamage = (int)((level + 2) * damageMultiplier);
            }
            else
            {
                career      = new DFCareer();
                careerIndex = -1;
                return;
            }

            this.mobileEnemy = mobileEnemy;
            this.entityType  = entityType;
            name             = career.Name;

            short skillsLevel = (short)((level * 5) + 30);

            if (skillsLevel > 100)
            {
                skillsLevel = 100;
            }

            for (int i = 0; i <= DaggerfallSkills.Count; i++)
            {
                skills.SetSkillValue(i, skillsLevel);
            }

            FillVitalSigns();
        }