コード例 #1
0
        public static DaggerfallUnityItem CreateRandomlyFilledSoulTrap()
        {
            // Create a trapped soul type and filter invalid creatures
            MobileTypes soul = MobileTypes.None;

            while (soul == MobileTypes.None)
            {
                MobileTypes randomSoul = (MobileTypes)UnityEngine.Random.Range((int)MobileTypes.Rat, (int)MobileTypes.Lamia + 1);
                if (randomSoul == MobileTypes.Horse_Invalid ||
                    randomSoul == MobileTypes.Dragonling)       // NOTE: Dragonling (34) is soulless, only soul of Dragonling_Alternate (40) from B0B70Y16 has a soul
                {
                    continue;
                }
                else
                {
                    soul = randomSoul;
                }
            }

            // Generate item
            DaggerfallUnityItem newItem = CreateItem(ItemGroups.MiscItems, (int)MiscItems.Soul_trap);

            newItem.TrappedSoulType = soul;
            MobileEnemy mobileEnemy = GameObjectHelper.EnemyDict[(int)soul];

            newItem.value = 5000 + mobileEnemy.SoulPts;

            return(newItem);
        }
コード例 #2
0
        private void MeleeDamage()
        {
            if (entityBehaviour)
            {
                EnemyEntity entity = entityBehaviour.Entity as EnemyEntity;
                MobileEnemy enemy  = entity.MobileEnemy;

                // Are we still in range and facing player? Then apply melee damage.
                if (senses.DistanceToPlayer < MeleeDistance && senses.PlayerInSight)
                {
                    // Calculate damage
                    // TODO: Implement enemy use of weapons. Play hit or miss sounds.
                    int damage = Game.Formulas.FormulaHelper.CalculateWeaponDamage(entity, GameManager.Instance.PlayerEntity, null);
                    if (damage > 0)
                    {
                        GameManager.Instance.PlayerObject.SendMessage("RemoveHealth", damage);
                    }
                    else if (sounds)
                    {
                        sounds.PlayMissSound();
                    }

                    // Tally player's dodging skill
                    GameManager.Instance.PlayerEntity.TallySkill((short)Skills.Dodging, 1);
                }
            }
        }
コード例 #3
0
        private void MeleeDamage()
        {
            if (entityBehaviour)
            {
                EnemyEntity entity = entityBehaviour.Entity as EnemyEntity;
                MobileEnemy enemy  = entity.MobileEnemy;

                int damage = 0;

                // Are we still in range and facing player? Then apply melee damage.
                if (senses.DistanceToPlayer < MeleeDistance && senses.PlayerInSight)
                {
                    // Calculate damage
                    damage = Game.Formulas.FormulaHelper.CalculateWeaponDamage(entity, GameManager.Instance.PlayerEntity, null);
                    if (damage > 0)
                    {
                        GameManager.Instance.PlayerObject.SendMessage("RemoveHealth", damage);
                    }

                    // Tally player's dodging skill
                    GameManager.Instance.PlayerEntity.TallySkill(DFCareer.Skills.Dodging, 1);
                }

                if (sounds)
                {
                    Items.DaggerfallUnityItem weapon = entity.ItemEquipTable.GetItem(Items.EquipSlots.RightHand);
                    if (weapon == null)
                    {
                        weapon = entity.ItemEquipTable.GetItem(Items.EquipSlots.LeftHand);
                    }
                    if (damage > 0)
                    {
                        // TODO: Play hit and parry sounds on other AI characters once attacks against other AI are possible
                        DaggerfallAudioSource dfAudioSource = GetComponent <DaggerfallAudioSource>();
                        if (dfAudioSource)
                        {
                            if (weapon == null)
                            {
                                dfAudioSource.PlayOneShot((int)SoundClips.Hit1 + UnityEngine.Random.Range(2, 4), 0, 1.1f);
                            }
                            else
                            {
                                dfAudioSource.PlayOneShot((int)SoundClips.Hit1 + UnityEngine.Random.Range(0, 5), 0, 1.1f);
                            }
                        }
                    }
                    else
                    {
                        sounds.PlayMissSound(weapon);
                    }
                }
            }
        }
        ItemCollection GetMerchantMagicItems()
        {
            if (merchantItems == null)
            {
                PlayerEntity   playerEntity = GameManager.Instance.PlayerEntity;
                ItemCollection items        = new ItemCollection();
                int            numOfItems   = (buildingDiscoveryData.quality / 2) + 1;

                for (int i = 0; i <= numOfItems; i++)
                {
                    DaggerfallUnityItem magicItem = ItemBuilder.CreateRandomMagicItem(playerEntity.Level, playerEntity.Gender, playerEntity.Race);

                    // Item is already identified
                    magicItem.flags |= 0x20;

                    items.AddItem(magicItem);
                }

                items.AddItem(ItemBuilder.CreateItem(ItemGroups.MiscItems, (int)MiscItems.Spellbook));

                if (guild.Rank >= 4)
                {
                    for (int i = 0; i <= numOfItems; i++)
                    {
                        DaggerfallUnityItem magicItem = ItemBuilder.CreateItem(ItemGroups.MiscItems, (int)MiscItems.Soul_trap);
                        magicItem.value = 5000;

                        if (UnityEngine.Random.Range(1, 101) >= 25)
                        {
                            magicItem.TrappedSoulType = MobileTypes.None;
                        }
                        else
                        {
                            int id = UnityEngine.Random.Range(0, 43);
                            magicItem.TrappedSoulType = (MobileTypes)id;
                            MobileEnemy mobileEnemy = GameObjectHelper.EnemyDict[id];
                            magicItem.value += mobileEnemy.SoulPts;
                        }

                        items.AddItem(magicItem);
                    }
                }

                merchantItems = items;
            }
            return(merchantItems);
        }
