Пример #1
0
        private static void OnHitCastSpell()
        {
            NWPlayer oPC = Object.OBJECT_SELF;

            if (!oPC.IsValid)
            {
                return;
            }

            NWObject oTarget = _.GetSpellTargetObject();
            NWItem   oItem   = _.GetSpellCastItem();

            // If this method was triggered by our own armor (from getting hit), return.
            if (oItem.BaseItemType == BASE_ITEM_ARMOR)
            {
                return;
            }

            // Flag this attack as physical so that the damage scripts treat it properly.
            LoggingService.Trace(TraceComponent.LastAttack, "Setting attack type from " + oPC.GlobalID + " against " + _.GetName(oTarget) + " to physical (" + ATTACK_PHYSICAL.ToString() + ")");
            oTarget.SetLocalInt(LAST_ATTACK + oPC.GlobalID, ATTACK_PHYSICAL);

            HandleGrenadeProficiency(oPC, oTarget);
            HandlePlasmaCellPerk(oPC, oTarget);
            int activeWeaponSkillID = oPC.GetLocalInt("ACTIVE_WEAPON_SKILL");

            if (activeWeaponSkillID <= 0)
            {
                return;
            }
            int activeWeaponSkillFeatID = oPC.GetLocalInt("ACTIVE_WEAPON_SKILL_FEAT_ID");

            if (activeWeaponSkillFeatID < 0)
            {
                activeWeaponSkillFeatID = -1;
            }

            PCPerk entity  = DataService.GetAll <PCPerk>().Single(x => x.PlayerID == oPC.GlobalID && x.PerkID == activeWeaponSkillID);
            var    perk    = DataService.Get <Data.Entity.Perk>(entity.PerkID);
            var    handler = PerkService.GetPerkHandler(activeWeaponSkillID);

            if (handler.CanCastSpell(oPC, oTarget))
            {
                handler.OnImpact(oPC, oTarget, entity.PerkLevel, activeWeaponSkillFeatID);

                if (oTarget.IsNPC)
                {
                    ApplyEnmity(oPC, oTarget.Object, perk);
                }
            }
            else
            {
                oPC.SendMessage(handler.CannotCastSpellMessage(oPC, oTarget) ?? "That ability cannot be used at this time.");
            }

            oPC.DeleteLocalString("ACTIVE_WEAPON_SKILL_UUID");
            oPC.DeleteLocalInt("ACTIVE_WEAPON_SKILL");
            oPC.DeleteLocalInt("ACTIVE_WEAPON_SKILL_FEAT_ID");
        }
Пример #2
0
        /// <summary>
        /// Processes all feats which are linked to perks.
        /// </summary>
        private static void OnModuleUseFeat()
        {
            // Activator is the creature who used the feat.
            // Target is who the activator selected to use this feat on.
            NWCreature activator = _.OBJECT_SELF;
            NWCreature target    = NWNXObject.StringToObject(NWNXEvents.GetEventData("TARGET_OBJECT_ID"));
            var        featID    = (Feat)Convert.ToInt32(NWNXEvents.GetEventData("FEAT_ID"));

            // Ensure this perk feat can be activated.
            if (!CanUsePerkFeat(activator, target, featID))
            {
                return;
            }

            // Retrieve information necessary for activation of perk feat.
            var perkFeat = DataService.PerkFeat.GetByFeatID((int)featID);

            Data.Entity.Perk perk = DataService.Perk.GetByID(perkFeat.PerkID);
            int creaturePerkLevel = PerkService.GetCreaturePerkLevel(activator, perk.ID);
            var handler           = PerkService.GetPerkHandler(perkFeat.PerkID);

            SendAOEMessage(activator, activator.Name + " readies " + perk.Name + ".");

            // Force Abilities (aka Spells)
            if (perk.ExecutionTypeID == PerkExecutionType.ForceAbility)
            {
                target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_FORCE);
                ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.ForceAbility, perkFeat.PerkLevelUnlocked);
            }
            // Combat Abilities
            else if (perk.ExecutionTypeID == PerkExecutionType.CombatAbility)
            {
                target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_PHYSICAL);
                ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.CombatAbility, perkFeat.PerkLevelUnlocked);
            }
            // Queued Weapon Skills
            else if (perk.ExecutionTypeID == PerkExecutionType.QueuedWeaponSkill)
            {
                target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_PHYSICAL);
                HandleQueueWeaponSkill(activator, perk, handler, featID);
            }
            // Stances
            else if (perk.ExecutionTypeID == PerkExecutionType.Stance)
            {
                target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_COMBATABILITY);
                ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.Stance, perkFeat.PerkLevelUnlocked);
            }
            // Concentration Abilities
            else if (perk.ExecutionTypeID == PerkExecutionType.ConcentrationAbility)
            {
                target.SetLocalInt(LAST_ATTACK + activator.GlobalID, ATTACK_FORCE);
                ActivateAbility(activator, target, perk, handler, creaturePerkLevel, PerkExecutionType.ConcentrationAbility, perkFeat.PerkLevelUnlocked);
            }
        }
