private static void HandleQueueWeaponSkill(NWCreature activator, Data.Entity.Perk entity, IPerkHandler ability, Feat spellFeatID)
        {
            var    perkFeat           = DataService.PerkFeat.GetByFeatID((int)spellFeatID);
            int?   cooldownCategoryID = ability.CooldownCategoryID(activator, entity.CooldownCategoryID, perkFeat.PerkLevelUnlocked);
            var    cooldownCategory   = DataService.CooldownCategory.GetByID(Convert.ToInt32(cooldownCategoryID));
            string queueUUID          = Guid.NewGuid().ToString();

            activator.SetLocalInt("ACTIVE_WEAPON_SKILL", entity.ID);
            activator.SetLocalString("ACTIVE_WEAPON_SKILL_UUID", queueUUID);
            activator.SetLocalInt("ACTIVE_WEAPON_SKILL_FEAT_ID", (int)spellFeatID);
            activator.SendMessage("Weapon skill '" + entity.Name + "' queued for next attack.");
            SendAOEMessage(activator, activator.Name + " readies weapon skill '" + entity.Name + "'.");

            ApplyCooldown(activator, cooldownCategory, ability, perkFeat.PerkLevelUnlocked, 0.0f);

            // Player must attack within 30 seconds after queueing or else it wears off.
            _.DelayCommand(30f, () =>
            {
                if (activator.GetLocalString("ACTIVE_WEAPON_SKILL_UUID") == queueUUID)
                {
                    activator.DeleteLocalInt("ACTIVE_WEAPON_SKILL");
                    activator.DeleteLocalString("ACTIVE_WEAPON_SKILL_UUID");
                    activator.DeleteLocalInt("ACTIVE_WEAPON_SKILL_FEAT_ID");
                    activator.SendMessage("Your weapon skill '" + entity.Name + "' is no longer queued.");
                    SendAOEMessage(activator, activator.Name + " no longer has weapon skill '" + entity.Name + "' readied.");
                }
            });
        }
        /// <summary>
        /// Sets the max FP for a creature to a specific amount.
        /// </summary>
        /// <param name="creature">The creature whose max FP we're setting.</param>
        /// <param name="amount">The amount of max FP to assign to the creature.</param>
        public static void SetMaxFP(NWCreature creature, int amount)
        {
            if (amount < 0)
            {
                amount = 0;
            }

            if (creature.IsPlayer)
            {
                var player = DataService.Player.GetByID(creature.GlobalID);
                player.MaxFP = amount;
                if (player.CurrentFP > player.MaxFP)
                {
                    player.CurrentFP = player.MaxFP;
                }
                DataService.SubmitDataChange(player, DatabaseActionType.Update);
            }
            else
            {
                if (creature.GetLocalInt("CURRENT_FP") > amount)
                {
                    creature.SetLocalInt("CURRENT_FP", amount);
                }
                creature.SetLocalInt("MAX_FP", amount);
            }
        }
        /// <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);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Sets the current FP amount of a creature to a specific value.
        /// This value must be between 0 and the creature's maximum FP.
        /// </summary>
        /// <param name="creature">The creature whose FP we're setting.</param>
        /// <param name="amount">The amount of FP to set it to.</param>
        public static void SetCurrentFP(NWCreature creature, int amount)
        {
            if (amount < 0)
            {
                amount = 0;
            }

            if (creature.IsPlayer)
            {
                var player = DataService.Get <Player>(creature.GlobalID);
                if (amount > player.MaxFP)
                {
                    amount = player.MaxFP;
                }

                player.CurrentFP = amount;
                DataService.SubmitDataChange(player, DatabaseActionType.Update);
            }
            else
            {
                int maxFP = creature.GetLocalInt("MAX_FP");
                if (amount > maxFP)
                {
                    amount = maxFP;
                }
                creature.SetLocalInt("CURRENT_FP", amount);
            }
        }
Beispiel #5
0
        public void ApplyEffects(NWCreature user, NWItem item, NWObject target, Location targetLocation, CustomData customData)
        {
            Location effectLocation;
            NWPlayer player = (user.Object);

            if (!string.IsNullOrWhiteSpace(target.GetLocalString("RESOURCE_RESREF")))
            {
                ScanResource(user, target);
                DurabilityService.RunItemDecay(player, item, RandomService.RandomFloat(0.05f, 0.1f));
                effectLocation = target.Location;
            }
            else
            {
                user.FloatingText("You cannot scan that object with this type of scanner.");
                return;
            }

            _.ApplyEffectAtLocation(DurationType.Instant, _.EffectVisualEffect(VisualEffect.Vfx_Fnf_Summon_Monster_3), effectLocation);

            if (user.IsPlayer && GetLocalBool(user, target.GlobalID.ToString()) == false)
            {
                int scanningBonus = item.ScanningBonus;
                SkillService.GiveSkillXP(player, SkillType.Harvesting, 150);
                user.SetLocalInt(target.GlobalID.ToString(), 1 + scanningBonus);
            }
        }
Beispiel #6
0
        public void ApplyEffects(NWCreature user, NWItem item, NWObject target, Location targetLocation, CustomData customData)
        {
            NWArea   area          = user.Area;
            NWPlayer player        = new NWPlayer(user);
            string   structureID   = area.GetLocalString("PC_BASE_STRUCTURE_ID");
            Guid     structureGuid = new Guid(structureID);

            PCBaseStructure pcbs      = DataService.PCBaseStructure.GetByID(structureGuid);
            BaseStructure   structure = DataService.BaseStructure.GetByID(pcbs.BaseStructureID);

            int repair    = SkillService.GetPCSkillRank(player, SkillType.Piloting);
            int maxRepair = (int)structure.Durability - (int)pcbs.Durability;

            if (maxRepair < repair)
            {
                repair = maxRepair;
            }

            // TODO - add perks to make repairing faster/better/shinier/etc.
            // Maybe a perk to allow repairing in space, with ground repairs only otherwise?

            NWCreature ship = area.GetLocalObject("CREATURE");

            if (ship.IsValid)
            {
                ship.SetLocalInt("HP", ship.GetLocalInt("HP") + repair);
                ship.FloatingText("Hull repaired: " + ship.GetLocalInt("HP") + "/" + ship.MaxHP);
            }

            pcbs.Durability += repair;
            DataService.SubmitDataChange(pcbs, DatabaseActionType.Update);

            player.SendMessage("Ship repaired for " + repair + " points. (Hull points: " + pcbs.Durability + "/" + structure.Durability + ")");
        }
        private static void CheckForSpellInterruption(NWCreature activator, string spellUUID, Vector position)
        {
            if (activator.GetLocalInt(spellUUID) == (int)SpellStatusType.Completed)
            {
                return;
            }

            Vector currentPosition = activator.Position;

            if (currentPosition.X != position.X ||
                currentPosition.Y != position.Y ||
                currentPosition.Z != position.Z)
            {
                var effect = activator.Effects.SingleOrDefault(x => _.GetEffectTag(x) == "ACTIVATION_VFX");
                if (effect != null)
                {
                    _.RemoveEffect(activator, effect);
                }

                NWNXPlayer.StopGuiTimingBar(activator, "", -1);
                activator.IsBusy = false;
                activator.SetLocalInt(spellUUID, (int)SpellStatusType.Interrupted);
                activator.SendMessage("Your ability has been interrupted.");
                return;
            }

            _.DelayCommand(0.5f, () => { CheckForSpellInterruption(activator, spellUUID, position); });
        }