コード例 #5
0
        private void SetEnemy()
        {
            // Get random enemy
            int         index       = Random.Range(0, GameObjectHelper.EnemyDict.Count);
            MobileEnemy mobileEnemy = GameObjectHelper.EnemyDict.ElementAt(index).Value;

            // Get random texture
            int         archive     = Random.value < 0.5f ? mobileEnemy.MaleTexture : mobileEnemy.FemaleTexture;
            string      fileName    = string.Format("TEXTURE.{0}", archive);
            TextureFile textureFile = new TextureFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, fileName), FileUsage.UseMemory, true);
            int         record      = Random.Range(0, textureFile.RecordCount);
            int         frame       = Random.Range(0, textureFile.GetFrameCount(record));

            // Set fields
            enemyTexture = ImageReader.GetTexture(fileName, record, frame, true);
            enemyName    = TextManager.Instance.GetLocalizedEnemyName(mobileEnemy.ID);
        }
コード例 #6
0
        private void MeleeDamage()
        {
            int minDamage = 0, maxDamage = 0;

            if (entityBehaviour)
            {
                EnemyEntity entity = entityBehaviour.Entity as EnemyEntity;
                MobileEnemy enemy  = entity.MobileEnemy;
                minDamage = enemy.MinDamage;
                maxDamage = enemy.MaxDamage;
            }

            // Are we still in range and facing player? Then apply melee damage.
            if (senses.DistanceToPlayer < MeleeDistance && senses.PlayerInSight)
            {
                int damage = Random.Range(minDamage, maxDamage + 1);
                senses.Player.SendMessage("RemoveHealth", damage);
            }
        }
コード例 #7
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();
        }
コード例 #8
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();
        }
コード例 #9
0
        // TODO: Classic seems deterministic so when re-visiting each mages guildhall, player sees same stuff.
        // Does it change with level? Is it always generated but uses a consistent seed? How should DFU do this?
        ItemCollection GetMerchantMagicItems()
        {
            PlayerEntity   playerEntity = GameManager.Instance.PlayerEntity;
            ItemCollection items        = new ItemCollection();
            int            numOfItems   = (buildingDiscoveryData.quality / 2) + 1;

            for (int i = 0; i <= numOfItems; i++)
            {
                // Create magic item which is already identified
                DaggerfallUnityItem magicItem = ItemBuilder.CreateRandomMagicItem(playerEntity.Level, playerEntity.Gender, playerEntity.Race);
                magicItem.IdentifyItem();
                items.AddItem(magicItem);
            }

            items.AddItem(ItemBuilder.CreateItem(ItemGroups.MiscItems, (int)MiscItems.Spellbook));

            if (guild.CanAccessService(GuildServices.BuySoulgems))
            {
                for (int i = 0; i <= numOfItems; i++)
                {
                    DaggerfallUnityItem magicItem = ItemBuilder.CreateItem(ItemGroups.MiscItems, (int)MiscItems.Soul_trap);
                    magicItem.value = 5000;

                    if (Dice100.FailedRoll(25))
                    {
                        magicItem.TrappedSoulType = MobileTypes.None;
                    }
                    else
                    {
                        int id = UnityEngine.Random.Range(0, 43);
                        magicItem.TrappedSoulType = (MobileTypes)id;
                        MobileEnemy mobileEnemy = GameObjectHelper.EnemyDict[id];
                        magicItem.value += mobileEnemy.SoulPts;
                    }
                    items.AddItem(magicItem);
                }
            }
            return(items);
        }
