Beispiel #1
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 =>
            {
                behaviour.OnPhysicalAttacked();
            });

            return(true);
        }
        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>
        /// Retrieves the DateTime in which the specified cooldownCategoryID will be available for usel
        /// </summary>
        /// <param name="activator">The creature whose cooldown we're checking.</param>
        /// <param name="cooldownCategoryID">The cooldown category we're checking for.</param>
        /// <returns></returns>
        private static DateTime GetAbilityCooldownUnlocked(NWCreature activator, int cooldownCategoryID)
        {
            // Players: Retrieve info from cache/DB, if it doesn't exist create a new record and insert it. Return unlock date.
            if (activator.IsPlayer)
            {
                PCCooldown pcCooldown = DataService.PCCooldown.GetByPlayerAndCooldownCategoryIDOrDefault(activator.GlobalID, cooldownCategoryID);
                if (pcCooldown == null)
                {
                    pcCooldown = new PCCooldown
                    {
                        CooldownCategoryID = Convert.ToInt32(cooldownCategoryID),
                        DateUnlocked       = DateTime.UtcNow.AddSeconds(-1),
                        PlayerID           = activator.GlobalID
                    };

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

                return(pcCooldown.DateUnlocked);
            }
            // Creatures: Retrieve info from local variable, convert to DateTime if possible. Return parsed unlock date.
            else
            {
                string unlockDate = activator.GetLocalString("ABILITY_COOLDOWN_ID_" + cooldownCategoryID);
                if (string.IsNullOrWhiteSpace(unlockDate))
                {
                    return(DateTime.UtcNow.AddSeconds(-1));
                }
                else
                {
                    return(DateTime.ParseExact(unlockDate, "yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture));
                }
            }
        }
Beispiel #4
0
        public bool Run(params object[] args)
        {
            NWCreature self = Object.OBJECT_SELF;

            _skill.OnCreatureDeath(self);
            _loot.OnCreatureDeath(self);
            _quest.OnCreatureDeath(self);
            _creatureCorpse.OnCreatureDeath();

            if (_cache.CustomObjectData.ContainsKey(self.GlobalID))
            {
                _cache.CustomObjectData.Remove(self.GlobalID);
            }

            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 =>
            {
                behaviour.OnDeath();
            });

            return(true);
        }
Beispiel #5
0
        private static string GetBehaviourScript(NWCreature self)
        {
            string creatureScript = self.GetLocalString("BEHAVIOUR");

            if (string.IsNullOrWhiteSpace(creatureScript))
            {
                creatureScript = self.GetLocalString("BEHAVIOR");
            }
            if (string.IsNullOrWhiteSpace(creatureScript))
            {
                creatureScript = self.GetLocalString("SCRIPT");
            }

            // Fall back to standard behaviour if a script can't be found.
            if (string.IsNullOrWhiteSpace(creatureScript) ||
                !_aiBehaviours.ContainsKey(creatureScript))
            {
                return("StandardBehaviour");
            }

            return(creatureScript);
        }
Beispiel #6
0
        public virtual void OnConversation(NWCreature self)
        {
            string convo = self.GetLocalString("CONVERSATION");

            if (!string.IsNullOrWhiteSpace(convo))
            {
                NWPlayer player = (GetLastSpeaker());
                DialogService.StartConversation(player, self, convo);
            }
            else if (!string.IsNullOrWhiteSpace(NWNXObject.GetDialogResref(self)))
            {
                BeginConversation(NWNXObject.GetDialogResref(self));
            }
        }
Beispiel #7
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);
        }
        private void HandleEvadeOrDeflectBlasterFire()
        {
            DamageData data = _nwnxDamage.GetDamageEventData();

            if (data.Total <= 0)
            {
                return;
            }
            NWCreature damager = data.Damager.Object;
            NWCreature target  = Object.OBJECT_SELF;

            NWItem damagerWeapon = _.GetLastWeaponUsed(damager);
            NWItem targetWeapon  = target.RightHand;

            int perkLevel;

            // Attacker isn't using a pistol or rifle. Return.
            if (damagerWeapon.CustomItemType != CustomItemType.BlasterPistol &&
                damagerWeapon.CustomItemType != CustomItemType.BlasterRifle)
            {
                return;
            }

            int    modifier;
            string action;

            // Check target's equipped weapon, armor and perk.
            if (target.Chest.CustomItemType == CustomItemType.LightArmor &&
                (targetWeapon.CustomItemType == CustomItemType.MartialArtWeapon ||
                 !target.RightHand.IsValid && !target.LeftHand.IsValid))
            {
                // Martial Arts (weapon or unarmed) uses the Evade Blaster Fire perk which is primarily DEX based.
                perkLevel = _perk.GetPCPerkLevel(target.Object, PerkType.EvadeBlasterFire);
                modifier  = target.DexterityModifier;
                action    = "evade";
            }
            else if (target.Chest.CustomItemType == CustomItemType.ForceArmor &&
                     (targetWeapon.CustomItemType == CustomItemType.Lightsaber ||
                      targetWeapon.CustomItemType == CustomItemType.Saberstaff ||
                      targetWeapon.GetLocalInt("LIGHTSABER") == TRUE))
            {
                // Lightsabers (lightsaber or saberstaff) uses the Deflect Blaster Fire perk which is primarily CHA based.
                perkLevel = _perk.GetPCPerkLevel(target.Object, PerkType.DeflectBlasterFire);
                modifier  = target.CharismaModifier;
                action    = "deflect";
            }
            else
            {
                return;
            }

            // Don't have the perk. Return.
            if (perkLevel <= 0)
            {
                return;
            }

            // Check attacker's DEX against the primary stat of the perk.
            int delta = modifier - damager.DexterityModifier;

            if (delta <= 0)
            {
                return;
            }

            // Has the delay between block/evade attempts past?
            DateTime cooldown       = DateTime.UtcNow;
            string   lastAttemptVar = target.GetLocalString("EVADE_OR_DEFLECT_BLASTER_FIRE_COOLDOWN");

            if (!string.IsNullOrWhiteSpace(lastAttemptVar))
            {
                cooldown = DateTime.Parse(lastAttemptVar);
            }

            // Cooldown hasn't expired yet. Not ready to attempt a deflect.
            if (cooldown >= DateTime.UtcNow)
            {
                return;
            }

            // Ready to attempt a deflect. Adjust chance based on the delta of attacker DEX versus primary stat of defender.
            int chanceToDeflect = 5 * delta;

            if (chanceToDeflect > 80)
            {
                chanceToDeflect = 80;
            }

            int delay; // Seconds delay between deflect attempts.

            switch (perkLevel)
            {
            case 1:
                delay = 18;
                break;

            case 2:
                delay = 12;
                break;

            case 3:
                delay = 6;
                break;

            default: throw new Exception("HandleEvadeOrDeflectBlasterFire -> Perk Level " + perkLevel + " unsupported.");
            }

            cooldown = DateTime.UtcNow.AddSeconds(delay);
            target.SetLocalString("EVADE_OR_DEFLECT_BLASTER_FIRE_COOLDOWN", cooldown.ToString(CultureInfo.InvariantCulture));

            int roll = _random.D100(1);

            if (roll <= chanceToDeflect)
            {
                target.SendMessage(_color.Gray("You " + action + " a blaster shot."));
                data.AdjustAllByPercent(-1);
                _nwnxDamage.SetDamageEventData(data);
            }
            else
            {
                target.SendMessage(_color.Gray("You fail to " + action + " a blaster shot. (" + roll + " vs " + chanceToDeflect + ")"));
            }
        }