Beispiel #8
0
        public void ApplyEffects(NWCreature user, NWItem item, NWObject target, Location targetLocation, CustomData customData)
        {
            Location effectLocation;
            NWPlayer player = (user.Object);

            // Targeted a location or self. Locate nearest resource.
            if (!target.IsValid || Equals(user, target))
            {
                ScanArea(user, targetLocation);
                _durability.RunItemDecay(player, item, _random.RandomFloat(0.02f, 0.08f));
                effectLocation = targetLocation;
            }
            else if (!string.IsNullOrWhiteSpace(target.GetLocalString("RESOURCE_RESREF")))
            {
                ScanResource(user, target);
                _durability.RunItemDecay(player, item, _random.RandomFloat(0.05f, 0.1f));
                effectLocation = target.Location;
            }
            else
            {
                user.FloatingText("You cannot scan that object with this type of scanner.");
                return;
            }

            _.ApplyEffectAtLocation(DURATION_TYPE_INSTANT, _.EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3), effectLocation);

            if (user.IsPlayer && user.GetLocalInt(target.GlobalID.ToString()) == FALSE)
            {
                int scanningBonus = item.ScanningBonus;
                _skill.GiveSkillXP(player, SkillType.Harvesting, 150);
                user.SetLocalInt(target.GlobalID.ToString(), 1 + scanningBonus);
            }
        }
Beispiel #9
0
        private void ApplyEffect(NWCreature creature, NWObject target, int spellTier)
        {
            Effect effectMindShield;

            // Handle effects for differing spellTier values
            switch (spellTier)
            {
            case 1:
                effectMindShield = _.EffectImmunity(ImmunityType.Dazed);

                creature.AssignCommand(() =>
                {
                    _.ApplyEffectToObject(DurationType.Temporary, effectMindShield, target, 6.1f);
                });
                break;

            case 2:
                effectMindShield = _.EffectImmunity(ImmunityType.Dazed);
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(ImmunityType.Confused));
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(ImmunityType.Dominate));     // Force Pursuade is DOMINATION effect

                creature.AssignCommand(() =>
                {
                    _.ApplyEffectToObject(DurationType.Temporary, effectMindShield, target, 6.1f);
                });
                break;

            case 3:
                effectMindShield = _.EffectImmunity(ImmunityType.Dazed);
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(ImmunityType.Confused));
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(ImmunityType.Dominate));     // Force Pursuade is DOMINATION effect

                if (target.GetLocalInt("FORCE_DRAIN_IMMUNITY") == 1)
                {
                    creature.SetLocalInt("FORCE_DRAIN_IMMUNITY", 0);
                }
                creature.DelayAssignCommand(() =>
                {
                    creature.DeleteLocalInt("FORCE_DRAIN_IMMUNITY");
                }, 6.1f);

                creature.AssignCommand(() =>
                {
                    _.ApplyEffectToObject(DurationType.Temporary, effectMindShield, target, 6.1f);
                });
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(spellTier));
            }

            // Play VFX
            _.ApplyEffectToObject(DurationType.Instant, _.EffectVisualEffect(VisualEffect.Dur_Mind_Affecting_Positive), target);

            if (creature.IsPlayer)
            {
                SkillService.RegisterPCToAllCombatTargetsForSkill(creature.Object, SkillType.ForceControl, null);
            }
        }
Beispiel #10
0
        public void OnImpact(NWCreature creature, NWObject target, int perkLevel, int spellTier)
        {
            float minimum = creature.Facing - 20;
            float maximum = creature.Facing + 20;

            if (target.Facing >= minimum &&
                target.Facing <= maximum)
            {
                // Mark the player as committing a sneak attack.
                // This is later picked up in the OnApplyDamage event.
                creature.SetLocalInt("SNEAK_ATTACK_ACTIVE", 1);
            }
            else
            {
                creature.SetLocalInt("SNEAK_ATTACK_ACTIVE", 2);
            }
        }
Beispiel #11
0
        private void ApplyEffect(NWCreature creature, NWObject target, int spellTier)
        {
            Effect effectMindShield;

            // Handle effects for differing spellTier values
            switch (spellTier)
            {
            case 1:
                effectMindShield = _.EffectImmunity(IMMUNITY_TYPE_DAZED);

                creature.AssignCommand(() =>
                {
                    _.ApplyEffectToObject(_.DURATION_TYPE_TEMPORARY, effectMindShield, target, 6.1f);
                });
                break;

            case 2:
                effectMindShield = _.EffectImmunity(IMMUNITY_TYPE_DAZED);
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(IMMUNITY_TYPE_CONFUSED));
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(IMMUNITY_TYPE_DOMINATE));     // Force Pursuade is DOMINATION effect

                creature.AssignCommand(() =>
                {
                    _.ApplyEffectToObject(_.DURATION_TYPE_TEMPORARY, effectMindShield, target, 6.1f);
                });
                break;

            case 3:
                effectMindShield = _.EffectImmunity(IMMUNITY_TYPE_DAZED);
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(IMMUNITY_TYPE_CONFUSED));
                effectMindShield = _.EffectLinkEffects(effectMindShield, _.EffectImmunity(IMMUNITY_TYPE_DOMINATE));     // Force Pursuade is DOMINATION effect

                if (target.GetLocalInt("FORCE_DRAIN_IMMUNITY") == 1)
                {
                    creature.SetLocalInt("FORCE_DRAIN_IMMUNITY", 0);
                }
                creature.DelayAssignCommand(() =>
                {
                    creature.DeleteLocalInt("FORCE_DRAIN_IMMUNITY");
                }, 6.1f);

                creature.AssignCommand(() =>
                {
                    _.ApplyEffectToObject(_.DURATION_TYPE_TEMPORARY, effectMindShield, target, 6.1f);
                });
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(spellTier));
            }

            // Play VFX
            _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectVisualEffect(_.VFX_DUR_MIND_AFFECTING_POSITIVE), target);
        }
Beispiel #12
0
        public void OnImpact(NWCreature creature, NWObject target, int perkLevel, int spellTier)
        {
            // Mark the player as performing a recovery blast.
            // This is later picked up in the OnApplyDamage event to reduce all damage to 0.
            creature.SetLocalInt("RECOVERY_BLAST_ACTIVE", 1);

            var members = creature.PartyMembers.Where(x => _.GetDistanceBetween(x, target) <= 10.0f);
            int luck    = PerkService.GetCreaturePerkLevel(creature, PerkType.Lucky);

            foreach (var member in members)
            {
                HealTarget(member, perkLevel, luck);
            }
        }