コード例 #10
0
        void Update()
        {
            if (mainCamera == null)
            {
                return;
            }

            // Change activate mode
            if (InputManager.Instance.ActionStarted(InputManager.Actions.StealMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Steal);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.GrabMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Grab);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.InfoMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Info);
            }
            else if (InputManager.Instance.ActionStarted(InputManager.Actions.TalkMode))
            {
                ChangeInteractionMode(PlayerActivateModes.Talk);
            }

            // Fire ray into scene
            if (InputManager.Instance.ActionStarted(InputManager.Actions.ActivateCenterObject))
            {
                // TODO: Clean all this up

                // Ray origin is slightly below camera height to ensure it originates inside player's own collider
                // This prevents ray from intersecting with player's own collider and blocking looting or low triggers
                Ray        ray = new Ray(transform.position + Vector3.up * 0.7f, mainCamera.transform.forward);
                RaycastHit hit;
                RayDistance = 75f; // Approximates classic at full view distance (default setting). Classic seems to do raycasts for as far as it can render objects.
                bool hitSomething = Physics.Raycast(ray, out hit, RayDistance);
                if (hitSomething)
                {
                    bool hitBuilding      = false;
                    bool buildingUnlocked = false;
                    DFLocation.BuildingTypes buildingType = DFLocation.BuildingTypes.AllValid;
                    StaticBuilding           building     = new StaticBuilding();

                    #region Hit Checks

                    // Trigger quest resource behaviour click on anything but NPCs
                    QuestResourceBehaviour questResourceBehaviour;
                    if (QuestResourceBehaviourCheck(hit, out questResourceBehaviour))
                    {
                        if (!(questResourceBehaviour.TargetResource is Person))
                        {
                            if (hit.distance > (DefaultActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                return;
                            }

                            // Only trigger click when not in info mode
                            if (currentMode != PlayerActivateModes.Info)
                            {
                                TriggerQuestResourceBehaviourClick(questResourceBehaviour);
                            }
                        }
                    }

                    // Check for a static building hit
                    Transform buildingOwner;
                    DaggerfallStaticBuildings buildings = GetBuildings(hit.transform, out buildingOwner);
                    if (buildings)
                    {
                        if (buildings.HasHit(hit.point, out building))
                        {
                            hitBuilding = true;

                            // Get building directory for location
                            BuildingDirectory buildingDirectory = GameManager.Instance.StreamingWorld.GetCurrentBuildingDirectory();
                            if (!buildingDirectory)
                            {
                                return;
                            }

                            // Get detailed building data from directory
                            BuildingSummary buildingSummary;
                            if (!buildingDirectory.GetBuildingSummary(building.buildingKey, out buildingSummary))
                            {
                                return;
                            }

                            // Check if door is unlocked
                            buildingUnlocked = BuildingIsUnlocked(buildingSummary);

                            // Store building type
                            buildingType = buildingSummary.BuildingType;

                            if (currentMode == PlayerActivateModes.Info)
                            {
                                // Discover building
                                GameManager.Instance.PlayerGPS.DiscoverBuilding(building.buildingKey);

                                // Get discovered building
                                PlayerGPS.DiscoveredBuilding db;
                                if (GameManager.Instance.PlayerGPS.GetDiscoveredBuilding(building.buildingKey, out db))
                                {
                                    // TODO: Check against quest system for an overriding quest-assigned display name for this building
                                    DaggerfallUI.AddHUDText(db.displayName);

                                    if (!buildingUnlocked && buildingType < DFLocation.BuildingTypes.Temple &&
                                        buildingType != DFLocation.BuildingTypes.HouseForSale)
                                    {
                                        string storeClosedMessage = HardStrings.storeClosed;
                                        storeClosedMessage = storeClosedMessage.Replace("%d1", openHours[(int)buildingType].ToString());
                                        storeClosedMessage = storeClosedMessage.Replace("%d2", closeHours[(int)buildingType].ToString());
                                        DaggerfallUI.Instance.PopupMessage(storeClosedMessage);
                                    }
                                }
                            }
                        }
                    }

                    // Check for a static door hit
                    Transform             doorOwner;
                    DaggerfallStaticDoors doors = GetDoors(hit.transform, out doorOwner);
                    if (doors && playerEnterExit)
                    {
                        StaticDoor door;
                        if (doors.HasHit(hit.point, out door))
                        {
                            // Check if close enough to activate
                            if (hit.distance > (DoorActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                return;
                            }

                            if (door.doorType == DoorTypes.Building && !playerEnterExit.IsPlayerInside)
                            {
                                // Discover building
                                GameManager.Instance.PlayerGPS.DiscoverBuilding(building.buildingKey);

                                // TODO: Implement lockpicking and door bashing for exterior doors
                                // For now, any locked building door can be entered by using steal mode
                                if (!buildingUnlocked)
                                {
                                    if (currentMode != PlayerActivateModes.Steal)
                                    {
                                        string Locked = "Locked.";
                                        DaggerfallUI.Instance.PopupMessage(Locked);
                                        return;
                                    }
                                    else     // Breaking into building
                                    {
                                        PlayerEntity player = GameManager.Instance.PlayerEntity;
                                        //player.TallyCrimeGuildRequirements(true, 1);
                                    }
                                }

                                // If entering a shop let player know the quality level
                                // If entering an open home, show greeting
                                if (hitBuilding)
                                {
                                    const int houseGreetingsTextId = 256;

                                    DaggerfallMessageBox mb;

                                    if (buildingUnlocked && buildingType >= DFLocation.BuildingTypes.House1 &&
                                        buildingType <= DFLocation.BuildingTypes.House4)
                                    {
                                        string greetingText = DaggerfallUnity.Instance.TextProvider.GetRandomText(houseGreetingsTextId);
                                        mb = DaggerfallUI.MessageBox(greetingText);
                                    }
                                    else
                                    {
                                        mb = PresentShopQuality(building);
                                    }

                                    if (mb != null)
                                    {
                                        // Defer transition to interior to after user closes messagebox
                                        deferredInteriorDoorOwner = doorOwner;
                                        deferredInteriorDoor      = door;
                                        mb.OnClose += Popup_OnClose;
                                        return;
                                    }
                                }

                                // Hit door while outside, transition inside
                                TransitionInterior(doorOwner, door, true);
                                return;
                            }
                            else if (door.doorType == DoorTypes.Building && playerEnterExit.IsPlayerInside)
                            {
                                // Hit door while inside, transition outside
                                playerEnterExit.TransitionExterior(true);
                                return;
                            }
                            else if (door.doorType == DoorTypes.DungeonEntrance && !playerEnterExit.IsPlayerInside)
                            {
                                if (playerGPS)
                                {
                                    // Hit dungeon door while outside, transition inside
                                    playerEnterExit.TransitionDungeonInterior(doorOwner, door, playerGPS.CurrentLocation, true);
                                    return;
                                }
                            }
                            else if (door.doorType == DoorTypes.DungeonExit && playerEnterExit.IsPlayerInside)
                            {
                                // Hit dungeon exit while inside, ask if access wagon or transition outside
                                if (GameManager.Instance.PlayerEntity.Items.Contains(ItemGroups.Transportation, (int)Transportation.Small_cart))
                                {
                                    DaggerfallMessageBox messageBox = new DaggerfallMessageBox(DaggerfallUI.UIManager, DaggerfallMessageBox.CommonMessageBoxButtons.YesNo, 38, DaggerfallUI.UIManager.TopWindow);
                                    messageBox.OnButtonClick += DungeonWagonAccess_OnButtonClick;
                                    DaggerfallUI.UIManager.PushWindow(messageBox);
                                    return;
                                }
                                else
                                {
                                    playerEnterExit.TransitionDungeonExterior(true);
                                }
                            }
                        }
                    }

                    // Check for an action door hit
                    DaggerfallActionDoor actionDoor;
                    if (ActionDoorCheck(hit, out actionDoor))
                    {
                        // Check if close enough to activate
                        if (hit.distance > (DoorActivationDistance * MeshReader.GlobalScale))
                        {
                            DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                            return;
                        }

                        if (currentMode == PlayerActivateModes.Steal && actionDoor.IsLocked && !actionDoor.IsOpen)
                        {
                            actionDoor.AttemptLockpicking();
                        }
                        else
                        {
                            actionDoor.ToggleDoor(true);
                        }
                    }

                    // Check for action record hit
                    DaggerfallAction action;
                    if (ActionCheck(hit, out action))
                    {
                        if (hit.distance <= (DefaultActivationDistance * MeshReader.GlobalScale))
                        {
                            action.Receive(this.gameObject, DaggerfallAction.TriggerTypes.Direct);
                        }
                    }

                    // Check for lootable object hit
                    DaggerfallLoot loot;
                    if (LootCheck(hit, out loot))
                    {
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker && !string.IsNullOrEmpty(loot.entityName))
                            {
                                string message = string.Empty;
                                if (loot.isEnemyClass)
                                {
                                    message = HardStrings.youSeeADeadPerson;
                                }
                                else
                                {
                                    message = HardStrings.youSeeADead;
                                    message = message.Replace("%s", loot.entityName);
                                }
                                DaggerfallUI.Instance.PopupMessage(message);
                            }
                            break;

                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                        case PlayerActivateModes.Steal:
                            // Check if close enough to activate
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker)
                            {
                                if (hit.distance > CorpseActivationDistance * MeshReader.GlobalScale)
                                {
                                    DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                    break;
                                }
                            }
                            else if (hit.distance > TreasureActivationDistance * MeshReader.GlobalScale)
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                break;
                            }

                            // For bodies, check has treasure first
                            if (loot.ContainerType == LootContainerTypes.CorpseMarker && loot.Items.Count == 0)
                            {
                                DaggerfallUI.AddHUDText(HardStrings.theBodyHasNoTreasure);
                                break;
                            }

                            // Open inventory window with loot as remote target
                            DaggerfallUI.Instance.InventoryWindow.LootTarget = loot;
                            DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenInventoryWindow);
                            break;
                        }
                    }

                    // Check for static NPC hit
                    StaticNPC npc;
                    if (NPCCheck(hit, out npc))
                    {
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                            PresentNPCInfo(npc);
                            break;

                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                        case PlayerActivateModes.Steal:
                            if (hit.distance > (StaticNPCActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                break;
                            }
                            StaticNPCClick(npc);
                            break;
                        }
                    }

                    // Check for mobile NPC hit
                    MobilePersonNPC mobileNpc = null;
                    if (MobilePersonMotorCheck(hit, out mobileNpc))
                    {
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                            if (hit.distance > (MobileNPCActivationDistance * MeshReader.GlobalScale))
                            {
                                DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                break;
                            }
                            GameManager.Instance.TalkManager.TalkToMobileNPC(mobileNpc);
                            break;

                        case PlayerActivateModes.Steal:
                            if (!mobileNpc.PickpocketByPlayerAttempted)
                            {
                                if (hit.distance > (PickpocketDistance * MeshReader.GlobalScale))
                                {
                                    DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                    break;
                                }
                                mobileNpc.PickpocketByPlayerAttempted = true;
                                Pickpocket();
                            }
                            break;
                        }
                    }

                    // Check for mobile enemy hit
                    DaggerfallEntityBehaviour mobileEnemyBehaviour;
                    if (MobileEnemyCheck(hit, out mobileEnemyBehaviour))
                    {
                        EnemyEntity enemyEntity = mobileEnemyBehaviour.Entity as EnemyEntity;
                        switch (currentMode)
                        {
                        case PlayerActivateModes.Info:
                        case PlayerActivateModes.Grab:
                        case PlayerActivateModes.Talk:
                            if (enemyEntity != null)
                            {
                                MobileEnemy mobileEnemy     = enemyEntity.MobileEnemy;
                                bool        startsWithVowel = "aeiouAEIOU".Contains(mobileEnemy.Name[0].ToString());
                                string      message;
                                if (startsWithVowel)
                                {
                                    message = HardStrings.youSeeAn;
                                }
                                else
                                {
                                    message = HardStrings.youSeeA;
                                }
                                message = message.Replace("%s", mobileEnemy.Name);
                                DaggerfallUI.Instance.PopupMessage(message);
                            }
                            break;

                        case PlayerActivateModes.Steal:
                            // Classic allows pickpocketing of NPC mobiles and enemy mobiles.
                            // In early versions the only enemy mobiles that can be pickpocketed are classes,
                            // but patch 1.07.212 allows pickpocketing of creatures.
                            // For now, the only enemy mobiles being allowed by DF Unity are classes.
                            if (mobileEnemyBehaviour && (mobileEnemyBehaviour.EntityType != EntityTypes.EnemyClass))
                            {
                                break;
                            }
                            // Classic doesn't set any flag when pickpocketing enemy mobiles, so infinite attempts are possible
                            if (enemyEntity != null && !enemyEntity.PickpocketByPlayerAttempted)
                            {
                                if (hit.distance > (PickpocketDistance * MeshReader.GlobalScale))
                                {
                                    DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                                    break;
                                }
                                enemyEntity.PickpocketByPlayerAttempted = true;
                                Pickpocket(mobileEnemyBehaviour);
                            }
                            break;
                        }
                    }

                    // Trigger ladder hit
                    DaggerfallLadder ladder = hit.transform.GetComponent <DaggerfallLadder>();
                    if (ladder)
                    {
                        if (hit.distance > (DefaultActivationDistance * MeshReader.GlobalScale))
                        {
                            DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway);
                            return;
                        }

                        ladder.ClimbLadder();
                    }

                    #endregion
                }
            }
        }
