示例#1
0
文件: Monster_Melee.cs 项目: klp2/ACE
        /// <summary>
        /// Returns the chance for creature to avoid monster attack
        /// </summary>
        public float GetEvadeChance()
        {
            // get monster attack skill
            var target      = AttackTarget as Creature;
            var attackSkill = GetCreatureSkill(GetCurrentAttackSkill()).Current;
            var offenseMod  = GetWeaponOffenseModifier(this);

            attackSkill = (uint)Math.Round(attackSkill * offenseMod);

            //if (IsExhausted)
            //attackSkill = GetExhaustedSkill(attackSkill);

            // get creature defense skill
            var defenseSkill = CurrentAttack == CombatType.Missile ? Skill.MissileDefense : Skill.MeleeDefense;
            var defenseMod   = defenseSkill == Skill.MeleeDefense ? GetWeaponMeleeDefenseModifier(AttackTarget as Creature) : 1.0f;
            var difficulty   = (uint)Math.Round(target.GetCreatureSkill(defenseSkill).Current *defenseMod);

            if (target.IsExhausted)
            {
                difficulty = 0;
            }

            /*var baseStr = offenseMod != 1.0f ? $" (base: {GetCreatureSkill(GetCurrentAttackSkill()).Current})" : "";
             * Console.WriteLine("Attack skill: " + attackSkill + baseStr);
             *
             * baseStr = defenseMod != 1.0f ? $" (base: {player.GetCreatureSkill(defenseSkill).Current})" : "";
             * Console.WriteLine("Defense skill: " + difficulty + baseStr);*/

            var evadeChance = 1.0f - SkillCheck.GetSkillChance((int)attackSkill, (int)difficulty);

            return((float)evadeChance);
        }
示例#2
0
        public void Examine(WorldObject obj)
        {
            var    success  = true;
            var    creature = obj as Creature;
            Player player   = null;

            if (creature != null)
            {
                player = obj as Player;
                var skill = player != null ? Skill.AssessPerson : Skill.AssessCreature;

                var currentSkill = (int)GetCreatureSkill(skill).Current;
                int difficulty   = (int)creature.GetCreatureSkill(Skill.Deception).Current;

                var chance = SkillCheck.GetSkillChance(currentSkill, difficulty);

                if (difficulty == 0 || player != null && !player.GetCharacterOption(CharacterOption.AttemptToDeceiveOtherPlayers))
                {
                    chance = 1.0f;
                }

                success = chance >= ThreadSafeRandom.Next(0.0f, 1.0f);
            }
            Session.Network.EnqueueSend(new GameEventIdentifyObjectResponse(Session, obj, success));

            if (!success && player != null)
            {
                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{Name} tried and failed to assess you!", ChatMessageType.Appraisal));
            }
        }
示例#3
0
        /// <summary>
        /// Returns the chance for player to avoid monster attack
        /// </summary>
        public float GetEvadeChance()
        {
            // get monster attack skill
            var attackSkill = GetCreatureSkill(GetCurrentAttackSkill()).Current;

            if (IsExhausted)
            {
                attackSkill = GetExhaustedSkill(attackSkill);
            }

            // get player defense skill
            var player = AttackTarget as Player;

            var defenseSkill = CurrentAttack == AttackType.Missile ? Skill.MissileDefense : Skill.MeleeDefense;
            var difficulty   = player.GetCreatureSkill(defenseSkill).Current;

            if (player.IsExhausted)
            {
                difficulty = 0;
            }

            //Console.WriteLine("Attack skill: " + attackSkill);
            //Console.WriteLine("Defense skill: " + difficulty);

            var evadeChance = 1.0f - SkillCheck.GetSkillChance((int)attackSkill, (int)difficulty);

            return((float)evadeChance);
        }
示例#4
0
        public void Examine(WorldObject obj)
        {
            var    success  = true;
            var    creature = obj as Creature;
            Player player   = null;

            if (creature != null)
            {
                player = obj as Player;
                var skill = player != null ? Skill.AssessPerson : Skill.AssessCreature;

                var currentSkill = (int)GetCreatureSkill(skill).Current;
                int difficulty   = (int)creature.GetCreatureSkill(Skill.Deception).Current;

                if (PropertyManager.GetBool("assess_creature_mod").Item&& skill == Skill.AssessCreature &&
                    Skills[Skill.AssessCreature].AdvancementClass < SkillAdvancementClass.Trained)
                {
                    currentSkill = (int)((Focus.Current + Self.Current) / 2);
                }

                var chance = SkillCheck.GetSkillChance(currentSkill, difficulty);

                if (difficulty == 0 || player == this || player != null && !player.GetCharacterOption(CharacterOption.AttemptToDeceiveOtherPlayers))
                {
                    chance = 1.0f;
                }

                if ((this is Admin || this is Sentinel) && CloakStatus == CloakStatus.On)
                {
                    chance = 1.0f;
                }

                success = chance >= ThreadSafeRandom.Next(0.0f, 1.0f);
            }

            if (creature is Pet || creature is CombatPet)
            {
                success = true;
            }

            Session.Network.EnqueueSend(new GameEventIdentifyObjectResponse(Session, obj, success));

            if (!success && player != null && !player.SquelchManager.Squelches.Contains(this, ChatMessageType.Appraisal))
            {
                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{Name} tried and failed to assess you!", ChatMessageType.Appraisal));
            }

            // pooky logic - handle monsters attacking on appraisal
            if (creature != null && creature.MonsterState == State.Idle)
            {
                if (creature.Tolerance.HasFlag(Tolerance.Appraise))
                {
                    creature.AttackTarget = this;
                    creature.WakeUp();
                }
            }
        }