Beispiel #13
0
        /// <summary>
        /// Looks at the creature's feats and if any of them are Perks, stores the highest
        /// level as a local variable on the creature. This variable is later used when the
        /// creature actually uses the feat.
        /// Also registers all of the available PerkFeats (highest tier) on the creature's Data.
        /// This data is also used in the AI to make decisions quicker.
        /// </summary>
        /// <param name="self">The creature whose perks we're registering.</param>
        private static void RegisterCreaturePerks(NWCreature self)
        {
            var perkFeatCache = new Dictionary <int, AIPerkDetails>();
            var featIDs       = new List <int>();

            // Add all feats the creature has to the list.
            int featCount = NWNXCreature.GetFeatCount(self);

            for (int x = 0; x <= featCount - 1; x++)
            {
                var featID = NWNXCreature.GetFeatByIndex(self, x);
                featIDs.Add((int)featID);
            }

            bool hasPerkFeat = false;
            // Retrieve perk feat information for only those feats registered as a perk.
            var perkFeats = DataService.PerkFeat.GetAllByIDs(featIDs);

            // Mark the highest perk level on the creature.
            foreach (var perkFeat in perkFeats)
            {
                int level = self.GetLocalInt("PERK_LEVEL_" + perkFeat.PerkID);
                if (level >= perkFeat.PerkLevelUnlocked)
                {
                    continue;
                }

                var perk = DataService.Perk.GetByID(perkFeat.PerkID);
                self.SetLocalInt("PERK_LEVEL_" + perkFeat.PerkID, perkFeat.PerkLevelUnlocked);
                perkFeatCache[perkFeat.PerkID] = new AIPerkDetails(perkFeat.FeatID, perk.ExecutionTypeID);
                hasPerkFeat = true;
            }

            // If a builder sets a perk feat but forgets to set the FP, do it automatically.
            if (hasPerkFeat && self.GetLocalInt("MAX_FP") <= 0)
            {
                int fp = 50;
                fp += (self.IntelligenceModifier + self.WisdomModifier + self.CharismaModifier) * 5;
                SetMaxFP(self, fp);
                SetCurrentFP(self, fp);
            }

            if (hasPerkFeat)
            {
                // Store a new dictionary containing PerkID and FeatID onto the creature's data.
                // This is later used in the AI processing for decision making.
                self.Data["PERK_FEATS"] = perkFeatCache;
            }
        }
 public static void StartConcentrationEffect(NWCreature creature, int perkID, int spellTier)
 {
     if (creature.IsPlayer)
     {
         var player = DataService.Player.GetByID(creature.GlobalID);
         player.ActiveConcentrationPerkID = perkID;
         player.ActiveConcentrationTier   = spellTier;
         DataService.SubmitDataChange(player, DatabaseActionType.Update);
     }
     else
     {
         creature.SetLocalInt("ACTIVE_CONCENTRATION_PERK_ID", perkID);
     }
     ConcentratingCreatures.Add(creature);
 }
Beispiel #15
0
        public static void AddTemporaryForceDefense(NWCreature target, ForceAbilityType forceAbility, int amount = 5, int length = 5)
        {
            if (amount <= 0)
            {
                amount = 1;
            }
            string   variable        = "TEMP_FORCE_DEFENSE_" + (int)forceAbility;
            int      tempDefense     = target.GetLocalInt(variable) + amount;
            string   tempDateExpires = target.GetLocalString(variable);
            DateTime expirationDate  = DateTime.UtcNow;

            if (!string.IsNullOrWhiteSpace(tempDateExpires))
            {
                expirationDate = DateTime.Parse(tempDateExpires);
            }

            expirationDate = expirationDate.AddSeconds(length);
            target.SetLocalString(variable, expirationDate.ToString(CultureInfo.InvariantCulture));
            target.SetLocalInt(variable, tempDefense);
        }
Beispiel #16
0
        private static string ProcessEventAndBuildDetails(int eventID)
        {
            string   details = string.Empty;
            NWObject target;
            int      amount;

            switch (eventID)
            {
            case 1:     // Spawn Creature
                string     areaName     = NWNXEvents.OnDMSpawnObject_GetArea().Name;
                NWCreature creature     = NWNXEvents.OnDMSpawnObject_GetObject().Object;
                int        objectTypeID = NWNXEvents.OnDMSpawnObject_GetObjectType();
                float      x            = NWNXEvents.OnDMSpawnObject_GetPositionX();
                float      y            = NWNXEvents.OnDMSpawnObject_GetPositionY();
                float      z            = NWNXEvents.OnDMSpawnObject_GetPositionZ();
                creature.SetLocalInt("DM_SPAWNED", _.TRUE);
                details = areaName + "," + creature.Name + "," + objectTypeID + "," + x + "," + y + "," + z;
                break;

            case 22:     // Give XP
                amount  = NWNXEvents.OnDMGiveXP_GetAmount();
                target  = NWNXEvents.OnDMGiveXP_GetTarget();
                details = amount + "," + target.Name;
                break;

            case 23:     // Give Level
                amount  = NWNXEvents.OnDMGiveLevels_GetAmount();
                target  = NWNXEvents.OnDMGiveLevels_GetTarget();
                details = amount + "," + target.Name;
                break;

            case 24:     // Give Gold
                amount  = NWNXEvents.OnDMGiveGold_GetAmount();
                target  = NWNXEvents.OnDMGiveGold_GetTarget();
                details = amount + "," + target.Name;
                break;
            }

            return(details);
        }
Beispiel #17
0
        public static void StartConcentrationEffect(NWCreature creature, int perkID, int spellTier)
        {
            if (creature.IsPlayer)
            {
                var player = DataService.Player.GetByID(creature.GlobalID);
                player.ActiveConcentrationPerkID = perkID;
                player.ActiveConcentrationTier   = spellTier;
                DataService.SubmitDataChange(player, DatabaseActionType.Update);
            }
            else
            {
                creature.SetLocalInt("ACTIVE_CONCENTRATION_PERK_ID", perkID);
            }

            // If swapping from one concentration to another, remove any existing entries.
            if (ConcentratingCreatures.Contains(creature))
            {
                ConcentratingCreatures.Remove(creature);
            }

            ConcentratingCreatures.Add(creature);
        }
Beispiel #18
0
        private static void OnCreatureSpawn()
        {
            NWCreature self = OBJECT_SELF;

            // Don't modify AI behaviour for DM-spawned creatures.
            if (GetLocalBool(self, "DM_SPAWNED") == true)
            {
                return;
            }

            string script = GetBehaviourScript(OBJECT_SELF);

            if (string.IsNullOrWhiteSpace(script))
            {
                return;
            }
            IAIBehaviour ai = GetAIBehaviour(script);

            if (ai.IgnoreNWNEvents)
            {
                self.SetLocalInt("IGNORE_NWN_EVENTS", 1);
            }
            if (ai.IgnoreOnBlocked)
            {
                self.SetLocalInt("IGNORE_NWN_ON_BLOCKED_EVENT", 1);
            }
            if (ai.IgnoreOnCombatRoundEnd)
            {
                self.SetLocalInt("IGNORE_NWN_ON_COMBAT_ROUND_END_EVENT", 1);
            }
            if (ai.IgnoreOnConversation)
            {
                self.SetLocalInt("IGNORE_NWN_ON_CONVERSATION_EVENT", 1);
            }
            if (ai.IgnoreOnDamaged)
            {
                self.SetLocalInt("IGNORE_NWN_ON_DAMAGED_EVENT", 1);
            }
            if (ai.IgnoreOnDeath)
            {
                self.SetLocalInt("IGNORE_NWN_ON_DEATH_EVENT", 1);
            }
            if (ai.IgnoreOnDisturbed)
            {
                self.SetLocalInt("IGNORE_NWN_ON_DISTURBED_EVENT", 1);
            }
            if (ai.IgnoreOnHeartbeat)
            {
                self.SetLocalInt("IGNORE_NWN_ON_HEARTBEAT_EVENT", 1);
            }
            if (ai.IgnoreOnPerception)
            {
                self.SetLocalInt("IGNORE_NWN_ON_PERCEPTION_EVENT", 1);
            }
            if (ai.IgnoreOnPhysicalAttacked)
            {
                self.SetLocalInt("IGNORE_NWN_ON_PHYSICAL_ATTACKED_EVENT", 1);
            }
            if (ai.IgnoreOnRested)
            {
                self.SetLocalInt("IGNORE_NWN_ON_RESTED_EVENT", 1);
            }
            if (ai.IgnoreOnSpawn)
            {
                self.SetLocalInt("IGNORE_NWN_ON_SPAWN_EVENT", 1);
            }
            if (ai.IgnoreOnSpellCastAt)
            {
                self.SetLocalInt("IGNORE_NWN_ON_SPELL_CAST_AT_EVENT", 1);
            }
            if (ai.IgnoreOnUserDefined)
            {
                self.SetLocalInt("IGNORE_NWN_ON_USER_DEFINED_EVENT", 1);
            }

            _areaAICreatures[self.Area].Add(self);
            ai.OnSpawn(self);
        }