コード例 #11
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.
        }
コード例 #12
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();
        }
コード例 #13
0
        /// <summary>
        /// Gets enemy definition based on name.
        /// Runs a brute force search for ID, so use sparingly.
        /// </summary>
        /// <param name="name">Enemy name to extract definition.</param>
        /// <param name="mobileEnemyOut">Receives details of enemy type if found.</param>
        /// <returns>True if successful.</returns>
        public static bool GetEnemy(string name, out MobileEnemy mobileEnemyOut)
        {
            for (int i = 0; i < Enemies.Length; i++)
            {
                if (0 == string.Compare(Enemies[i].Name, name, StringComparison.InvariantCultureIgnoreCase))
                {
                    mobileEnemyOut = Enemies[i];
                    return true;
                }
            }

            // No match found, just return an empty definition
            mobileEnemyOut = new MobileEnemy();
            return false;
        }
コード例 #14
0
        /// <summary>
        /// Gets enemy definition based on type.
        /// Runs a brute force search for ID, so use sparingly.
        /// Store a dictionary from GetEnemyDict() for faster lookups.
        /// </summary>
        /// <param name="enemyType">Enemy type to extract definition.</param>
        /// <param name="mobileEnemyOut">Receives details of enemy type.</param>
        /// <returns>True if successful.</returns>
        public static bool GetEnemy(MobileTypes enemyType, out MobileEnemy mobileEnemyOut)
        {
            // Cast type enum to ID.
            // You can add additional IDs to enum to create new enemies.
            int id = (int)enemyType;

            // Search for matching definition in enemy list.
            // Don't forget to add new enemy IDs to Enemies definition array.
            for (int i = 0; i < Enemies.Length; i++)
            {
                if (Enemies[i].ID == id)
                {
                    mobileEnemyOut = Enemies[i];
                    return true;
                }
            }

            // No match found, just return an empty definition
            mobileEnemyOut = new MobileEnemy();
            return false;
        }