Пример #3
0
        public static void ApplyEnmity(NWCreature attacker, NWCreature target, Data.Entity.Perk perk)
        {
            switch ((EnmityAdjustmentRuleType)perk.EnmityAdjustmentRuleID)
            {
            case EnmityAdjustmentRuleType.AllTaggedTargets:
                EnmityService.AdjustEnmityOnAllTaggedCreatures(attacker, perk.Enmity);
                break;

            case EnmityAdjustmentRuleType.TargetOnly:
                if (target.IsValid)
                {
                    EnmityService.AdjustEnmity(target, attacker, perk.Enmity);
                }
                break;

            case EnmityAdjustmentRuleType.Custom:
                var handler = PerkService.GetPerkHandler(perk.ID);
                handler.OnCustomEnmityRule(attacker, perk.Enmity);
                break;
            }
        }
Пример #4
0
        /// <summary>
        /// Runs validation checks to ensure activator can use a perk feat.
        /// Activation will fail if any of the following are true:
        ///     - Target is invalid
        ///     - Activator is a ship
        ///     - Feat is not a perk feat
        ///     - Cooldown has not passed
        /// </summary>
        /// <param name="activator">The creature activating a perk feat.</param>
        /// <param name="target">The target of the perk feat.</param>
        /// <param name="featID">The ID number of the feat being used.</param>
        /// <returns>true if able to use perk feat on target, false otherwise.</returns>
        public static bool CanUsePerkFeat(NWCreature activator, NWObject target, Feat featID)
        {
            var perkFeat = DataService.PerkFeat.GetByFeatIDOrDefault((int)featID);

            // There's no matching feat in the DB for this ability. Exit early.
            if (perkFeat == null)
            {
                return(false);
            }

            // Retrieve the perk information.
            Data.Entity.Perk perk = DataService.Perk.GetByIDOrDefault(perkFeat.PerkID);

            // No perk could be found. Exit early.
            if (perk == null)
            {
                return(false);
            }

            // Check to see if we are a spaceship.  Spaceships can't use abilities...
            if (activator.GetLocalInt("IS_SHIP") > 0 || activator.GetLocalInt("IS_GUNNER") > 0)
            {
                activator.SendMessage("You cannot use that ability while piloting a ship.");
                return(false);
            }

            // Retrieve the perk-specific handler logic.
            var handler = PerkService.GetPerkHandler(perkFeat.PerkID);

            // Get the creature's perk level.
            int creaturePerkLevel = PerkService.GetCreaturePerkLevel(activator, perk.ID);

            // If player is disabling an existing stance, remove that effect.
            if (perk.ExecutionTypeID == PerkExecutionType.Stance)
            {
                // Can't process NPC stances at the moment. Need to do some more refactoring before this is possible.
                // todo: handle NPC stances.
                if (!activator.IsPlayer)
                {
                    return(false);
                }

                PCCustomEffect stanceEffect = DataService.PCCustomEffect.GetByStancePerkOrDefault(activator.GlobalID, perk.ID);

                if (stanceEffect != null)
                {
                    if (CustomEffectService.RemoveStance(activator))
                    {
                        return(false);
                    }
                }
            }

            // Check for a valid perk level.
            if (creaturePerkLevel <= 0)
            {
                activator.SendMessage("You do not meet the prerequisites to use this ability.");
                return(false);
            }

            // Verify that this hostile action meets PVP sanctuary restriction rules.
            if (handler.IsHostile() && target.IsPlayer)
            {
                if (!PVPSanctuaryService.IsPVPAttackAllowed(activator.Object, target.Object))
                {
                    return(false);
                }
            }

            // Activator and target must be in the same area and within line of sight.
            if (activator.Area.Resref != target.Area.Resref ||
                _.LineOfSightObject(activator.Object, target.Object) == false)
            {
                activator.SendMessage("You cannot see your target.");
                return(false);
            }

            // Run this perk's specific checks on whether the activator may use this perk on the target.
            string canCast = handler.CanCastSpell(activator, target, perkFeat.PerkLevelUnlocked);

            if (!string.IsNullOrWhiteSpace(canCast))
            {
                activator.SendMessage(canCast);
                return(false);
            }

            // Calculate the FP cost to use this ability. Verify activator has sufficient FP.
            int fpCost    = handler.FPCost(activator, handler.FPCost(activator, perkFeat.BaseFPCost, perkFeat.PerkLevelUnlocked), perkFeat.PerkLevelUnlocked);
            int currentFP = GetCurrentFP(activator);

            if (currentFP < fpCost)
            {
                activator.SendMessage("You do not have enough FP. (Required: " + fpCost + ". You have: " + currentFP + ")");
                return(false);
            }

            // Verify activator isn't busy or dead.
            if (activator.IsBusy || activator.CurrentHP <= 0)
            {
                activator.SendMessage("You are too busy to activate that ability.");
                return(false);
            }

            // verify activator is commandable. https://github.com/zunath/SWLOR_NWN/issues/940#issue-467175951
            if (!activator.IsCommandable)
            {
                activator.SendMessage("You cannot take actions currently.");
                return(false);
            }

            // If we're executing a concentration ability, check and see if the activator currently has this ability
            // active. If it's active, then we immediately remove its effect and bail out.
            // Any other ability (including other concentration abilities) execute as normal.
            if (perk.ExecutionTypeID == PerkExecutionType.ConcentrationAbility)
            {
                // Retrieve the concentration effect for this creature.
                var concentrationEffect = GetActiveConcentrationEffect(activator);
                if ((int)concentrationEffect.Type == perk.ID)
                {
                    // It's active. Time to disable it.
                    EndConcentrationEffect(activator);
                    activator.SendMessage("Concentration ability '" + perk.Name + "' deactivated.");
                    SendAOEMessage(activator, activator.Name + " deactivates concentration ability '" + perk.Name + "'.");
                    return(false);
                }
            }

            // Retrieve the cooldown information and determine the unlock time.
            int?     cooldownCategoryID = handler.CooldownCategoryID(activator, perk.CooldownCategoryID, perkFeat.PerkLevelUnlocked);
            DateTime now            = DateTime.UtcNow;
            DateTime unlockDateTime = cooldownCategoryID == null ? now : GetAbilityCooldownUnlocked(activator, (int)cooldownCategoryID);

            // Check if we've passed the unlock date. Exit early if we have not.
            if (unlockDateTime > now)
            {
                string timeToWait = TimeService.GetTimeToWaitLongIntervals(now, unlockDateTime, false);
                activator.SendMessage("That ability can be used in " + timeToWait + ".");
                return(false);
            }

            // Passed all checks. Return true.
            return(true);
        }