Beispiel #9
0
 /// <summary>
 /// Sets event scripts base on local variables and deletes the local variables when done.
 /// </summary>
 /// <param name="creature">The creatures whose events we're enabling</param>
 private static void EnableCreatureEvents(NWCreature creature)
 {
     // NOTE: Don't disable the spawn-in event because it's necessary for AI to work.
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_HEARTBEAT"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_NOTICE, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_NOTICE"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_SPELLCASTAT"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_MELEE_ATTACKED"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_DAMAGED, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DAMAGED"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_DISTURBED, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DISTURBED"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_END_COMBATROUND"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DIALOGUE"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_RESTED, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_RESTED"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_DEATH, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DEATH"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_USER_DEFINED_EVENT"));
     SetEventScript(creature, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_BLOCKED_BY_DOOR"));
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_HEARTBEAT");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_NOTICE");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_SPELLCASTAT");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_MELEE_ATTACK");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DAMAGED");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DISTURBED");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_END_COMBATROUND");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DIALOGUE");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_RESTED");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DEATH");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_USER_DEFINED_EVENT");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_BLOCKED_BY_DOOR");
 }
Beispiel #10
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 #11
0
 /// <summary>
 /// Sets event scripts base on local variables and deletes the local variables when done.
 /// </summary>
 /// <param name="creature">The creatures whose events we're enabling</param>
 private static void EnableCreatureEvents(NWCreature creature)
 {
     // NOTE: Don't disable the spawn-in event because it's necessary for AI to work.
     SetEventScript(creature, EventScript.Creature_OnHeartbeat, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_HEARTBEAT"));
     SetEventScript(creature, EventScript.Creature_OnNotice, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_NOTICE"));
     SetEventScript(creature, EventScript.Creature_OnSpellCastAt, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_SPELLCASTAT"));
     SetEventScript(creature, EventScript.Creature_OnMeleeAttacked, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_MELEE_ATTACKED"));
     SetEventScript(creature, EventScript.Creature_OnDamaged, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DAMAGED"));
     SetEventScript(creature, EventScript.Creature_OnDisturbed, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DISTURBED"));
     SetEventScript(creature, EventScript.Creature_OnEndCombatRound, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_END_COMBATROUND"));
     SetEventScript(creature, EventScript.Creature_OnDialogue, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DIALOGUE"));
     SetEventScript(creature, EventScript.Creature_OnRested, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_RESTED"));
     SetEventScript(creature, EventScript.Creature_OnDeath, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_DEATH"));
     SetEventScript(creature, EventScript.Creature_OnUserDefined, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_USER_DEFINED_EVENT"));
     SetEventScript(creature, EventScript.Creature_OnBlockedByDoor, creature.GetLocalString("SPAWN_CREATURE_EVENT_ON_BLOCKED_BY_DOOR"));
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_HEARTBEAT");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_NOTICE");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_SPELLCASTAT");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_MELEE_ATTACK");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DAMAGED");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DISTURBED");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_END_COMBATROUND");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DIALOGUE");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_RESTED");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_DEATH");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_USER_DEFINED_EVENT");
     creature.DeleteLocalString("SPAWN_CREATURE_EVENT_ON_BLOCKED_BY_DOOR");
 }
Beispiel #12
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 #13
0
        private static int CalculateForceAccuracy(
            NWCreature caster,
            NWCreature target,
            ForceAbilityType abilityType)
        {
            EffectiveItemStats casterItemStats = caster.IsPlayer ?
                                                 PlayerStatService.GetPlayerItemEffectiveStats(caster.Object) :
                                                 null;
            float casterPrimary;
            float casterSecondary;
            float casterItemAccuracy = casterItemStats?.ForceAccuracy ?? 0;

            EffectiveItemStats targetItemStats = target.IsPlayer ?
                                                 PlayerStatService.GetPlayerItemEffectiveStats(target.Object) :
                                                 null;
            float targetPrimary;
            float targetSecondary;
            float targetItemDefense = targetItemStats?.ForceDefense ?? 0;

            switch (abilityType)
            {
            case ForceAbilityType.Electrical:
                casterPrimary     = caster.Intelligence;
                casterSecondary   = caster.Wisdom;
                targetPrimary     = target.Intelligence;
                targetSecondary   = target.Wisdom;
                targetItemDefense = targetItemDefense + targetItemStats?.ElectricalDefense ?? 0;
                break;

            case ForceAbilityType.Dark:
                casterPrimary     = caster.Intelligence;
                casterSecondary   = caster.Wisdom;
                targetPrimary     = target.Wisdom;
                targetSecondary   = target.Intelligence;
                targetItemDefense = targetItemDefense + targetItemStats?.DarkDefense ?? 0;
                break;

            case ForceAbilityType.Mind:
                casterPrimary     = caster.Wisdom;
                casterSecondary   = caster.Intelligence;
                targetPrimary     = target.Wisdom;
                targetSecondary   = target.Intelligence;
                targetItemDefense = targetItemDefense + targetItemStats?.MindDefense ?? 0;
                break;

            case ForceAbilityType.Light:
                casterPrimary     = caster.Wisdom;
                casterSecondary   = caster.Intelligence;
                targetPrimary     = target.Intelligence;
                targetSecondary   = target.Wisdom;
                targetItemDefense = targetItemDefense + targetItemStats?.ElectricalDefense ?? 0;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(abilityType), abilityType, null);
            }

            // Calculate accuracy based on the caster's primary and secondary stats. Add modifiers for overall item accuracy.
            float baseAccuracy = caster.Charisma * 0.25f + casterPrimary * 0.75f + casterSecondary * 0.5f + casterItemAccuracy * 0.15f;

            // Calculate defense based on target's primary and secondary stats. Add modifiers for specific defense types.
            float baseDefense = target.Charisma * 0.25f + targetPrimary * 0.75f + targetSecondary * 0.5f + targetItemDefense * 0.15f;

            // Temp defense increases whenever a hostile force ability is used. This is primarily a deterrant towards spamming the same ability over and over.
            string expiration = target.GetLocalString("TEMP_FORCE_DEFENSE_" + (int)abilityType);

            if (DateTime.TryParse(expiration, out var unused))
            {
                int tempDefense = target.GetLocalInt("TEMP_FORCE_DEFENSE_" + (int)abilityType);
                baseDefense += tempDefense;
            }


            float delta         = baseAccuracy - baseDefense;
            float finalAccuracy = delta < 0 ?
                                  75 + (float)Math.Floor(delta / 2.0f) :
                                  75 + delta;

            // Accuracy cannot go above 95% or below 0%
            if (finalAccuracy > 95)
            {
                finalAccuracy = 95;
            }
            else if (finalAccuracy < 0)
            {
                finalAccuracy = 0;
            }

            return((int)finalAccuracy);
        }