コード例 #15
0
        /// <summary>
        /// Sets up enemy based on current settings.
        /// </summary>
        public void ApplyEnemySettings(MobileGender gender)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            Dictionary <int, MobileEnemy> enemyDict = GameObjectHelper.EnemyDict;
            MobileEnemy mobileEnemy = enemyDict[(int)EnemyType];

            // Find mobile unit in children
            DaggerfallMobileUnit dfMobile = GetMobileBillboardChild();

            if (dfMobile != null)
            {
                // Setup mobile billboard
                Vector2 size = Vector2.one;
                mobileEnemy.Gender = gender;
                dfMobile.SetEnemy(dfUnity, mobileEnemy, EnemyReaction);

                // Setup controller
                CharacterController controller = GetComponent <CharacterController>();
                if (controller)
                {
                    // Set base height from sprite
                    size = dfMobile.Summary.RecordSizes[0];
                    controller.height = size.y;

                    // Reduce height of flying creatures as their wing animation makes them taller than desired
                    // This helps them get through doors while aiming for player eye height
                    if (dfMobile.Summary.Enemy.Behaviour == MobileBehaviour.Flying)
                    {
                        controller.height /= 2f;
                    }

                    // Uncomment below lines to limit maximum controller height
                    // Some particularly tall sprites (e.g. giants) require this hack to get through doors
                    // However they will appear sunken into ground as a result
                    //if (controller.height > 1.9f)
                    //    controller.height = 1.9f;

                    controller.gameObject.layer = LayerMask.NameToLayer("Enemies");
                }

                // Setup sounds
                EnemySounds enemySounds = GetComponent <Game.EnemySounds>();
                if (enemySounds)
                {
                    enemySounds.MoveSound   = (SoundClips)dfMobile.Summary.Enemy.MoveSound;
                    enemySounds.BarkSound   = (SoundClips)dfMobile.Summary.Enemy.BarkSound;
                    enemySounds.AttackSound = (SoundClips)dfMobile.Summary.Enemy.AttackSound;
                }

                // Setup entity
                if (entityBehaviour)
                {
                    EnemyEntity entity = new EnemyEntity();
                    entityBehaviour.Entity = entity;

                    int enemyIndex = (int)EnemyType;
                    if (enemyIndex >= 0 && enemyIndex <= 42)
                    {
                        entityBehaviour.EntityType = EntityTypes.EnemyMonster;
                        entity.SetEnemyCareer(mobileEnemy, entityBehaviour.EntityType);
                    }
                    else if (enemyIndex >= 128 && enemyIndex <= 146)
                    {
                        entityBehaviour.EntityType = EntityTypes.EnemyClass;
                        entity.SetEnemyCareer(mobileEnemy, entityBehaviour.EntityType);
                    }
                    else
                    {
                        entityBehaviour.EntityType = EntityTypes.None;
                    }
                }
            }
        }