Beispiel #19
0
        public bool Run(params object[] args)
        {
            NWCreature self = Object.OBJECT_SELF;

            string creatureScript = self.GetLocalString("BEHAVIOUR");

            if (string.IsNullOrWhiteSpace(creatureScript))
            {
                creatureScript = self.GetLocalString("BEHAVIOR");
            }
            if (string.IsNullOrWhiteSpace(creatureScript))
            {
                creatureScript = self.GetLocalString("SCRIPT");
            }
            if (string.IsNullOrWhiteSpace(creatureScript))
            {
                return(false);
            }
            if (!App.IsKeyRegistered <IBehaviour>("AI." + creatureScript))
            {
                return(false);
            }

            App.ResolveByInterface <IBehaviour>("AI." + creatureScript, behaviour =>
            {
                if (behaviour.IgnoreNWNEvents)
                {
                    self.SetLocalInt("IGNORE_NWN_EVENTS", 1);
                }
                if (behaviour.IgnoreOnBlocked)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_BLOCKED_EVENT", 1);
                }
                if (behaviour.IgnoreOnCombatRoundEnd)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_COMBAT_ROUND_END_EVENT", 1);
                }
                if (behaviour.IgnoreOnConversation)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_CONVERSATION_EVENT", 1);
                }
                if (behaviour.IgnoreOnDamaged)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_DAMAGED_EVENT", 1);
                }
                if (behaviour.IgnoreOnDeath)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_DEATH_EVENT", 1);
                }
                if (behaviour.IgnoreOnDisturbed)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_DISTURBED_EVENT", 1);
                }
                if (behaviour.IgnoreOnHeartbeat)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_HEARTBEAT_EVENT", 1);
                }
                if (behaviour.IgnoreOnPerception)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_PERCEPTION_EVENT", 1);
                }
                if (behaviour.IgnoreOnPhysicalAttacked)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_PHYSICAL_ATTACKED_EVENT", 1);
                }
                if (behaviour.IgnoreOnRested)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_RESTED_EVENT", 1);
                }
                if (behaviour.IgnoreOnSpawn)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_SPAWN_EVENT", 1);
                }
                if (behaviour.IgnoreOnSpellCastAt)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_SPELL_CAST_AT_EVENT", 1);
                }
                if (behaviour.IgnoreOnUserDefined)
                {
                    self.SetLocalInt("IGNORE_NWN_ON_USER_DEFINED_EVENT", 1);
                }

                if (behaviour.Behaviour != null)
                {
                    var result = behaviour.Behaviour
                                 .End()
                                 .Build();
                    _behaviour.RegisterBehaviour(result, self);
                }

                behaviour.OnSpawn();
            });

            return(true);
        }
