示例#1
0
 /// <summary>
 /// Applies effects to the activator for each requirement.
 /// Depending on the ability type, this may be called before or after the ability has finished.
 /// </summary>
 /// <param name="activator">The activator of the ability.</param>
 /// <param name="ability">The ability details</param>
 private static void ApplyRequirementEffects(uint activator, AbilityDetail ability)
 {
     foreach (var req in ability.Requirements)
     {
         req.AfterActivationAction(activator);
     }
 }
示例#2
0
        /// <summary>
        /// Handles queuing a weapon ability for the activator's next attack.
        /// Local variables are set on the activator which are picked up the next time the activator's weapon hits a target.
        /// If the activator does not hit a target within 30 seconds, the queued ability wears off automatically.
        /// Requirement reductions (MP, STM, etc) are applied as soon as the ability is queued.
        /// </summary>
        /// <param name="activator">The creature activating the ability.</param>
        /// <param name="ability">The ability details</param>
        /// <param name="feat">The feat being activated</param>
        /// <param name="effectivePerkLevel">The activator's effective perk level</param>
        private static void QueueWeaponAbility(uint activator, AbilityDetail ability, Feat feat, int effectivePerkLevel)
        {
            var abilityId = Guid.NewGuid().ToString();

            // Assign local variables which will be picked up on the next weapon OnHit event by this player.
            SetLocalInt(activator, ActiveAbilityName, (int)feat);
            SetLocalString(activator, ActiveAbilityIdName, abilityId);
            SetLocalInt(activator, ActiveAbilityFeatIdName, (int)feat);
            SetLocalInt(activator, ActiveAbilityEffectivePerkLevelName, effectivePerkLevel);

            ApplyRequirementEffects(activator, ability);

            var abilityRecastDelay = ability.RecastDelay?.Invoke(activator) ?? 0.0f;

            ApplyRecastDelay(activator, ability.RecastGroup, abilityRecastDelay);

            // Activator must attack within 30 seconds after queueing or else it wears off.
            DelayCommand(30.0f, () =>
            {
                if (GetLocalString(activator, ActiveAbilityIdName) != abilityId)
                {
                    return;
                }

                // Remove the local variables.
                DeleteLocalInt(activator, ActiveAbilityName);
                DeleteLocalString(activator, ActiveAbilityIdName);
                DeleteLocalInt(activator, ActiveAbilityFeatIdName);
                DeleteLocalInt(activator, ActiveAbilityEffectivePerkLevelName);

                // Notify the activator and nearby players
                SendMessageToPC(activator, $"Your weapon ability {ability.Name} is no longer queued.");
                Messaging.SendMessageNearbyToPlayers(activator, $"{GetName(activator)} no longer has weapon ability {ability.Name} readied.");
            });
        }
示例#3
0
        /// <summary>
        /// Checks whether a creature can activate the perk feat.
        /// </summary>
        /// <param name="activator">The activator of the perk feat.</param>
        /// <param name="target">The target of the perk feat.</param>
        /// <param name="ability">The ability details</param>
        /// <param name="effectivePerkLevel">The activator's effective perk level.</param>
        /// <returns>true if successful, false otherwise</returns>
        private static bool CanUseAbility(uint activator, uint target, AbilityDetail ability, int effectivePerkLevel)
        {
            // Must have at least one level in the perk.
            if (effectivePerkLevel <= 0)
            {
                SendMessageToPC(activator, "You do not meet the prerequisites to use this ability.");
                return(false);
            }

            // Activator is dead.
            if (GetCurrentHitPoints(activator) <= 0)
            {
                SendMessageToPC(activator, "You are dead.");
                return(false);
            }

            // Not commandable
            if (!GetCommandable(activator))
            {
                SendMessageToPC(activator, "You cannot take actions at this time.");
                return(false);
            }

            // Must be within line of sight.
            if (!LineOfSightObject(activator, target))
            {
                SendMessageToPC(activator, "You cannot see your target.");
                return(false);
            }

            // Perk-specific requirement checks
            foreach (var req in ability.Requirements)
            {
                var requirementError = req.CheckRequirements(activator);
                if (!string.IsNullOrWhiteSpace(requirementError))
                {
                    SendMessageToPC(activator, requirementError);
                    return(false);
                }
            }

            // Perk-specific custom validation logic.
            var customValidationResult = ability.CustomValidation == null ? string.Empty : ability.CustomValidation(activator, target, effectivePerkLevel);

            if (!string.IsNullOrWhiteSpace(customValidationResult))
            {
                SendMessageToPC(activator, customValidationResult);
                return(false);
            }

            // Check if ability is on a recast timer still.
            if (IsOnRecastDelay(activator, ability.RecastGroup))
            {
                return(false);
            }

            return(true);
        }
示例#4
0
        /// <summary>能力分类窗口</summary>
        public static void ShowAbilityDetail(ObservableCollection <AbilityModel> abilityDetailModels)
        {
            var dlg = new AbilityDetail(abilityDetailModels)
            {
                Owner = GetTopWindow()
            };

            dlg.ShowDialog();
        }