コード例 #16
0
        /// <summary>
        /// Sets up enemy based on current settings.
        /// </summary>
        public void ApplyEnemySettings(MobileGender gender)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            Dictionary <int, MobileEnemy> enemyDict = GameObjectHelper.EnemyDict;
            MobileEnemy mobileEnemy = enemyDict[(int)EnemyType];

            if (AlliedToPlayer)
            {
                mobileEnemy.Team = MobileTeams.PlayerAlly;
            }

            // Find mobile unit in children
            MobileUnit dfMobile = GetMobileBillboardChild();

            if (dfMobile != null)
            {
                // Setup mobile billboard
                Vector2 size = Vector2.one;
                mobileEnemy.Gender    = gender;
                mobileEnemy.Reactions = EnemyReaction;
                dfMobile.SetEnemy(dfUnity, mobileEnemy, EnemyReaction, ClassicSpawnDistanceType);

                // Setup controller
                CharacterController controller = GetComponent <CharacterController>();
                if (controller)
                {
                    // Set base height from sprite
                    size = dfMobile.GetSize();
                    controller.height = size.y;

                    // Reduce height of flying creatures as their wing animation makes them taller than desired
                    // This helps them get through doors while aiming for player eye height
                    if (dfMobile.Enemy.Behaviour == MobileBehaviour.Flying)
                    {
                        // (in frame 0 wings are in high position, assume body is  the lower half)
                        AdjustControllerHeight(controller, controller.height / 2, ControllerJustification.BOTTOM);
                    }

                    // Limit minimum controller height
                    // Stops very short characters like rats from being walked upon
                    if (controller.height < 1.6f)
                    {
                        AdjustControllerHeight(controller, 1.6f, ControllerJustification.BOTTOM);
                    }

                    controller.gameObject.layer = LayerMask.NameToLayer("Enemies");
                }

                // Setup sounds
                EnemySounds enemySounds = GetComponent <Game.EnemySounds>();
                if (enemySounds)
                {
                    enemySounds.MoveSound   = (SoundClips)dfMobile.Enemy.MoveSound;
                    enemySounds.BarkSound   = (SoundClips)dfMobile.Enemy.BarkSound;
                    enemySounds.AttackSound = (SoundClips)dfMobile.Enemy.AttackSound;
                }

                MeshRenderer meshRenderer = dfMobile.GetComponent <MeshRenderer>();
                if (meshRenderer)
                {
                    if (dfMobile.Enemy.Behaviour == MobileBehaviour.Spectral)
                    {
                        meshRenderer.material.shader = Shader.Find(MaterialReader._DaggerfallGhostShaderName);
                        meshRenderer.material.SetFloat("_Cutoff", 0.1f);
                    }
                    if (dfMobile.Enemy.NoShadow)
                    {
                        meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
                    }
                    if (dfMobile.Enemy.GlowColor != null)
                    {
                        meshRenderer.receiveShadows = false;
                        GameObject enemyLightGameObject = Instantiate(LightAura);
                        enemyLightGameObject.transform.parent        = dfMobile.transform;
                        enemyLightGameObject.transform.localPosition = new Vector3(0, 0.3f, 0.2f);
                        Light enemyLight = enemyLightGameObject.GetComponent <Light>();
                        enemyLight.color   = (Color)dfMobile.Enemy.GlowColor;
                        enemyLight.shadows = DaggerfallUnity.Settings.DungeonLightShadows ? LightShadows.Soft : LightShadows.None;
                    }
                }

                // Setup entity
                if (entityBehaviour)
                {
                    EnemyEntity entity = new EnemyEntity(entityBehaviour);
                    entityBehaviour.Entity = entity;

                    // Enemies are initially added to same world context as player
                    entity.WorldContext = GameManager.Instance.PlayerEnterExit.WorldContext;

                    int enemyIndex = (int)EnemyType;
                    if (enemyIndex >= 0 && enemyIndex <= 42)
                    {
                        entityBehaviour.EntityType = EntityTypes.EnemyMonster;
                        entity.SetEnemyCareer(mobileEnemy, entityBehaviour.EntityType);
                    }
                    else if (enemyIndex >= 128 && enemyIndex <= 146)
                    {
                        entityBehaviour.EntityType = EntityTypes.EnemyClass;
                        entity.SetEnemyCareer(mobileEnemy, entityBehaviour.EntityType);
                    }
                    else
                    {
                        entityBehaviour.EntityType = EntityTypes.None;
                    }
                }

                // Add special behaviour for Daedra Seducer mobiles
                if (dfMobile.Enemy.ID == (int)MobileTypes.DaedraSeducer)
                {
                    dfMobile.gameObject.AddComponent <DaedraSeducerMobileBehaviour>();
                }
            }
        }