Beispiel #20
0
        private bool UseFeat(int featID, string featName, NWCreature caster, NWCreature target)
        {
            // Note - this code is loosely based on code from AbilityService.  However, the perk interface
            // is written assuming players will always be using perks.  To allow NPCs to use them requires some hackery.
            int perkLevel = (int)caster.ChallengeRating / 5;

            if (perkLevel < 1)
            {
                perkLevel = 1;
            }

            if (caster.Area.Resref != target.Area.Resref ||
                _.LineOfSightObject(caster.Object, target.Object) == 0)
            {
                return(false);
            }

            // Give NPCs a bit longer range than most PCs.
            if (_.GetDistanceBetween(caster, target) > 20.0f)
            {
                return(false);
            }

            // Note - NPCs are assumed to have infinite FPs.
            if (_.GetIsDead(caster) == 1)
            {
                return(false);
            }

            // Cooldown of 1 round.
            string   timeout    = caster.GetLocalString("TIMEOUT_" + featName);
            DateTime unlockTime = DateTime.UtcNow;

            if (!string.IsNullOrWhiteSpace(timeout))
            {
                unlockTime = DateTime.Parse(timeout);
            }
            DateTime now = DateTime.UtcNow;

            if (unlockTime > now)
            {
                return(false);
            }
            else
            {
                unlockTime = now.AddSeconds(6);
                caster.SetLocalString("TIMEOUT_" + featName, unlockTime.ToString());
            }

            // Do the actual force attack.  Code taken from perks.
            if (featID == (int)CustomFeatType.ForceLightning)
            {
                int length;
                int dotAmount;

                int         basePotency;
                const float Tier1Modifier = 1.0f;
                const float Tier2Modifier = 1.6f;
                const float Tier3Modifier = 2.2f;
                const float Tier4Modifier = 0;

                switch (perkLevel)
                {
                case 1:
                    basePotency = 15;
                    length      = 0;
                    dotAmount   = 0;
                    break;

                case 2:
                    basePotency = 20;
                    length      = 6;
                    dotAmount   = 4;
                    break;

                case 3:
                    basePotency = 25;
                    length      = 6;
                    dotAmount   = 6;
                    break;

                case 4:
                    basePotency = 40;
                    length      = 12;
                    dotAmount   = 6;
                    break;

                case 5:
                    basePotency = 50;
                    length      = 12;
                    dotAmount   = 6;
                    break;

                case 6:
                    basePotency = 60;
                    length      = 12;
                    dotAmount   = 6;
                    break;

                case 7:
                    basePotency = 70;
                    length      = 12;
                    dotAmount   = 6;
                    break;

                case 8:
                    basePotency = 80;
                    length      = 12;
                    dotAmount   = 8;
                    break;

                case 9:
                    basePotency = 90;
                    length      = 12;
                    dotAmount   = 8;
                    break;

                default:
                    basePotency = 100;
                    length      = 12;
                    dotAmount   = 10;
                    break;
                }

                var calc = CombatService.CalculateForceDamage(
                    caster,
                    target.Object,
                    ForceAbilityType.Electrical,
                    basePotency,
                    Tier1Modifier,
                    Tier2Modifier,
                    Tier3Modifier,
                    Tier4Modifier);

                caster.AssignCommand(() => {
                    _.SetFacingPoint(target.Location.Position);
                    _.ActionPlayAnimation(ANIMATION_LOOPING_CONJURE1, 1.0f, 1.0f);
                });

                caster.SetLocalInt("CASTING", 1);

                _.DelayCommand(1.0f, () =>
                {
                    caster.AssignCommand(() =>
                    {
                        Effect damage = _.EffectDamage(calc.Damage, DAMAGE_TYPE_ELECTRICAL);
                        _.ApplyEffectToObject(DURATION_TYPE_INSTANT, damage, target);
                    });

                    if (length > 0.0f && dotAmount > 0)
                    {
                        CustomEffectService.ApplyCustomEffect(caster, target.Object, CustomEffectType.ForceShock, length, perkLevel, dotAmount.ToString());
                    }

                    caster.AssignCommand(() =>
                    {
                        _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, _.EffectVisualEffect(VFX_BEAM_LIGHTNING), target, 1.0f);
                        caster.DeleteLocalInt("CASTING");
                    });

                    CombatService.AddTemporaryForceDefense(target.Object, ForceAbilityType.Electrical);
                });
            }
            else if (featID == (int)CustomFeatType.DrainLife)
            {
                float       recoveryPercent;
                int         basePotency;
                const float Tier1Modifier = 1;
                const float Tier2Modifier = 2;
                const float Tier3Modifier = 0;
                const float Tier4Modifier = 0;

                switch (perkLevel)
                {
                case 1:
                    basePotency     = 10;
                    recoveryPercent = 0.2f;
                    break;

                case 2:
                    basePotency     = 15;
                    recoveryPercent = 0.2f;
                    break;

                case 3:
                    basePotency     = 20;
                    recoveryPercent = 0.4f;
                    break;

                case 4:
                    basePotency     = 25;
                    recoveryPercent = 0.4f;
                    break;

                default:
                    basePotency     = 30;
                    recoveryPercent = 0.5f;
                    break;
                }

                var calc = CombatService.CalculateForceDamage(
                    caster,
                    target.Object,
                    ForceAbilityType.Dark,
                    basePotency,
                    Tier1Modifier,
                    Tier2Modifier,
                    Tier3Modifier,
                    Tier4Modifier);

                caster.AssignCommand(() => {
                    _.SetFacingPoint(target.Location.Position);
                    _.ActionPlayAnimation(ANIMATION_LOOPING_CONJURE1, 1.0f, 1.0f);
                });
                caster.SetLocalInt("CASTING", 1);

                _.DelayCommand(1.0f, () =>
                {
                    _.AssignCommand(caster, () =>
                    {
                        int heal = (int)(calc.Damage * recoveryPercent);
                        if (heal > target.CurrentHP)
                        {
                            heal = target.CurrentHP;
                        }

                        _.ApplyEffectToObject(DURATION_TYPE_INSTANT, _.EffectDamage(calc.Damage), target);
                        _.ApplyEffectToObject(DURATION_TYPE_INSTANT, _.EffectHeal(heal), caster);
                        _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, _.EffectVisualEffect(VFX_BEAM_MIND), target, 1.0f);
                        caster.DeleteLocalInt("CASTING");
                    });
                });


                CombatService.AddTemporaryForceDefense(target.Object, ForceAbilityType.Dark);
            }

            return(true);
        }
Beispiel #21
0
        public void OnImpact(NWPlayer player, NWObject target, int perkLevel)
        {
            int   massLevel  = _perk.GetPCPerkLevel(player, PerkType.MassTranquilizer);
            int   tranqLevel = _perk.GetPCPerkLevel(player, PerkType.Tranquilizer);
            int   luck       = _perk.GetPCPerkLevel(player, PerkType.Lucky);
            float duration;
            float range = 5 * massLevel;

            switch (tranqLevel)
            {
            case 0:
                duration = 6;
                break;

            case 1:
                duration = 12;
                break;

            case 2:
                duration = 24;
                break;

            case 3:
                duration = 36;
                break;

            case 4:
                duration = 48;
                break;

            case 5:
                duration = 60;
                break;

            case 6:
                duration = 72;
                break;

            case 7:
                duration = 84;
                break;

            case 8:
                duration = 96;
                break;

            case 9:
                duration = 108;
                break;

            case 10:
                duration = 120;
                break;

            default: return;
            }

            if (_random.D100(1) <= luck)
            {
                duration *= 2;
                player.SendMessage("Lucky shot!");
            }

            int        current = 1;
            NWCreature nearest = _.GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, target, current);

            while (nearest.IsValid)
            {
                if (_.GetDistanceBetween(nearest, target) > range)
                {
                    break;
                }
                if (RemoveExistingEffect(target, duration))
                {
                    continue;
                }

                nearest.SetLocalInt("TRANQUILIZER_EFFECT_FIRST_RUN", 1);
                Effect effect = _.EffectDazed();
                effect = _.EffectLinkEffects(effect, _.EffectVisualEffect(VFX_DUR_IOUNSTONE_BLUE));
                effect = _.TagEffect(effect, "TRANQUILIZER_EFFECT");

                _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, effect, target, duration);

                current++;
                nearest = _.GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, target, current);
            }
        }