示例#5
0
        /// <summary>
        /// Handles casting abilities. These can be combat-related or casting-related and may or may not have a casting delay.
        /// Requirement reductions (MP, STM, etc) are applied after the casting has completed.
        /// In the event there is no casting delay, the reductions are applied immediately.
        /// </summary>
        /// <param name="activator">The creature activating the ability.</param>
        /// <param name="target">The target of the ability</param>
        /// <param name="ability">The ability details</param>
        /// <param name="effectivePerkLevel">The activator's effective perk level</param>
        private static void ActivateAbility(uint activator, uint target, AbilityDetail ability, int effectivePerkLevel)
        {
            // Activation delay is increased if player is equipped with heavy or light armor.
            float CalculateActivationDelay()
            {
                const float HeavyArmorPenalty = 2.0f;
                const float LightArmorPenalty = 1.5f;

                var armorPenalty   = 1.0f;
                var penaltyMessage = string.Empty;

                for (var slot = 0; slot < NumberOfInventorySlots; slot++)
                {
                    var item = GetItemInSlot((InventorySlot)slot, activator);

                    for (var ip = GetFirstItemProperty(item); GetIsItemPropertyValid(ip); ip = GetNextItemProperty(item))
                    {
                        if (GetItemPropertyType(ip) != ItemPropertyType.ArmorType)
                        {
                            continue;
                        }

                        var armorType = (ArmorType)GetItemPropertySubType(ip);
                        if (armorType == ArmorType.Heavy)
                        {
                            armorPenalty   = HeavyArmorPenalty;
                            penaltyMessage = "Heavy armor slows your casting speed by 100%.";
                            break;
                        }
                        else if (armorType == ArmorType.Light)
                        {
                            armorPenalty   = LightArmorPenalty;
                            penaltyMessage = "Light armor slows your casting speed by 50%.";
                        }
                    }

                    // If we found heavy armor, we can exit early. Anything else requires us to iterate over the rest of the items.
                    if (armorPenalty >= HeavyArmorPenalty)
                    {
                        break;
                    }
                }

                // Notify player if needed.
                if (!string.IsNullOrWhiteSpace(penaltyMessage))
                {
                    SendMessageToPC(activator, penaltyMessage);
                }

                var abilityDelay = ability.ActivationDelay?.Invoke(activator, target, effectivePerkLevel) ?? 0.0f;

                return(abilityDelay * armorPenalty);
            }

            // Handles displaying animation and visual effects.
            void ProcessAnimationAndVisualEffects(float delay)
            {
                // Force out of stealth
                if (GetActionMode(activator, ActionMode.Stealth))
                {
                    SetActionMode(activator, ActionMode.Stealth, false);
                }

                AssignCommand(activator, () => ClearAllActions());
                BiowarePosition.TurnToFaceObject(target, activator);

                // Display a casting visual effect if one has been specified.
                if (ability.ActivationVisualEffect != VisualEffect.None)
                {
                    var vfx = TagEffect(EffectVisualEffect(ability.ActivationVisualEffect), "ACTIVATION_VFX");
                    ApplyEffectToObject(DurationType.Temporary, vfx, activator, delay + 0.2f);
                }

                // Casted types play an animation of casting.
                if (ability.ActivationType == AbilityActivationType.Casted &&
                    ability.AnimationType != Animation.Invalid)
                {
                    AssignCommand(activator, () => ActionPlayAnimation(ability.AnimationType, 1.0f, delay - 0.2f));
                }
            }

            // Recursive function which checks if player has moved since starting the casting.
            void CheckForActivationInterruption(string activationId, Vector3 originalPosition)
            {
                if (!GetIsPC(activator))
                {
                    return;
                }

                // Completed abilities should no longer run.
                var status = GetLocalInt(activator, activationId);

                if (status == (int)ActivationStatus.Completed || status == (int)ActivationStatus.Invalid)
                {
                    return;
                }

                var currentPosition = GetPosition(activator);

                if (currentPosition.X != originalPosition.X ||
                    currentPosition.Y != originalPosition.Y ||
                    currentPosition.Z != originalPosition.Z)
                {
                    RemoveEffectByTag(activator, "ACTIVATION_VFX");

                    Player.StopGuiTimingBar(activator, string.Empty);
                    SendMessageToPC(activator, "Your ability has been interrupted.");
                    return;
                }

                DelayCommand(0.5f, () => CheckForActivationInterruption(activationId, originalPosition));
            }

            // This method is called after the delay of the ability has finished.
            void CompleteActivation(string id, float abilityRecastDelay)
            {
                DeleteLocalInt(activator, id);

                // Moved during casting or activator died. Cancel the activation.
                if (GetLocalInt(activator, id) == (int)ActivationStatus.Interrupted || GetCurrentHitPoints(activator) <= 0)
                {
                    return;
                }

                ApplyRequirementEffects(activator, ability);
                ability.ImpactAction?.Invoke(activator, target, effectivePerkLevel);
                ApplyRecastDelay(activator, ability.RecastGroup, abilityRecastDelay);
            }

            // Begin the main process
            var activationId    = Guid.NewGuid().ToString();
            var activationDelay = CalculateActivationDelay();
            var recastDelay     = ability.RecastDelay(activator);
            var position        = GetPosition(activator);

            ProcessAnimationAndVisualEffects(activationDelay);
            CheckForActivationInterruption(activationId, position);
            SetLocalInt(activator, activationId, (int)ActivationStatus.Started);

            if (GetIsPC(activator))
            {
                if (activationDelay > 0.0f)
                {
                    Player.StartGuiTimingBar(activator, activationDelay, string.Empty);
                }
            }

            DelayCommand(activationDelay, () => CompleteActivation(activationId, recastDelay));
        }
示例#6
0
 private void Start()
 {
     abilityDetailScript = abilityDetails.GetComponent <AbilityDetail> ();
 }