Пример #5
0
        private static void OnHitCastSpell()
        {
            NWPlayer oPC = _.OBJECT_SELF;

            if (!oPC.IsValid)
            {
                return;
            }

            NWObject oTarget = _.GetSpellTargetObject();
            NWItem   oItem   = _.GetSpellCastItem();

            // If this method was triggered by our own armor (from getting hit), return.
            if (oItem.BaseItemType == BaseItem.Armor)
            {
                return;
            }

            // Flag this attack as physical so that the damage scripts treat it properly.
            LoggingService.Trace(TraceComponent.LastAttack, "Setting attack type from " + oPC.GlobalID + " against " + _.GetName(oTarget) + " to physical (" + ATTACK_PHYSICAL.ToString() + ")");
            oTarget.SetLocalInt(LAST_ATTACK + oPC.GlobalID, ATTACK_PHYSICAL);

            HandleGrenadeProficiency(oPC, oTarget);
            HandlePlasmaCellPerk(oPC, oTarget);
            int activeWeaponSkillID = oPC.GetLocalInt("ACTIVE_WEAPON_SKILL");

            if (activeWeaponSkillID <= 0)
            {
                return;
            }
            int activeWeaponSkillFeatID = oPC.GetLocalInt("ACTIVE_WEAPON_SKILL_FEAT_ID");

            if (activeWeaponSkillFeatID < 0)
            {
                activeWeaponSkillFeatID = -1;
            }

            PCPerk entity   = DataService.PCPerk.GetByPlayerAndPerkID(oPC.GlobalID, activeWeaponSkillID);
            var    perk     = DataService.Perk.GetByID(entity.PerkID);
            var    perkFeat = DataService.PerkFeat.GetByFeatID(activeWeaponSkillFeatID);
            var    handler  = PerkService.GetPerkHandler(activeWeaponSkillID);

            string canCast = handler.CanCastSpell(oPC, oTarget, perkFeat.PerkLevelUnlocked);

            if (string.IsNullOrWhiteSpace(canCast))
            {
                handler.OnImpact(oPC, oTarget, entity.PerkLevel, perkFeat.PerkLevelUnlocked);

                if (oTarget.IsNPC)
                {
                    ApplyEnmity(oPC, oTarget.Object, perk);
                }
            }
            else
            {
                oPC.SendMessage(canCast);
            }

            oPC.DeleteLocalString("ACTIVE_WEAPON_SKILL_UUID");
            oPC.DeleteLocalInt("ACTIVE_WEAPON_SKILL");
            oPC.DeleteLocalInt("ACTIVE_WEAPON_SKILL_FEAT_ID");
        }