コード例 #17
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();
        }
コード例 #18
0
        /// <summary>
        /// Sets up enemy based on current settings.
        /// </summary>
        public void ApplyEnemySettings(MobileGender gender)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;
            Dictionary <int, MobileEnemy> enemyDict = GameObjectHelper.EnemyDict;
            MobileEnemy mobileEnemy = enemyDict[(int)EnemyType];

            // Find mobile unit in children
            DaggerfallMobileUnit dfMobile = GetMobileBillboardChild();

            if (dfMobile != null)
            {
                // Setup mobile billboard
                Vector2 size = Vector2.one;
                mobileEnemy.Gender = gender;
                dfMobile.SetEnemy(dfUnity, mobileEnemy, EnemyReaction, ClassicSpawnDistanceType);

                // Setup controller
                CharacterController controller = GetComponent <CharacterController>();
                if (controller)
                {
                    // Set base height from sprite
                    size = dfMobile.Summary.RecordSizes[0];
                    controller.height = size.y;

                    // Reduce height of flying creatures as their wing animation makes them taller than desired
                    // This helps them get through doors while aiming for player eye height
                    if (dfMobile.Summary.Enemy.Behaviour == MobileBehaviour.Flying)
                    {
                        controller.height /= 2f;
                    }

                    // Limit maximum controller height
                    // Some particularly tall sprites (e.g. giants) require this hack to get through doors
                    if (controller.height > 1.78f)
                    {
                        // Adjust center so that sprite doesn't sink into the ground
                        Vector3 newCenter = controller.center;
                        newCenter.y      += (1.78f - controller.height) / 2;
                        controller.center = newCenter;
                        controller.height = 1.78f;
                    }

                    controller.gameObject.layer = LayerMask.NameToLayer("Enemies");
                }

                // Setup sounds
                EnemySounds enemySounds = GetComponent <Game.EnemySounds>();
                if (enemySounds)
                {
                    enemySounds.MoveSound   = (SoundClips)dfMobile.Summary.Enemy.MoveSound;
                    enemySounds.BarkSound   = (SoundClips)dfMobile.Summary.Enemy.BarkSound;
                    enemySounds.AttackSound = (SoundClips)dfMobile.Summary.Enemy.AttackSound;
                }

                // Setup entity
                if (entityBehaviour)
                {
                    EnemyEntity entity = new EnemyEntity(entityBehaviour);
                    entityBehaviour.Entity = entity;

                    // Enemies are initially added to same world context as player
                    entity.WorldContext = GameManager.Instance.PlayerEnterExit.WorldContext;

                    int enemyIndex = (int)EnemyType;
                    if (enemyIndex >= 0 && enemyIndex <= 42)
                    {
                        entityBehaviour.EntityType = EntityTypes.EnemyMonster;
                        entity.SetEnemyCareer(mobileEnemy, entityBehaviour.EntityType);
                    }
                    else if (enemyIndex >= 128 && enemyIndex <= 146)
                    {
                        entityBehaviour.EntityType = EntityTypes.EnemyClass;
                        entity.SetEnemyCareer(mobileEnemy, entityBehaviour.EntityType);
                    }
                    else
                    {
                        entityBehaviour.EntityType = EntityTypes.None;
                    }
                }
            }
        }