示例#5
0
        public void Examine(WorldObject obj)
        {
            //Console.WriteLine($"{Name}.Examine({obj.Name})");

            var    success  = true;
            var    creature = obj as Creature;
            Player player   = null;

            if (creature != null)
            {
                player = obj as Player;
                var skill = player != null ? Skill.AssessPerson : Skill.AssessCreature;

                var currentSkill = (int)GetCreatureSkill(skill).Current;
                int difficulty   = (int)creature.GetCreatureSkill(Skill.Deception).Current;

                if (PropertyManager.GetBool("assess_creature_mod").Item&& skill == Skill.AssessCreature &&
                    Skills[Skill.AssessCreature].AdvancementClass < SkillAdvancementClass.Trained)
                {
                    currentSkill = (int)((Focus.Current + Self.Current) / 2);
                }

                var chance = SkillCheck.GetSkillChance(currentSkill, difficulty);

                if (difficulty == 0 || player == this || player != null && !player.GetCharacterOption(CharacterOption.AttemptToDeceiveOtherPlayers))
                {
                    chance = 1.0f;
                }

                if ((this is Admin || this is Sentinel) && CloakStatus == CloakStatus.On)
                {
                    chance = 1.0f;
                }

                success = chance > ThreadSafeRandom.Next(0.0f, 1.0f);
            }

            if (obj.ResistItemAppraisal >= 999)
            {
                success = false;
            }

            if (creature is Pet || creature is CombatPet)
            {
                success = true;
            }

            if (success)
            {
                CurrentAppraisalTarget = obj.Guid.Full;
            }

            Session.Network.EnqueueSend(new GameEventIdentifyObjectResponse(Session, obj, success));

            OnAppraisal(obj, success);
        }
示例#6
0
        public float GetEvadeChance(WorldObject target)
        {
            // get player attack skill
            var attackSkill = GetEffectiveAttackSkill();

            // get target defense skill
            var difficulty = GetTargetEffectiveDefenseSkill(target);

            var evadeChance = 1.0f - SkillCheck.GetSkillChance((int)attackSkill, (int)difficulty);

            return((float)evadeChance);
        }
示例#7
0
        public float GetEvadeChance(WorldObject target)
        {
            // get player attack skill
            var attackSkill = GetCreatureSkill(GetCurrentWeaponSkill());

            // get target defense skill
            var creature     = target as Creature;
            var defenseSkill = GetAttackType() == AttackType.Melee ? Skill.MeleeDefense : Skill.MissileDefense;
            var difficulty   = creature.GetCreatureSkill(defenseSkill).Current;

            var evadeChance = 1.0f - SkillCheck.GetSkillChance((int)attackSkill.Current, (int)difficulty);

            return((float)evadeChance);
        }
示例#8
0
        /// <summary>
        /// Returns the chance for player to avoid monster attack
        /// </summary>
        /// <returns></returns>
        public float GetEvadeChance()
        {
            // get monster attack skill
            var attackSkill = GetCreatureSkill(GetCurrentAttackSkill());

            // get player defense skill
            var player     = AttackTarget as Player;
            var difficulty = player.GetCreatureSkill(Skill.MeleeDefense).Current;

            //Console.WriteLine("Attack skill: " + attackSkill.Current);
            //Console.WriteLine("Defense skill: " + difficulty);

            var evadeChance = 1.0f - SkillCheck.GetSkillChance((int)attackSkill.Current, (int)difficulty);

            return((float)evadeChance);
        }
示例#9
0
        public static uint GetManaCost(uint difficulty, uint manaCost, uint manaConv)
        {
            // thanks to GDLE for this function!
            if (manaConv == 0)
            {
                return(manaCost);
            }

            // Dropping diff by half as Specced ManaC is only 48 with starter Aug so 50 at level 1 means no bonus
            //   easiest change without having to create two different formulas to try to emulate retail
            var successChance = SkillCheck.GetSkillChance(manaConv, difficulty / 2);
            var roll          = ThreadSafeRandom.Next(0.0f, 1.0f);

            // Luck lowers the roll value to give better outcome
            // e.g. successChance = 0.83 & roll = 0.71 would still provide some savings.
            //   but a luck roll of 0.19 will lower that 0.71 to 0.13 so the caster would
            //   receive a 60% reduction in mana cost.  without the luck roll, 12%
            //   so players will always have a level of "luck" in manacost if they make skill checks
            var luck = ThreadSafeRandom.Next(0.0f, 1.0f);

            if (roll <= successChance)
            {
                manaCost = (uint)Math.Round(manaCost * (1.0f - (successChance - (roll * luck))));
            }

            // above seems to give a good middle of the range
            // seen in pcaps for mana usage for low level chars
            // bug still need a way to give a better reduction for the "lucky"

            // save some calc time if already at 1 mana cost
            if (manaCost > 1)
            {
                successChance = SkillCheck.GetSkillChance(manaConv, difficulty);
                roll          = ThreadSafeRandom.Next(0.0f, 1.0f);

                if (roll <= successChance)
                {
                    manaCost = (uint)Math.Round(manaCost * (1.0f - (successChance - (roll * luck))));
                }
            }

            return(Math.Max(manaCost, 1));
        }