Пример #6
0
        private static void ProcessConcentrationEffects()
        {
            // Loop through each creature. If they have a concentration ability active,
            // process it using that perk's OnConcentrationTick() method.
            for (int index = ConcentratingCreatures.Count - 1; index >= 0; index--)
            {
                var  creature      = ConcentratingCreatures.ElementAt(index);
                var  activeAbility = GetActiveConcentrationEffect(creature);
                int  perkID        = (int)activeAbility.Type;
                int  tier          = activeAbility.Tier;
                bool ended         = false;

                // If we have an invalid creature for any reason, remove it and move to the next one.
                if (!creature.IsValid || creature.CurrentHP <= 0 || activeAbility.Type == PerkType.Unknown)
                {
                    ConcentratingCreatures.RemoveAt(index);
                    continue;
                }

                // Track the current tick.
                int tick = creature.GetLocalInt("ACTIVE_CONCENTRATION_ABILITY_TICK") + 1;
                creature.SetLocalInt("ACTIVE_CONCENTRATION_ABILITY_TICK", tick);

                PerkFeat perkFeat = DataService.PerkFeat.GetByPerkIDAndLevelUnlocked(perkID, tier);

                // Are we ready to continue processing this concentration effect?
                if (tick % perkFeat.ConcentrationTickInterval != 0)
                {
                    continue;
                }

                // Get the perk handler, FP cost, and the target.
                var      handler   = PerkService.GetPerkHandler(perkID);
                int      fpCost    = handler.FPCost(creature, perkFeat.ConcentrationFPCost, tier);
                NWObject target    = creature.GetLocalObject("CONCENTRATION_TARGET");
                int      currentFP = GetCurrentFP(creature);
                int      maxFP     = GetMaxFP(creature);

                // Is the target still valid?
                if (!target.IsValid || target.CurrentHP <= 0)
                {
                    creature.SendMessage("Concentration effect has ended because your target is no longer valid.");
                    EndConcentrationEffect(creature);
                    ended = true;
                }
                // Does player have enough FP to maintain this concentration?
                else if (currentFP < fpCost)
                {
                    creature.SendMessage("Concentration effect has ended because you ran out of FP.");
                    EndConcentrationEffect(creature);
                    ended = true;
                }
                // Is the target still within range and in the same area?
                else if (creature.Area.Object != target.Area.Object ||
                         _.GetDistanceBetween(creature, target) > 50.0f)
                {
                    creature.SendMessage("Concentration effect has ended because your target has gone out of range.");
                    EndConcentrationEffect(creature);
                    ended = true;
                }
                // Otherwise deduct the required FP.
                else
                {
                    currentFP -= fpCost;
                }

                SetCurrentFP(creature, currentFP);

                // Send a FP status message if the effect ended or it's been six seconds since the last one.
                if (ended || tick % 6 == 0)
                {
                    creature.SendMessage(ColorTokenService.Custom("FP: " + currentFP + " / " + maxFP, 32, 223, 219));
                }

                // Run this individual perk's concentration tick method if it didn't end this tick.
                if (!ended && target.IsValid)
                {
                    handler.OnConcentrationTick(creature, target, tier, tick);
                }
            }
        }