Beispiel #22
0
        public bool Run(params object[] args)
        {
            using (new Profiler(nameof(FinishAbilityUse)))
            {
                // These arguments are sent from the AbilityService's ActivateAbility method.
                NWCreature activator    = (NWCreature)args[0];
                string     spellUUID    = Convert.ToString(args[1]);
                int        perkID       = (int)args[2];
                NWObject   target       = (NWObject)args[3];
                int        pcPerkLevel  = (int)args[4];
                int        spellTier    = (int)args[5];
                float      armorPenalty = (float)args[6];

                // Get the relevant perk information from the database.
                Data.Entity.Perk dbPerk = DataService.Single <Data.Entity.Perk>(x => x.ID == perkID);

                // The execution type determines how the perk behaves and the rules surrounding it.
                PerkExecutionType executionType = dbPerk.ExecutionTypeID;

                // Get the class which handles this perk's behaviour.
                IPerkHandler perk = PerkService.GetPerkHandler(perkID);

                // Pull back cooldown information.
                int?cooldownID            = perk.CooldownCategoryID(activator, dbPerk.CooldownCategoryID, spellTier);
                CooldownCategory cooldown = cooldownID == null ? null : DataService.SingleOrDefault <CooldownCategory>(x => x.ID == cooldownID);

                // If the activator interrupted the spell or died, we can bail out early.
                if (activator.GetLocalInt(spellUUID) == (int)SpellStatusType.Interrupted || // Moved during casting
                    activator.CurrentHP < 0 || activator.IsDead)                            // Or is dead/dying
                {
                    activator.DeleteLocalInt(spellUUID);
                    return(false);
                }

                // Remove the temporary UUID which is tracking this spell cast.
                activator.DeleteLocalInt(spellUUID);

                // Force Abilities, Combat Abilities, Stances, and Concentration Abilities
                if (executionType == PerkExecutionType.ForceAbility ||
                    executionType == PerkExecutionType.CombatAbility ||
                    executionType == PerkExecutionType.Stance ||
                    executionType == PerkExecutionType.ConcentrationAbility)
                {
                    // Run the impact script.
                    perk.OnImpact(activator, target, pcPerkLevel, spellTier);

                    // If an animation is specified for this perk, play it now.
                    if (dbPerk.CastAnimationID != null && dbPerk.CastAnimationID > 0)
                    {
                        activator.AssignCommand(() => { _.ActionPlayAnimation((int)dbPerk.CastAnimationID, 1f, 1f); });
                    }

                    // If the target is an NPC, assign enmity towards this creature for that NPC.
                    if (target.IsNPC)
                    {
                        AbilityService.ApplyEnmity(activator, target.Object, dbPerk);
                    }
                }

                // Adjust creature's current FP, if necessary.
                // Adjust FP only if spell cost > 0
                PerkFeat perkFeat = DataService.Single <PerkFeat>(x => x.PerkID == perkID && x.PerkLevelUnlocked == spellTier);
                int      fpCost   = perk.FPCost(activator, perkFeat.BaseFPCost, spellTier);

                if (fpCost > 0)
                {
                    int currentFP = AbilityService.GetCurrentFP(activator);
                    int maxFP     = AbilityService.GetMaxFP(activator);
                    currentFP -= fpCost;
                    AbilityService.SetCurrentFP(activator, currentFP);
                    activator.SendMessage(ColorTokenService.Custom("FP: " + currentFP + " / " + maxFP, 32, 223, 219));
                }

                // Notify activator of concentration ability change and also update it in the DB.
                if (executionType == PerkExecutionType.ConcentrationAbility)
                {
                    AbilityService.StartConcentrationEffect(activator, perkID, spellTier);
                    activator.SendMessage("Concentration ability activated: " + dbPerk.Name);

                    // The Skill Increase effect icon and name has been overwritten. Apply the effect to the player now.
                    // This doesn't do anything - it simply gives a visual cue that the player has an active concentration effect.
                    _.ApplyEffectToObject(_.DURATION_TYPE_PERMANENT, _.EffectSkillIncrease(_.SKILL_USE_MAGIC_DEVICE, 1), activator);
                }

                // Handle applying cooldowns, if necessary.
                if (cooldown != null)
                {
                    AbilityService.ApplyCooldown(activator, cooldown, perk, spellTier, armorPenalty);
                }

                // Mark the creature as no longer busy.
                activator.IsBusy = false;

                // Mark the spell cast as complete.
                activator.SetLocalInt(spellUUID, (int)SpellStatusType.Completed);

                return(true);
            }
        }
Beispiel #23
0
        public void ApplyCustomEffect(NWCreature oCaster, NWCreature oTarget, int customEffectID, int ticks, int effectLevel)
        {
            // Can't apply the effect if the existing one is stronger.
            int existingEffectLevel = GetActiveEffectLevel(oTarget, customEffectID);

            if (existingEffectLevel > effectLevel)
            {
                oCaster.SendMessage("A more powerful effect already exists on your target.");
                return;
            }

            Data.Entities.CustomEffect effectEntity = _db.CustomEffects.Single(x => x.CustomEffectID == customEffectID);

            // PC custom effects are tracked in the database.
            if (oTarget.IsPlayer)
            {
                PCCustomEffect entity = _db.PCCustomEffects.SingleOrDefault(x => x.PlayerID == oTarget.GlobalID && x.CustomEffectID == customEffectID);

                if (entity == null)
                {
                    entity = new PCCustomEffect
                    {
                        PlayerID       = oTarget.GlobalID,
                        CustomEffectID = customEffectID
                    };

                    _db.PCCustomEffects.Add(entity);
                }

                entity.Ticks = ticks;
                _db.SaveChanges();

                oTarget.SendMessage(effectEntity.StartMessage);
            }
            // NPCs custom effects are tracked in server memory.
            else
            {
                // Look for existing effect.
                foreach (var entry in _state.NPCEffects)
                {
                    CasterSpellVO casterSpellModel = entry.Key;

                    if (casterSpellModel.Caster.Equals(oCaster) &&
                        casterSpellModel.CustomEffectID == customEffectID &&
                        casterSpellModel.Target.Equals(oTarget))
                    {
                        _state.NPCEffects[entry.Key] = ticks;
                        return;
                    }
                }

                // Didn't find an existing effect. Create a new one.
                CasterSpellVO spellModel = new CasterSpellVO
                {
                    Caster         = oCaster,
                    CustomEffectID = customEffectID,
                    EffectName     = effectEntity.Name,
                    Target         = oTarget
                };

                _state.NPCEffects[spellModel] = ticks;
            }

            ICustomEffect handler = App.ResolveByInterface <ICustomEffect>("CustomEffect." + effectEntity.ScriptHandler);

            handler?.Apply(oCaster, oTarget);
            oTarget.SetLocalInt("CUSTOM_EFFECT_ACTIVE_" + customEffectID, effectLevel);
        }
Beispiel #24
0
        private static void ActivateAbility(
            NWCreature activator,
            NWObject target,
            Data.Entity.Perk entity,
            IPerkHandler perkHandler,
            int pcPerkLevel,
            PerkExecutionType executionType,
            int spellTier)
        {
            string uuid = Guid.NewGuid().ToString();
            float  baseActivationTime = perkHandler.CastingTime(activator, (float)entity.BaseCastingTime, spellTier);
            float  activationTime     = baseActivationTime;
            var    vfxID       = VisualEffect.Invalid;
            var    animationID = Animation.Invalid;

            if (baseActivationTime > 0f && activationTime < 1.0f)
            {
                activationTime = 1.0f;
            }

            // Force ability armor penalties
            float armorPenalty = 0.0f;

            if (executionType == PerkExecutionType.ForceAbility ||
                executionType == PerkExecutionType.ConcentrationAbility)
            {
                string penaltyMessage = string.Empty;
                foreach (var item in activator.EquippedItems)
                {
                    if (item.CustomItemType == CustomItemType.HeavyArmor)
                    {
                        armorPenalty   = 2;
                        penaltyMessage = "Heavy armor slows your force cooldown by 100%.";
                        break;
                    }
                    else if (item.CustomItemType == CustomItemType.LightArmor)
                    {
                        armorPenalty   = 1.25f;
                        penaltyMessage = "Light armor slows your force cooldown by 25%.";
                    }
                }

                // If there's an armor penalty, send a message to the player.
                if (armorPenalty > 0.0f)
                {
                    activator.SendMessage(penaltyMessage);
                }
            }

            // If player is in stealth mode, force them out of stealth mode.
            if (_.GetActionMode(activator.Object, ActionMode.Stealth))
            {
                _.SetActionMode(activator.Object, ActionMode.Stealth, false);
            }

            // Make the player face their target.
            _.ClearAllActions();
            BiowarePosition.TurnToFaceObject(target, activator);

            // Force and Concentration Abilities will display a visual effect during the casting process.
            if (executionType == PerkExecutionType.ForceAbility ||
                executionType == PerkExecutionType.ConcentrationAbility)
            {
                vfxID       = VisualEffect.Vfx_Dur_Iounstone_Yellow;
                animationID = Animation.LoopingConjure1;
            }

            if (executionType == PerkExecutionType.ConcentrationAbility)
            {
                activator.SetLocalObject("CONCENTRATION_TARGET", target);
            }

            // If a VFX ID has been specified, play that effect instead of the default one.
            if (vfxID != VisualEffect.Invalid)
            {
                var vfx = _.EffectVisualEffect(vfxID);
                vfx = _.TagEffect(vfx, "ACTIVATION_VFX");
                _.ApplyEffectToObject(DurationType.Temporary, vfx, activator.Object, activationTime + 0.2f);
            }

            // If an animation has been specified, make the player play that animation now.
            // bypassing if perk is throw saber due to couldn't get the animation to work via db table edit
            if (animationID != Animation.Invalid && entity.ID != (int)PerkType.ThrowSaber)
            {
                activator.AssignCommand(() => _.ActionPlayAnimation(animationID, 1.0f, activationTime - 0.1f));
            }

            // Mark player as busy. Busy players can't take other actions (crafting, harvesting, etc.)
            activator.IsBusy = true;

            // Non-players can't be interrupted via movement.
            if (!activator.IsPlayer)
            {
                // Begin the check for spell interruption. If the activator moves, the spell will be canceled.
                CheckForSpellInterruption(activator, uuid, activator.Position);
            }

            activator.SetLocalInt(uuid, (int)SpellStatusType.Started);

            // If there's a casting delay, display a timing bar on-screen.
            if (activationTime > 0)
            {
                NWNXPlayer.StartGuiTimingBar(activator, (int)activationTime, string.Empty);
            }

            // Run the FinishAbilityUse event at the end of the activation time.
            int perkID = entity.ID;

            var @event = new OnFinishAbilityUse(activator, uuid, perkID, target, pcPerkLevel, spellTier, armorPenalty);

            activator.DelayEvent(activationTime + 0.2f, @event);
        }