示例#10
0
        public void Examine(WorldObject obj)
        {
            var    success  = true;
            var    creature = obj as Creature;
            Player player   = null;

            if (creature != null)
            {
                player = obj as Player;
                var skill = player != null ? Skill.AssessPerson : Skill.AssessCreature;

                var currentSkill = (int)GetCreatureSkill(skill).Current;
                int difficulty   = (int)creature.GetCreatureSkill(Skill.Deception).Current;

                var chance = SkillCheck.GetSkillChance(currentSkill, difficulty);

                if (difficulty == 0 || player != null && (!player.GetCharacterOption(CharacterOption.AttemptToDeceiveOtherPlayers) || player == this))
                {
                    chance = 1.0f;
                }

                success = chance >= ThreadSafeRandom.Next(0.0f, 1.0f);
            }
            Session.Network.EnqueueSend(new GameEventIdentifyObjectResponse(Session, obj, success));

            if (!success && player != null)
            {
                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{Name} tried and failed to assess you!", ChatMessageType.Appraisal));
            }

            // pooky logic - handle monsters attacking on appraisal
            if (creature != null && creature.MonsterState == State.Idle)
            {
                var tolerance = (Tolerance)(creature.GetProperty(PropertyInt.Tolerance) ?? 0);
                if (tolerance.HasFlag(Tolerance.Appraise))
                {
                    creature.AttackTarget = this;
                    creature.WakeUp();
                }
            }
        }
示例#11
0
        public CastingPreCheckStatus GetCastingPreCheckStatus(Spell spell, uint magicSkill, bool isWeaponSpell)
        {
            var difficulty = spell.Power;

            var castingPreCheckStatus = CastingPreCheckStatus.CastFailed;

            if (magicSkill > 0 && magicSkill >= (int)difficulty - 50)
            {
                var chance = SkillCheck.GetMagicSkillChance((int)magicSkill, (int)difficulty);
                var rng    = ThreadSafeRandom.Next(0.0f, 1.0f);
                if (chance > rng)
                {
                    castingPreCheckStatus = CastingPreCheckStatus.Success;
                }
            }

            // build-in spells never fizzle
            if (isWeaponSpell)
            {
                castingPreCheckStatus = CastingPreCheckStatus.Success;
            }

            // limit casting time between war and void
            if (spell.School == MagicSchool.VoidMagic && LastSuccessCast_School == MagicSchool.WarMagic ||
                spell.School == MagicSchool.WarMagic && LastSuccessCast_School == MagicSchool.VoidMagic)
            {
                // roll each time?
                var timeLimit = ThreadSafeRandom.Next(3.0f, 5.0f);

                if (Time.GetUnixTime() - LastSuccessCast_Time < timeLimit)
                {
                    var curType  = spell.School == MagicSchool.WarMagic ? "War" : "Void";
                    var prevType = LastSuccessCast_School == MagicSchool.VoidMagic ? "Nether" : "Elemental";

                    Session.Network.EnqueueSend(new GameMessageSystemChat($"The {prevType} energies permeating your blood cause this {curType} magic to fail.", ChatMessageType.Magic));

                    castingPreCheckStatus = CastingPreCheckStatus.CastFailed;
                }
            }
            return(castingPreCheckStatus);
        }
示例#12
0
文件: Lock.cs 项目: jacobtipp/trACE
        public static UnlockResults Unlock(WorldObject target, uint playerLockpickSkillLvl, ref int difficulty)
        {
            var isPickable = IsPickable(target);

            if (!isPickable)
            {
                return(UnlockResults.CannotBePicked);
            }

            int?myResistLockpick = GetResistLockpick(target);

            difficulty = myResistLockpick.Value;

            if (target.IsOpen)
            {
                return(UnlockResults.Open);
            }

            if (!target.IsLocked)
            {
                return(UnlockResults.AlreadyUnlocked);
            }

            var pickChance = SkillCheck.GetSkillChance((int)playerLockpickSkillLvl, difficulty);

#if DEBUG
            Debug.WriteLine($"{pickChance.FormatChance()} chance of UnlockSuccess");
#endif

            var dice = ThreadSafeRandom.Next(0.0f, 1.0f);
            if (dice > pickChance)
            {
                return(UnlockResults.PickLockFailed);
            }

            target.IsLocked = false;
            target.EnqueueBroadcast(new GameMessagePublicUpdatePropertyBool(target, PropertyBool.Locked, target.IsLocked));
            //target.CurrentLandblock?.EnqueueBroadcastSound(target, Sound.Lockpicking);
            return(UnlockResults.UnlockSuccess);
        }
示例#13
0
文件: Lock.cs 项目: zarlant/ACE
        public static UnlockResults Unlock(WorldObject me, uint playerLockpickSkillLvl)
        {
            int?myResistLockpick = GetResistLockpick(me);

            if (!myResistLockpick.HasValue || myResistLockpick < 1)
            {
                return(UnlockResults.CannotBePicked);
            }

            if (me.IsOpen ?? false)
            {
                return(UnlockResults.Open);
            }

            if (!me.IsLocked ?? false)
            {
                return(UnlockResults.AlreadyUnlocked);
            }

            var pickChance = SkillCheck.GetSkillChance((int)playerLockpickSkillLvl, (int)myResistLockpick);

#if DEBUG
            Debug.WriteLine($"{pickChance.FormatChance()} chance of UnlockSuccess");
#endif

            var dice = Physics.Common.Random.RollDice(0.0f, 1.0f);
            if (dice > pickChance)
            {
                return(UnlockResults.PickLockFailed);
            }

            me.IsLocked = false;
            me.CurrentLandblock.EnqueueBroadcast(me.Location, Landblock.MaxObjectRange, new GameMessagePublicUpdatePropertyBool(me, PropertyBool.Locked, me.IsLocked ?? false));
            //me.CurrentLandblock.EnqueueBroadcastSound(me, Sound.Lockpicking);
            return(UnlockResults.UnlockSuccess);
        }