Пример #7
0
        private static void OnModuleUseFeat()
        {
            NWPlayer   pc       = Object.OBJECT_SELF;
            NWCreature target   = NWNXEvents.OnFeatUsed_GetTarget().Object;
            int        featID   = NWNXEvents.OnFeatUsed_GetFeatID();
            var        perkFeat = DataService.SingleOrDefault <PerkFeat>(x => x.FeatID == featID);

            if (perkFeat == null)
            {
                return;
            }
            Data.Entity.Perk perk = DataService.GetAll <Data.Entity.Perk>().SingleOrDefault(x => x.ID == perkFeat.PerkID);
            if (perk == null)
            {
                return;
            }

            // Check to see if we are a spaceship.  Spaceships can't use abilities...
            if (pc.GetLocalInt("IS_SHIP") > 0 || pc.GetLocalInt("IS_GUNNER") > 0)
            {
                pc.SendMessage("You cannot use that ability while piloting a ship.");
                return;
            }

            var perkAction = PerkService.GetPerkHandler(perkFeat.PerkID);

            Player playerEntity = DataService.Get <Player>(pc.GlobalID);
            int    pcPerkLevel  = PerkService.GetPCPerkLevel(pc, perk.ID);

            // If player is disabling an existing stance, remove that effect.
            if (perk.ExecutionTypeID == (int)PerkExecutionType.Stance)
            {
                PCCustomEffect stanceEffect = DataService.SingleOrDefault <PCCustomEffect>(x => x.StancePerkID == perk.ID &&
                                                                                           x.PlayerID == pc.GlobalID);

                if (stanceEffect != null)
                {
                    if (CustomEffectService.RemoveStance(pc))
                    {
                        return;
                    }
                }
            }

            if (pcPerkLevel <= 0)
            {
                pc.SendMessage("You do not meet the prerequisites to use this ability.");
                return;
            }

            if (perkAction.IsHostile() && target.IsPlayer)
            {
                if (!PVPSanctuaryService.IsPVPAttackAllowed(pc, target.Object))
                {
                    return;
                }
            }

            if (pc.Area.Resref != target.Area.Resref ||
                _.LineOfSightObject(pc.Object, target.Object) == 0)
            {
                pc.SendMessage("You cannot see your target.");
                return;
            }

            if (!perkAction.CanCastSpell(pc, target))
            {
                pc.SendMessage(perkAction.CannotCastSpellMessage(pc, target) ?? "That ability cannot be used at this time.");
                return;
            }

            int fpCost = perkAction.FPCost(pc, perkAction.FPCost(pc, perk.BaseFPCost, featID), featID);

            if (playerEntity.CurrentFP < fpCost)
            {
                pc.SendMessage("You do not have enough FP. (Required: " + fpCost + ". You have: " + playerEntity.CurrentFP + ")");
                return;
            }

            if (pc.IsBusy || pc.CurrentHP <= 0)
            {
                pc.SendMessage("You are too busy to activate that ability.");
                return;
            }

            // Check cooldown
            int?       cooldownCategoryID = perkAction.CooldownCategoryID(pc, perk.CooldownCategoryID, featID);
            PCCooldown pcCooldown         = DataService.GetAll <PCCooldown>().SingleOrDefault(x => x.PlayerID == pc.GlobalID &&
                                                                                              x.CooldownCategoryID == cooldownCategoryID);

            if (pcCooldown == null)
            {
                pcCooldown = new PCCooldown
                {
                    CooldownCategoryID = Convert.ToInt32(cooldownCategoryID),
                    DateUnlocked       = DateTime.UtcNow.AddSeconds(-1),
                    PlayerID           = pc.GlobalID
                };

                DataService.SubmitDataChange(pcCooldown, DatabaseActionType.Insert);
            }

            DateTime unlockDateTime = pcCooldown.DateUnlocked;
            DateTime now            = DateTime.UtcNow;

            if (unlockDateTime > now)
            {
                string timeToWait = TimeService.GetTimeToWaitLongIntervals(now, unlockDateTime, false);
                pc.SendMessage("That ability can be used in " + timeToWait + ".");
                return;
            }

            // Force Abilities (aka Spells)
            if (perk.ExecutionTypeID == (int)PerkExecutionType.ForceAbility)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_FORCE);
                ActivateAbility(pc, target, perk, perkAction, pcPerkLevel, PerkExecutionType.ForceAbility, featID);
            }
            // Combat Abilities
            else if (perk.ExecutionTypeID == (int)PerkExecutionType.CombatAbility)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_PHYSICAL);
                ActivateAbility(pc, target, perk, perkAction, pcPerkLevel, PerkExecutionType.CombatAbility, featID);
            }
            // Queued Weapon Skills
            else if (perk.ExecutionTypeID == (int)PerkExecutionType.QueuedWeaponSkill)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_PHYSICAL);
                HandleQueueWeaponSkill(pc, perk, perkAction, featID);
            }
            // Stances
            else if (perk.ExecutionTypeID == (int)PerkExecutionType.Stance)
            {
                target.SetLocalInt(LAST_ATTACK + pc.GlobalID, ATTACK_COMBATABILITY);
                ActivateAbility(pc, target, perk, perkAction, pcPerkLevel, PerkExecutionType.Stance, featID);
            }
        }