Beispiel #25
0
        public bool Run(params object[] args)
        {
            NWPlayer    player         = (_.GetLastDisturbed());
            NWPlaceable bay            = (Object.OBJECT_SELF);
            int         disturbType    = _.GetInventoryDisturbType();
            NWItem      item           = (_.GetInventoryDisturbItem());
            bool        stronidiumOnly = bay.GetLocalInt("CONTROL_TOWER_FUEL_TYPE") == TRUE;
            string      allowedResref  = stronidiumOnly ? "stronidium" : "fuel_cell";
            string      structureID    = bay.GetLocalString("PC_BASE_STRUCTURE_ID");

            // Check for either fuel cells or stronidium when adding an item to the container.
            if (disturbType == INVENTORY_DISTURB_TYPE_ADDED)
            {
                if (item.Resref != allowedResref)
                {
                    ItemService.ReturnItem(player, item);
                    player.SendMessage("Only " + (stronidiumOnly ? "Stronidium" : "Fuel Cells") + " may be placed inside this fuel bay.");
                    return(false);
                }
            }
            // If the item removed wasn't fuel cells or stronidium, exit early. We don't need to do anything else.
            else if (disturbType == INVENTORY_DISTURB_TYPE_REMOVED)
            {
                if (item.Resref != allowedResref)
                {
                    return(false);
                }
            }

            var structure = DataService.Single <PCBaseStructure>(x => x.ID == new Guid(structureID));
            var pcBase    = DataService.Get <PCBase>(structure.PCBaseID);

            // Calculate how much fuel exists in the bay's inventory.
            int fuelCount = 0;

            foreach (var fuel in bay.InventoryItems)
            {
                fuelCount += fuel.StackSize;
            }

            // If there are extra units of fuel, destroy them. We will set the stack size of the first fuel later on.
            NWItem firstFuel = (_.GetFirstItemInInventory(bay.Object));
            NWItem nextFuel  = (_.GetNextItemInInventory(bay.Object));

            while (nextFuel.IsValid)
            {
                nextFuel.Destroy();
                nextFuel = (_.GetNextItemInInventory(bay.Object));
            }

            int maxFuel;

            // Handle Stronidium fuel process
            if (stronidiumOnly)
            {
                maxFuel = BaseService.CalculateMaxReinforcedFuel(pcBase.ID);

                // For starships only: Add the ship's cargo bonus to the max stronidium amount.
                if (bay.Area.GetLocalInt("BUILDING_TYPE") == (int)Enumeration.BuildingType.Starship)
                {
                    maxFuel += 25 * SpaceService.GetCargoBonus(SpaceService.GetCargoBay(player.Area, null), (int)CustomItemPropertyType.StarshipStronidiumBonus);
                }

                // Did the player put too much fuel inside? Return the excess to their inventory.
                if (fuelCount > maxFuel)
                {
                    int returnAmount = fuelCount - maxFuel;
                    _.CreateItemOnObject("stronidium", player.Object, returnAmount);

                    fuelCount = maxFuel;
                }

                firstFuel.StackSize   = fuelCount;
                pcBase.ReinforcedFuel = fuelCount;

                if (bay.Area.GetLocalInt("BUILDING_TYPE") == (int)Enumeration.BuildingType.Starship)
                {
                    // This is a starship. Update the creature object, if any, with the new fuel count.
                    NWCreature ship = bay.Area.GetLocalObject("CREATURE");

                    if (ship.IsValid)
                    {
                        ship.SetLocalInt("STRONIDIUM", fuelCount);
                    }
                }
            }
            // Handle Fuel Cell process
            else
            {
                maxFuel = BaseService.CalculateMaxFuel(pcBase.ID);

                // For starships only: Add the ship's cargo bonus to the max fuel amount.
                if (bay.Area.GetLocalInt("BUILDING_TYPE") == (int)Enumeration.BuildingType.Starship)
                {
                    maxFuel += 25 * SpaceService.GetCargoBonus(SpaceService.GetCargoBay(player.Area, null), (int)CustomItemPropertyType.StarshipFuelBonus);
                }

                // Did the player put too much fuel inside? Return the excess to their inventory.
                if (fuelCount > maxFuel)
                {
                    int returnAmount = fuelCount - maxFuel;
                    _.CreateItemOnObject("fuel_cell", player.Object, returnAmount);

                    fuelCount = maxFuel;
                }

                firstFuel.StackSize = fuelCount;
                pcBase.Fuel         = fuelCount;
            }

            // Submit a DB data change for the fuel or stronidium amount adjustment.
            DataService.SubmitDataChange(pcBase, DatabaseActionType.Update);

            var tower          = BaseService.GetBaseControlTower(structure.PCBaseID);
            var towerStructure = DataService.Single <BaseStructure>(x => x.ID == tower.BaseStructureID);

            if (towerStructure.BaseStructureTypeID == (int)BaseStructureType.Starship)
            {
                // This is a spaceship, so don't give the feedback message.
                return(true);
            }

            int fuelRating = towerStructure.FuelRating;


            // Stronidium - Every unit lasts for 6 seconds during reinforcement mode.
            if (stronidiumOnly)
            {
                int      seconds  = 6 * fuelCount;
                TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
                player.SendMessage(ColorTokenService.Gray("Reinforcement mode will last for " +
                                                          TimeService.GetTimeLongIntervals(timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, false) +
                                                          " (" + fuelCount + " / " + maxFuel + " units"));
            }
            // Regular fuel cells - Every unit lasts for 45, 15, or 5 minutes depending on the size of the tower.
            else
            {
                int minutes;
                switch (fuelRating)
                {
                case 1:     // Small
                    minutes = 45;
                    break;

                case 2:     // Medium
                    minutes = 15;
                    break;

                case 3:     // Large
                    minutes = 5;
                    break;

                default:
                    throw new Exception("Invalid fuel rating value: " + fuelRating);
                }

                TimeSpan timeSpan = TimeSpan.FromMinutes(minutes * fuelCount);
                player.SendMessage(ColorTokenService.Gray("Fuel will last for " +
                                                          TimeService.GetTimeLongIntervals(timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, false) +
                                                          " (" + fuelCount + " / " + maxFuel + " units)"));
            }


            return(true);
        }