示例#14
0
 /// <summary>
 /// Determines whether a spell will be evaded, based upon the caster's magic skill vs target's magic defense skill
 /// </summary>
 /// <param name="casterMagicSkill"></param>
 /// <param name="targetMagicDefenseSkill"></param>
 /// <returns></returns>
 public static bool MagicDefenseCheck(uint casterMagicSkill, uint targetMagicDefenseSkill)
 {
     return(Physics.Common.Random.RollDice(0.0f, 1.0f) < (1.0f - SkillCheck.GetSkillChance((int)casterMagicSkill, (int)targetMagicDefenseSkill)));
 }
示例#15
0
        /// <summary>
        /// Method used for handling player targeted spell casts
        /// </summary>
        public void CreatePlayerSpell(WorldObject target, TargetCategory targetCategory, uint spellId)
        {
            var player         = this;
            var creatureTarget = target as Creature;

            if (player.IsBusy == true)
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, WeenieError.YoureTooBusy));
                return;
            }
            player.IsBusy = true;

            var spell = new Spell(spellId);

            if (spell.NotFound)
            {
                if (spell._spellBase == null)
                {
                    Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, $"SpellId {spellId} Invalid."));
                    Session.Network.EnqueueSend(new GameEventUseDone(Session, WeenieError.None));
                }
                else
                {
                    Session.Network.EnqueueSend(new GameMessageSystemChat($"{spell.Name} spell not implemented, yet!", ChatMessageType.System));
                    Session.Network.EnqueueSend(new GameEventUseDone(Session, WeenieError.MagicInvalidSpellType));
                }

                player.IsBusy = false;
                return;
            }

            if (IsInvalidTarget(spell, target))
            {
                player.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(player.Session, $"{spell.Name} cannot be cast on {target.Name}."));
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, WeenieError.None));
                player.IsBusy = false;
                return;
            }

            // if casting implement has spell built in,
            // use spellcraft from the item, instead of player's magic skill?
            var caster        = GetEquippedWand();
            var isWeaponSpell = IsWeaponSpell(spell);

            // Grab player's skill level in the spell's Magic School
            var magicSkill = player.GetCreatureSkill(spell.School).Current;

            if (isWeaponSpell && caster.ItemSpellcraft != null)
            {
                magicSkill = (uint)caster.ItemSpellcraft;
            }

            if (targetCategory == TargetCategory.WorldObject)
            {
                if (target.Guid != Guid)
                {
                    var targetLoc = target;
                    if (targetLoc.WielderId != null)
                    {
                        targetLoc = CurrentLandblock?.GetObject(targetLoc.WielderId.Value);
                    }

                    float distanceTo = Location.Distance2D(targetLoc.Location);

                    if (distanceTo > spell.BaseRangeConstant + magicSkill * spell.BaseRangeMod)
                    {
                        player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, WeenieError.None),
                                                           new GameMessageSystemChat($"Target is out of range!", ChatMessageType.Magic));
                        player.IsBusy = false;
                        return;
                    }
                }
            }

            var difficulty = spell.Power;

            // is this needed? should talismans remain the same, regardless of player spell formula?
            spell.Formula.GetPlayerFormula(player);

            var castingPreCheckStatus = CastingPreCheckStatus.CastFailed;

            if (magicSkill > 0 && magicSkill >= (int)difficulty - 50)
            {
                var chance = 1.0f - SkillCheck.GetMagicSkillChance((int)magicSkill, (int)difficulty);
                var rng    = ThreadSafeRandom.Next(0.0f, 1.0f);
                if (chance < rng || isWeaponSpell)
                {
                    castingPreCheckStatus = CastingPreCheckStatus.Success;
                }
            }

            // limit casting time between war and void
            if (spell.School == MagicSchool.VoidMagic && LastSuccessCast_School == MagicSchool.WarMagic ||
                spell.School == MagicSchool.WarMagic && LastSuccessCast_School == MagicSchool.VoidMagic)
            {
                // roll each time?
                var timeLimit = ThreadSafeRandom.Next(3.0f, 5.0f);

                if (Time.GetUnixTime() - LastSuccessCast_Time < timeLimit)
                {
                    var curType  = spell.School == MagicSchool.WarMagic ? "War" : "Void";
                    var prevType = LastSuccessCast_School == MagicSchool.VoidMagic ? "Nether" : "Elemental";

                    Session.Network.EnqueueSend(new GameMessageSystemChat($"The {prevType} energies permeating your blood cause this {curType} magic to fail.", ChatMessageType.Magic));

                    castingPreCheckStatus = CastingPreCheckStatus.CastFailed;
                }
            }

            // Calculate mana usage
            uint manaUsed = CalculateManaUsage(player, spell, target);

            var currentMana = player.Mana.Current;

            if (isWeaponSpell)
            {
                currentMana = (uint)(caster.ItemCurMana ?? 0);
            }

            if (manaUsed > currentMana)
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, WeenieError.YouDontHaveEnoughManaToCast));
                IsBusy = false; // delay?
                return;
            }

            // begin spellcasting
            Proficiency.OnSuccessUse(player, player.GetCreatureSkill(Skill.ManaConversion), spell.PowerMod);

            if (!isWeaponSpell)
            {
                player.UpdateVitalDelta(player.Mana, -(int)manaUsed);
            }
            else
            {
                caster.ItemCurMana -= (int)manaUsed;
            }

            spell.Formula.GetPlayerFormula(player);

            string spellWords = spell._spellBase.GetSpellWords(DatManager.PortalDat.SpellComponentsTable);

            if (spellWords != null && !isWeaponSpell)
            {
                EnqueueBroadcast(new GameMessageCreatureMessage(spellWords, Name, Guid.Full, ChatMessageType.Spellcasting));
            }

            var spellChain = new ActionChain();
            var castSpeed  = 2.0f;  // hardcoded for player spell casting?

            var startPos = new Position(Location);

            // do wind-up gestures: fastcast has no windup (creature enchantments)
            if (!spell.Flags.HasFlag(SpellFlags.FastCast) && !isWeaponSpell)
            {
                // note that ACE is currently sending the windup motion and the casting gesture
                // at the same time. the client is automatically queueing these animations to run at the correct time.

                foreach (var windupGesture in spell.Formula.WindupGestures)
                {
                    spellChain.AddAction(this, () =>
                    {
                        var motionWindUp = new Motion(MotionStance.Magic, windupGesture, castSpeed);
                        EnqueueBroadcastMotion(motionWindUp);
                    });
                }
            }

            // cast spell
            spellChain.AddAction(this, () =>
            {
                var castGesture = spell.Formula.CastGesture;
                if (isWeaponSpell && caster.UseUserAnimation != 0)
                {
                    castGesture = caster.UseUserAnimation;
                }

                var motionCastSpell = new Motion(MotionStance.Magic, castGesture, castSpeed);
                EnqueueBroadcastMotion(motionCastSpell);
            });

            var castingDelay = spell.Formula.GetCastTime(MotionTableId, castSpeed, isWeaponSpell);

            spellChain.AddDelaySeconds(castingDelay);

            bool movedTooFar = false;

            spellChain.AddAction(this, () =>
            {
                if (!isWeaponSpell)
                {
                    TryBurnComponents(spell);
                }

                // check windup move distance cap
                var endPos = new Position(Location);
                var dist   = startPos.DistanceTo(endPos);

                if (dist > Windup_MaxMove)
                {
                    castingPreCheckStatus = CastingPreCheckStatus.CastFailed;
                    movedTooFar           = true;
                }

                var pk_error = CheckPKStatusVsTarget(player, target, spell);
                if (pk_error != null)
                {
                    castingPreCheckStatus = CastingPreCheckStatus.InvalidPKStatus;
                }

                var useDone = WeenieError.None;

                switch (castingPreCheckStatus)
                {
                case CastingPreCheckStatus.Success:

                    if ((spell.Flags & SpellFlags.FellowshipSpell) == 0)
                    {
                        CreatePlayerSpell(target, spell);
                    }
                    else
                    {
                        var fellows = GetFellowshipTargets();
                        foreach (var fellow in fellows)
                        {
                            CreatePlayerSpell(fellow, spell);
                        }
                    }
                    break;

                case CastingPreCheckStatus.InvalidPKStatus:

                    if (spell.NumProjectiles > 0)
                    {
                        switch (spell.School)
                        {
                        case MagicSchool.WarMagic:
                            WarMagic(target, spell);
                            break;

                        case MagicSchool.VoidMagic:
                            VoidMagic(target, spell);
                            break;

                        case MagicSchool.LifeMagic:
                            LifeMagic(target, spell, out uint damage, out bool critical, out var enchantmentStatus);
                            break;
                        }
示例#16
0
        /// <summary>
        /// Method used for handling player untargeted spell casts
        /// </summary>
        public void CreatePlayerSpell(uint spellId)
        {
            if (IsBusy == true)
            {
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.YoureTooBusy));
                return;
            }
            else
            {
                IsBusy = true;
            }

            SpellTable spellTable = DatManager.PortalDat.SpellTable;

            if (!spellTable.Spells.ContainsKey(spellId))
            {
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.MagicInvalidSpellType));
                IsBusy = false;
                return;
            }

            SpellBase spell = spellTable.Spells[spellId];

            Database.Models.World.Spell spellStatMod = DatabaseManager.World.GetCachedSpell(spellId);
            if (spellStatMod == null)
            {
                Session.Network.EnqueueSend(new GameMessageSystemChat($"{spell.Name} spell not implemented, yet!", ChatMessageType.System));
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.MagicInvalidSpellType));
                IsBusy = false;
                return;
            }

            // Grab player's skill level in the spell's Magic School
            var magicSkill = GetCreatureSkill(spell.School);

            float scale   = SpellAttributes(Session.Account, spellId, out float castingDelay, out MotionCommand windUpMotion, out MotionCommand spellGesture);
            var   formula = SpellTable.GetSpellFormula(spellTable, spellId, Session.Account);

            bool spellCastSuccess = false || ((Physics.Common.Random.RollDice(0.0f, 1.0f) > (1.0f - SkillCheck.GetMagicSkillChance((int)magicSkill.Current, (int)spell.Power))) &&
                                              (magicSkill.Current >= (int)spell.Power - 50) && (magicSkill.Current > 0));

            // Calculating mana usage
            #region
            if (spellCastSuccess == true)
            {
                CreatureSkill mc = GetCreatureSkill(Skill.ManaConversion);
                double        z  = mc.Current;
                double        baseManaPercent = 1;
                if (z > spell.Power)
                {
                    baseManaPercent = spell.Power / z;
                }
                double preCost;
                uint   manaUsed;
                if ((int)Math.Floor(baseManaPercent) == 1)
                {
                    preCost  = spell.BaseMana;
                    manaUsed = (uint)preCost;
                }
                else
                {
                    preCost = spell.BaseMana * baseManaPercent;
                    if (preCost < 1)
                    {
                        preCost = 1;
                    }
                    manaUsed = (uint)Physics.Common.Random.RollDice(1, (int)preCost);
                }
                if (spell.MetaSpellType == SpellType.Transfer)
                {
                    uint vitalChange, casterVitalChange;
                    vitalChange = (uint)(GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) * spellStatMod.Proportion);
                    if (spellStatMod.TransferCap != 0)
                    {
                        if (vitalChange > spellStatMod.TransferCap)
                        {
                            vitalChange = (uint)spellStatMod.TransferCap;
                        }
                    }
                    casterVitalChange = (uint)(vitalChange * (1.0f - spellStatMod.LossPercent));
                    vitalChange       = (uint)(casterVitalChange / (1.0f - spellStatMod.LossPercent));

                    if (spellStatMod.Source == (int)PropertyAttribute2nd.Mana && (vitalChange + 10 + manaUsed) > Mana.Current)
                    {
                        ActionChain resourceCheckChain = new ActionChain();

                        resourceCheckChain.AddAction(this, () =>
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                        });

                        resourceCheckChain.AddDelaySeconds(2.0f);
                        resourceCheckChain.AddAction(this, () =>
                        {
                            Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                            IsBusy = false;
                        });

                        resourceCheckChain.EnqueueChain();

                        return;
                    }

                    if ((vitalChange + 10) > GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source))
                    {
                        ActionChain resourceCheckChain = new ActionChain();

                        resourceCheckChain.AddAction(this, () =>
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                        });

                        resourceCheckChain.AddDelaySeconds(2.0f);
                        resourceCheckChain.AddAction(this, () => IsBusy = false);
                        resourceCheckChain.EnqueueChain();

                        return;
                    }
                }
                else if (manaUsed > Mana.Current)
                {
                    ActionChain resourceCheckChain = new ActionChain();

                    resourceCheckChain.AddAction(this, () =>
                    {
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                    });

                    resourceCheckChain.AddDelaySeconds(2.0f);
                    resourceCheckChain.AddAction(this, () =>
                    {
                        Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                        IsBusy = false;
                    });

                    resourceCheckChain.EnqueueChain();

                    return;
                }
                else
                {
                    UpdateVital(Mana, Mana.Current - manaUsed);
                }
            }
            #endregion

            ActionChain spellChain = new ActionChain();

            uint fastCast = (spell.Bitfield >> 14) & 0x1u;
            if (fastCast != 1)
            {
                spellChain.AddAction(this, () =>
                {
                    var motionWindUp = new UniversalMotion(MotionStance.Spellcasting);
                    motionWindUp.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                    motionWindUp.MovementData.ForwardCommand = (uint)windUpMotion;
                    motionWindUp.MovementData.ForwardSpeed   = 2;
                    DoMotion(motionWindUp);
                });
            }

            spellChain.AddAction(this, () =>
            {
                CurrentLandblock.EnqueueBroadcast(Location, new GameMessageCreatureMessage(SpellComponentsTable.GetSpellWords(DatManager.PortalDat.SpellComponentsTable,
                                                                                                                              formula), Name, Guid.Full, ChatMessageType.Magic));
            });

            spellChain.AddAction(this, () =>
            {
                var motionCastSpell = new UniversalMotion(MotionStance.Spellcasting);
                motionCastSpell.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionCastSpell.MovementData.ForwardCommand = (uint)spellGesture;
                motionCastSpell.MovementData.ForwardSpeed   = 2;
                DoMotion(motionCastSpell);
            });

            if (fastCast == 1)
            {
                spellChain.AddDelaySeconds(castingDelay * 0.26f);
            }
            else
            {
                spellChain.AddDelaySeconds(castingDelay);
            }

            if (spellCastSuccess == false)
            {
                spellChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)));
            }
            else
            {
                // TODO - Successful spell casting code goes here for untargeted spells to replace line below
                Session.Network.EnqueueSend(new GameMessageSystemChat("Targeted SpellID " + spellId + " not yet implemented!", ChatMessageType.System));
            }

            spellChain.AddAction(this, () =>
            {
                var motionReturnToCastStance = new UniversalMotion(MotionStance.Spellcasting);
                motionReturnToCastStance.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionReturnToCastStance.MovementData.ForwardCommand = (uint)MotionCommand.Invalid;
                DoMotion(motionReturnToCastStance);
            });

            spellChain.AddDelaySeconds(1.0f);

            spellChain.AddAction(this, () =>
            {
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.None));
                IsBusy = false;
            });

            spellChain.EnqueueChain();

            return;
        }