コード例 #19
0
        /// <summary>
        /// Create a regular non-artifact magic item.
        /// </summary>
        /// <param name="chosenItem">An integer index of the item to create, or -1 for a random one.</param>
        /// <param name="playerLevel">The player level to create an item for.</param>
        /// <param name="gender">The gender to create an item for.</param>
        /// <param name="race">The race to create an item for.</param>
        /// <returns>DaggerfallUnityItem</returns>
        /// <exception cref="Exception">When a base item cannot be created.</exception>
        public static DaggerfallUnityItem CreateRegularMagicItem(int chosenItem, int playerLevel, Genders gender, Races race)
        {
            byte[] itemGroups0 = { 2, 3, 6, 10, 12, 14, 25 };
            byte[] itemGroups1 = { 2, 3, 6, 12, 25 };

            DaggerfallUnityItem newItem = null;

            // Get the list of magic item templates read from MAGIC.DEF
            MagicItemsFile           magicItemsFile = new MagicItemsFile(Path.Combine(DaggerfallUnity.Instance.Arena2Path, "MAGIC.DEF"));
            List <MagicItemTemplate> magicItems     = magicItemsFile.MagicItemsList;

            // Reduce the list to only the regular magic items.
            MagicItemTemplate[] regularMagicItems = magicItems.Where(template => template.type == MagicItemTypes.RegularMagicItem).ToArray();
            if (chosenItem > regularMagicItems.Length)
            {
                throw new Exception(string.Format("Magic item subclass {0} does not exist", chosenItem));
            }

            // Pick a random one if needed.
            if (chosenItem == chooseAtRandom)
            {
                chosenItem = UnityEngine.Random.Range(0, regularMagicItems.Length);
            }

            // Get the chosen template
            MagicItemTemplate magicItem = regularMagicItems[chosenItem];

            // Get the item group. The possible groups are determined by the 33rd byte (magicItem.group) of the MAGIC.DEF template being used.
            ItemGroups group = 0;

            if (magicItem.group == 0)
            {
                group = (ItemGroups)itemGroups0[UnityEngine.Random.Range(0, 7)];
            }
            else if (magicItem.group == 1)
            {
                group = (ItemGroups)itemGroups1[UnityEngine.Random.Range(0, 5)];
            }
            else if (magicItem.group == 2)
            {
                group = ItemGroups.Weapons;
            }

            // Create the base item
            if (group == ItemGroups.Weapons)
            {
                newItem = CreateRandomWeapon(playerLevel);

                // No arrows as enchanted items
                while (newItem.GroupIndex == 18)
                {
                    newItem = CreateRandomWeapon(playerLevel);
                }
            }
            else if (group == ItemGroups.Armor)
            {
                newItem = CreateRandomArmor(playerLevel, gender, race);
            }
            else if (group == ItemGroups.MensClothing || group == ItemGroups.WomensClothing)
            {
                newItem = CreateRandomClothing(gender, race);
            }
            else if (group == ItemGroups.ReligiousItems)
            {
                newItem = CreateRandomReligiousItem();
            }
            else if (group == ItemGroups.Gems)
            {
                newItem = CreateRandomGem();
            }
            else // Only other possibility is jewellery
            {
                newItem = CreateRandomJewellery();
            }

            if (newItem == null)
            {
                throw new Exception("CreateRegularMagicItem() failed to create an item.");
            }

            // Replace the regular item name with the magic item name
            newItem.shortName = magicItem.name;

            // Add the enchantments
            newItem.legacyMagic = new DaggerfallEnchantment[magicItem.enchantments.Length];
            for (int i = 0; i < magicItem.enchantments.Length; ++i)
            {
                newItem.legacyMagic[i] = magicItem.enchantments[i];
            }

            // Set the condition/magic uses
            newItem.maxCondition     = magicItem.uses;
            newItem.currentCondition = magicItem.uses;

            // Set the value of the item. This is determined by the enchantment point cost/spell-casting cost
            // of the enchantments on the item.
            int value = 0;

            for (int i = 0; i < magicItem.enchantments.Length; ++i)
            {
                if (magicItem.enchantments[i].type != EnchantmentTypes.None &&
                    magicItem.enchantments[i].type < EnchantmentTypes.ItemDeteriorates)
                {
                    switch (magicItem.enchantments[i].type)
                    {
                    case EnchantmentTypes.CastWhenUsed:
                    case EnchantmentTypes.CastWhenHeld:
                    case EnchantmentTypes.CastWhenStrikes:
                        // Enchantments that cast a spell. The parameter is the spell index in SPELLS.STD.
                        value += Formulas.FormulaHelper.GetSpellEnchantPtCost(magicItem.enchantments[i].param);
                        break;

                    case EnchantmentTypes.RepairsObjects:
                    case EnchantmentTypes.AbsorbsSpells:
                    case EnchantmentTypes.EnhancesSkill:
                    case EnchantmentTypes.FeatherWeight:
                    case EnchantmentTypes.StrengthensArmor:
                        // Enchantments that provide an effect that has no parameters
                        value += enchantmentPointCostsForNonParamTypes[(int)magicItem.enchantments[i].type];
                        break;

                    case EnchantmentTypes.SoulBound:
                        // Bound soul
                        MobileEnemy mobileEnemy = GameObjectHelper.EnemyDict[magicItem.enchantments[i].param];
                        value += mobileEnemy.SoulPts;     // TODO: Not sure about this. Should be negative? Needs to be tested.
                        break;

                    default:
                        // Enchantments that provide a non-spell effect with a parameter (parameter = when effect applies, what enemies are affected, etc.)
                        value += enchantmentPtsForItemPowerArrays[(int)magicItem.enchantments[i].type][magicItem.enchantments[i].param];
                        break;
                    }
                }
            }

            newItem.value = value;

            return(newItem);
        }
コード例 #20
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();
        }