Beispiel #26
0
        public void OnItemDisturbed()
        {
            NWPlaceable bay = OBJECT_SELF;

            // Filer to only events created by a fuel bay, and ignore this event if it was triggered by clearing
            // the inventory when the bay is being destroyed.
            if (bay.Resref != "fuel_bay" || bay.GetLocalBool("SETUP") == true)
            {
                return;
            }

            NWItem   item           = StringToObject(NWNXEvents.GetEventData("ITEM"));
            NWPlayer player         = bay.GetLocalObject("BAY_ACCESSOR");
            var      disturbType    = NWNXEvents.GetCurrentEvent();
            bool     stronidiumOnly = GetLocalBool(bay, "CONTROL_TOWER_FUEL_TYPE");
            string   allowedResref  = stronidiumOnly ? "stronidium" : "fuel_cell";
            string   structureID    = bay.GetLocalString("PC_BASE_STRUCTURE_ID");

            // Check for either fuel cells or stronidium when adding an item to the container.
            if (disturbType == EventType.ItemInventoryAddItemAfter)
            {
                if (item.Resref != allowedResref)
                {
                    ItemService.ReturnItem(player, item);
                    player.SendMessage("Only " + (stronidiumOnly ? "Stronidium" : "Fuel Cells") + " may be placed inside this fuel bay.");
                    return;
                }
            }
            // If the item removed wasn't fuel cells or stronidium, exit early. We don't need to do anything else.
            else if (disturbType == EventType.ItemInventoryRemoveItemAfter)
            {
                if (item.Resref != allowedResref)
                {
                    return;
                }
            }

            var structure = DataService.PCBaseStructure.GetByID(new Guid(structureID));
            var pcBase    = DataService.PCBase.GetByID(structure.PCBaseID);

            // Calculate how much fuel exists in the bay's inventory.
            int fuelCount = 0;

            foreach (var fuel in bay.InventoryItems)
            {
                fuelCount += fuel.StackSize;
            }

            // If there are extra units of fuel, destroy them. We will set the stack size of the first fuel later on.
            NWItem firstFuel = GetFirstItemInInventory(bay.Object);
            NWItem nextFuel  = GetNextItemInInventory(bay.Object);

            while (nextFuel.IsValid)
            {
                nextFuel.Destroy();
                nextFuel = GetNextItemInInventory(bay.Object);
            }

            int maxFuel;

            // Handle Stronidium fuel process
            if (stronidiumOnly)
            {
                maxFuel = BaseService.CalculateMaxReinforcedFuel(pcBase.ID);

                // For starships only: Add the ship's cargo bonus to the max stronidium amount.
                if (bay.Area.GetLocalInt("BUILDING_TYPE") == (int)Enumeration.BuildingType.Starship)
                {
                    maxFuel += 25 * SpaceService.GetCargoBonus(SpaceService.GetCargoBay(player.Area, player), ItemPropertyType.StarshipStronidiumBonus);
                }

                // Did the player put too much fuel inside? Return the excess to their inventory.
                if (fuelCount > maxFuel)
                {
                    int returnAmount = fuelCount - maxFuel;
                    CreateItemOnObject("stronidium", player.Object, returnAmount);

                    fuelCount = maxFuel;
                }

                firstFuel.StackSize   = fuelCount;
                pcBase.ReinforcedFuel = fuelCount;

                if (bay.Area.GetLocalInt("BUILDING_TYPE") == (int)Enumeration.BuildingType.Starship)
                {
                    // This is a starship. Update the creature object, if any, with the new fuel count.
                    NWCreature ship = bay.Area.GetLocalObject("CREATURE");

                    if (ship.IsValid)
                    {
                        ship.SetLocalInt("STRONIDIUM", fuelCount);
                    }
                }
            }
            // Handle Fuel Cell process
            else
            {
                maxFuel = BaseService.CalculateMaxFuel(pcBase.ID);

                // For starships only: Add the ship's cargo bonus to the max fuel amount.
                if (bay.Area.GetLocalInt("BUILDING_TYPE") == (int)Enumeration.BuildingType.Starship)
                {
                    maxFuel += 25 * SpaceService.GetCargoBonus(SpaceService.GetCargoBay(player.Area, player), ItemPropertyType.StarshipFuelBonus);
                }

                // Did the player put too much fuel inside? Return the excess to their inventory.
                if (fuelCount > maxFuel)
                {
                    int returnAmount = fuelCount - maxFuel;
                    CreateItemOnObject("fuel_cell", player.Object, returnAmount);

                    fuelCount = maxFuel;
                }

                firstFuel.StackSize = fuelCount;
                pcBase.Fuel         = fuelCount;
            }

            // Submit a DB data change for the fuel or stronidium amount adjustment.
            DataService.SubmitDataChange(pcBase, DatabaseActionType.Update);

            var tower = BaseService.GetBaseControlTower(structure.PCBaseID);

            if (tower == null)
            {
                Console.WriteLine("Could not locate tower in Fuel Bay. PCBaseID = " + structure.PCBaseID);
                return;
            }

            var towerStructure = DataService.BaseStructure.GetByID(tower.BaseStructureID);

            if (towerStructure.BaseStructureTypeID == (int)BaseStructureType.Starship)
            {
                // This is a spaceship, so don't give the feedback message.
                return;
            }

            int fuelRating = towerStructure.FuelRating;


            // Stronidium - Every unit lasts for 6 seconds during reinforcement mode.
            if (stronidiumOnly)
            {
                int      seconds  = 6 * fuelCount;
                TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
                player.SendMessage(ColorTokenService.Gray("Reinforcement mode will last for " +
                                                          TimeService.GetTimeLongIntervals(timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, false) +
                                                          " (" + fuelCount + " / " + maxFuel + " units"));
            }
            // Regular fuel cells - Every unit lasts for 45, 15, or 5 minutes depending on the size of the tower.
            else
            {
                int minutes;
                switch (fuelRating)
                {
                case 1:     // Small
                    minutes = 45;
                    break;

                case 2:     // Medium
                    minutes = 15;
                    break;

                case 3:     // Large
                    minutes = 5;
                    break;

                default:
                    throw new Exception("Invalid fuel rating value: " + fuelRating);
                }

                TimeSpan timeSpan = TimeSpan.FromMinutes(minutes * fuelCount);
                player.SendMessage(ColorTokenService.Gray("Fuel will last for " +
                                                          TimeService.GetTimeLongIntervals(timeSpan.Days, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, false) +
                                                          " (" + fuelCount + " / " + maxFuel + " units)"));
            }


            return;
        }
Beispiel #27
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);
            }
        }