示例#17
0
        /// <summary>
        /// Method used for handling player targeted spell casts
        /// </summary>
        public void CreatePlayerSpell(ObjectGuid guidTarget, uint spellId)
        {
            Player         player         = CurrentLandblock.GetObject(Guid) as Player;
            WorldObject    target         = CurrentLandblock.GetObject(guidTarget);
            TargetCategory targetCategory = TargetCategory.WorldObject;

            if (target == null)
            {
                target         = GetWieldedItem(guidTarget);
                targetCategory = TargetCategory.Wielded;
            }
            if (target == null)
            {
                target         = GetInventoryItem(guidTarget);
                targetCategory = TargetCategory.Inventory;
            }
            if (target == null)
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.TargetNotAcquired));
                targetCategory = TargetCategory.UnDef;
                return;
            }

            SpellTable spellTable = DatManager.PortalDat.SpellTable;

            if (!spellTable.Spells.ContainsKey(spellId))
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicInvalidSpellType));
                return;
            }

            SpellBase spell = spellTable.Spells[spellId];

            if (IsInvalidTarget(spell, target))
            {
                player.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(player.Session, $"{spell.Name} cannot be cast on {target.Name}."));
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.None));
                return;
            }

            Database.Models.World.Spell spellStatMod = DatabaseManager.World.GetCachedSpell(spellId);
            if (spellStatMod == null)
            {
                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{spell.Name} spell not implemented, yet!", ChatMessageType.System));
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicInvalidSpellType));
                return;
            }

            if (player.IsBusy == true)
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YoureTooBusy));
                return;
            }
            else
            {
                player.IsBusy = true;
            }

            uint targetEffect = spell.TargetEffect;

            // Grab player's skill level in the spell's Magic School
            var magicSkill = player.GetCreatureSkill(spell.School).Current;

            if (targetCategory == TargetCategory.WorldObject)
            {
                if (guidTarget != Guid)
                {
                    float distanceTo = Location.Distance2D(target.Location);

                    if (distanceTo > spell.BaseRangeConstant + magicSkill * spell.BaseRangeMod)
                    {
                        player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicTargetOutOfRange),
                                                           new GameMessageSystemChat($"{target.Name} is out of range!", ChatMessageType.Magic));
                        player.IsBusy = false;
                        return;
                    }
                }
            }

            // Ensure that a harmful spell isn't being cast on a player target that doesn't have the same PK status
            if (target.WeenieClassId == 1 && player.PlayerKillerStatus != ACE.Entity.Enum.PlayerKillerStatus.NPK)
            {
                bool isSpellHarmful = IsSpellHarmful(spell);
                if (player.PlayerKillerStatus != target.PlayerKillerStatus && isSpellHarmful)
                {
                    player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.InvalidPkStatus));
                    player.IsBusy = false;
                    return;
                }
            }

            float scale   = SpellAttributes(player.Session.Account, spellId, out float castingDelay, out MotionCommand windUpMotion, out MotionCommand spellGesture);
            var   formula = SpellTable.GetSpellFormula(spellTable, spellId, player.Session.Account);

            bool spellCastSuccess = false || ((Physics.Common.Random.RollDice(0.0f, 1.0f) > (1.0f - SkillCheck.GetMagicSkillChance((int)magicSkill, (int)spell.Power))) &&
                                              (magicSkill >= (int)spell.Power - 50) && (magicSkill > 0));

            // Calculating mana usage
            #region
            CreatureSkill mc = player.GetCreatureSkill(Skill.ManaConversion);
            double        z  = mc.Current;
            double        baseManaPercent = 1;
            if (z > spell.Power)
            {
                baseManaPercent = spell.Power / z;
            }
            double preCost;
            uint   manaUsed;
            if ((int)Math.Floor(baseManaPercent) == 1)
            {
                preCost  = spell.BaseMana;
                manaUsed = (uint)preCost;
            }
            else
            {
                preCost = spell.BaseMana * baseManaPercent;
                if (preCost < 1)
                {
                    preCost = 1;
                }
                manaUsed = (uint)Physics.Common.Random.RollDice(1, (int)preCost);
            }
            if (spell.MetaSpellType == SpellType.Transfer)
            {
                uint vitalChange, casterVitalChange;
                vitalChange = (uint)(player.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) * spellStatMod.Proportion);
                if (spellStatMod.TransferCap != 0)
                {
                    if (vitalChange > spellStatMod.TransferCap)
                    {
                        vitalChange = (uint)spellStatMod.TransferCap;
                    }
                }
                casterVitalChange = (uint)(vitalChange * (1.0f - spellStatMod.LossPercent));
                vitalChange       = (uint)(casterVitalChange / (1.0f - spellStatMod.LossPercent));

                if (spellStatMod.Source == (int)PropertyAttribute2nd.Mana && (vitalChange + 10 + manaUsed) > player.Mana.Current)
                {
                    ActionChain resourceCheckChain = new ActionChain();

                    resourceCheckChain.AddAction(this, () =>
                    {
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                    });

                    resourceCheckChain.AddDelaySeconds(2.0f);
                    resourceCheckChain.AddAction(this, () =>
                    {
                        player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                        player.IsBusy = false;
                    });

                    resourceCheckChain.EnqueueChain();

                    return;
                }
                else if ((vitalChange + 10) > player.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source))
                {
                    ActionChain resourceCheckChain = new ActionChain();

                    resourceCheckChain.AddAction(this, () =>
                    {
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                    });

                    resourceCheckChain.AddDelaySeconds(2.0f);
                    resourceCheckChain.AddAction(this, () => player.IsBusy = false);
                    resourceCheckChain.EnqueueChain();

                    return;
                }
            }
            else if (manaUsed > player.Mana.Current)
            {
                ActionChain resourceCheckChain = new ActionChain();

                resourceCheckChain.AddAction(this, () =>
                {
                    CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                });

                resourceCheckChain.AddDelaySeconds(2.0f);
                resourceCheckChain.AddAction(this, () =>
                {
                    player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                    player.IsBusy = false;
                });

                resourceCheckChain.EnqueueChain();

                return;
            }
            else
            {
                player.UpdateVital(player.Mana, player.Mana.Current - manaUsed);
            }
            #endregion

            ActionChain spellChain = new ActionChain();

            uint fastCast = (spell.Bitfield >> 14) & 0x1u;
            if (fastCast != 1)
            {
                spellChain.AddAction(this, () =>
                {
                    var motionWindUp = new UniversalMotion(MotionStance.Spellcasting);
                    motionWindUp.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                    motionWindUp.MovementData.ForwardCommand = (uint)windUpMotion;
                    motionWindUp.MovementData.ForwardSpeed   = 2;
                    DoMotion(motionWindUp);
                });
            }

            spellChain.AddAction(this, () =>
            {
                CurrentLandblock.EnqueueBroadcast(Location, new GameMessageCreatureMessage(SpellComponentsTable.GetSpellWords(DatManager.PortalDat.SpellComponentsTable,
                                                                                                                              formula), Name, Guid.Full, ChatMessageType.Magic));
            });

            spellChain.AddAction(this, () =>
            {
                var motionCastSpell = new UniversalMotion(MotionStance.Spellcasting);
                motionCastSpell.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionCastSpell.MovementData.ForwardCommand = (uint)spellGesture;
                motionCastSpell.MovementData.ForwardSpeed   = 2;
                DoMotion(motionCastSpell);
            });

            if (fastCast == 1)
            {
                spellChain.AddDelaySeconds(castingDelay * 0.26f);
            }
            else
            {
                spellChain.AddDelaySeconds(castingDelay);
            }

            if (spellCastSuccess == false)
            {
                spellChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)));
            }
            else
            {
                spellChain.AddAction(this, () =>
                {
                    bool targetDeath;
                    string message;

                    switch (spell.School)
                    {
                    case MagicSchool.WarMagic:
                        WarMagic(target, spell, spellStatMod);
                        break;

                    case MagicSchool.VoidMagic:
                        VoidMagic(target, spell, spellStatMod);
                        break;

                    case MagicSchool.CreatureEnchantment:
                        if (IsSpellHarmful(spell))
                        {
                            // Retrieve player's skill level in the Magic School
                            var playerMagicSkill = player.GetCreatureSkill(spell.School).Current;

                            // Retrieve target's Magic Defense Skill
                            Creature creature           = (Creature)target;
                            var targetMagicDefenseSkill = creature.GetCreatureSkill(Skill.MagicDefense).Current;

                            if (MagicDefenseCheck(playerMagicSkill, targetMagicDefenseSkill))
                            {
                                CurrentLandblock.EnqueueBroadcastSound(player, Sound.ResistSpell);
                                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{creature.Name} resists {spell.Name}", ChatMessageType.Magic));
                                break;
                            }
                        }
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale));
                        message = CreatureMagic(target, spell, spellStatMod);
                        if (message != "")
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic));
                        }
                        break;

                    case MagicSchool.LifeMagic:
                        if (spell.MetaSpellType != SpellType.LifeProjectile)
                        {
                            if (IsSpellHarmful(spell))
                            {
                                // Retrieve player's skill level in the Magic School
                                var playerMagicSkill = player.GetCreatureSkill(spell.School).Current;

                                // Retrieve target's Magic Defense Skill
                                Creature creature           = (Creature)target;
                                var targetMagicDefenseSkill = creature.GetCreatureSkill(Skill.MagicDefense).Current;

                                if (MagicDefenseCheck(playerMagicSkill, targetMagicDefenseSkill))
                                {
                                    CurrentLandblock.EnqueueBroadcastSound(player, Sound.ResistSpell);
                                    player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{creature.Name} resists {spell.Name}", ChatMessageType.Magic));
                                    break;
                                }
                            }
                        }
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale));
                        targetDeath = LifeMagic(target, spell, spellStatMod, out message);
                        if (message != null)
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic));
                        }
                        if (targetDeath == true)
                        {
                            Creature creatureTarget = (Creature)target;
                            creatureTarget.Die();
                            Strings.DeathMessages.TryGetValue(DamageType.Base, out var messages);
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(string.Format(messages[0], target.Name), ChatMessageType.Broadcast));
                            player.EarnXP((long)target.XpOverride);
                        }
                        break;

                    case MagicSchool.ItemEnchantment:
                        if (guidTarget == Guid)
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, (PlayScript)spell.CasterEffect, scale));
                        }
                        else
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale));
                        }
                        message = ItemMagic(target, spell, spellStatMod);
                        if (message != "")
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic));
                        }
                        break;

                    default:
                        break;
                    }
                });
            }

            spellChain.AddAction(this, () =>
            {
                var motionReturnToCastStance = new UniversalMotion(MotionStance.Spellcasting);
                motionReturnToCastStance.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionReturnToCastStance.MovementData.ForwardCommand = (uint)MotionCommand.Invalid;
                DoMotion(motionReturnToCastStance);
            });

            spellChain.AddDelaySeconds(1.0f);

            spellChain.AddAction(this, () =>
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.None));
                player.IsBusy = false;
            });

            spellChain.EnqueueChain();

            return;
        }