Beispiel #1
0
        public void Cast(UserGroup target, Xml.SpawnCastable creatureCastable, Xml.TargetType targetType)
        {
            var inRange = Map.EntityTree.GetObjects(GetViewport()).OfType <User>();

            var result = inRange.Intersect(target.Members).ToList();

            var castable = World.WorldData.GetByIndex <Xml.Castable>(creatureCastable.Name);

            if (targetType == Xml.TargetType.Group)
            {
                foreach (var user in result)
                {
                    UseCastable(castable, user, creatureCastable);
                }
            }

            if (targetType == Xml.TargetType.Random)
            {
                var rngSelection = _random.Next(0, result.Count);

                var user = result[rngSelection];

                UseCastable(castable, user, creatureCastable);
            }

            Condition.Casting = false;
        }
Beispiel #2
0
        public void Cast(Creature target, Xml.SpawnCastable creatureCastable)
        {
            var castable = World.WorldData.GetByIndex <Xml.Castable>(creatureCastable.Name);

            if (target is Merchant)
            {
                return;
            }
            UseCastable(castable, target, creatureCastable);
            Condition.Casting = false;
        }
Beispiel #3
0
        public Xml.SpawnCastable SelectSpawnCastable(SpawnCastType castType)
        {
            Xml.SpawnCastable creatureCastable = null;
            switch (castType)
            {
            case SpawnCastType.Offensive:
                creatureCastable = _castables.Offense.Castables.PickRandom(true);
                break;

            case SpawnCastType.Defensive:
                creatureCastable = _castables.Defense.Castables.PickRandom(true);
                break;

            case SpawnCastType.NearDeath:
                creatureCastable = _castables.NearDeath.Castables.PickRandom(true);
                break;

            case SpawnCastType.OnDeath:
                creatureCastable = _castables.OnDeath.PickRandom(true);
                break;
            }

            return(creatureCastable);
        }
Beispiel #4
0
        public virtual bool UseCastable(Xml.Castable castObject, Creature target = null, Xml.SpawnCastable spawnCastable = null)
        {
            if (!Condition.CastingAllowed)
            {
                return(false);
            }

            if (this is User)
            {
                GameLog.UserActivityInfo($"UseCastable: {Name} begin casting {castObject.Name} on target: {target?.Name ?? "no target"} CastingAllowed: {Condition.CastingAllowed}");
            }

            var             damage  = castObject.Effects.Damage;
            List <Creature> targets = new List <Creature>();

            if (this is Monster)
            {
                if (spawnCastable != null)
                {
                    damage = new Xml.CastableDamage
                    {
                        Simple = new Xml.SimpleQuantity
                        {
                            Min = (uint)spawnCastable.MinDmg,
                            Max = (uint)spawnCastable.MaxDmg
                        }
                    };

                    castObject.Effects.Damage = damage;                //set damage based on spawncastable settings.
                    castObject.Element        = spawnCastable.Element; //handle defined element without redoing a ton of code.
                }
            }

            targets = GetTargets(castObject, target);

            // Quick checks
            // If no targets and is not an assail, do nothing
            if (targets.Count() == 0 && castObject.IsAssail == false && string.IsNullOrEmpty(castObject.Script))
            {
                GameLog.UserActivityInfo($"UseCastable: {Name}: no targets and not assail");
                return(false);
            }
            // Is this a pvpable spell? If so, is pvp enabled?

            // We do these next steps to ensure effects are displayed uniformly and as fast as possible
            var deadMobs = new List <Creature>();

            if (castObject.Effects?.Animations?.OnCast != null)
            {
                foreach (var tar in targets)
                {
                    foreach (var user in tar.viewportUsers.ToList())
                    {
                        GameLog.UserActivityInfo($"UseCastable: Sending {user.Name} effect for {Name}: {castObject.Effects.Animations.OnCast.Target.Id}");
                        user.SendEffect(tar.Id, castObject.Effects.Animations.OnCast.Target.Id, castObject.Effects.Animations.OnCast.Target.Speed);
                    }
                }
                if (castObject.Effects?.Animations?.OnCast?.SpellEffect != null)
                {
                    GameLog.UserActivityInfo($"UseCastable: Sending spelleffect for {Name}: {castObject.Effects.Animations.OnCast.SpellEffect.Id}");
                    Effect(castObject.Effects.Animations.OnCast.SpellEffect.Id, castObject.Effects.Animations.OnCast.SpellEffect.Speed);
                }
            }

            if (castObject.Effects?.Sound != null)
            {
                PlaySound(castObject.Effects.Sound.Id);
            }

            GameLog.UserActivityInfo($"UseCastable: {Name} casting {castObject.Name}, {targets.Count()} targets");

            if (!string.IsNullOrEmpty(castObject.Script))
            {
                // If a script is defined we fire it immediately, and let it handle targeting / etc
                if (Game.World.ScriptProcessor.TryGetScript(castObject.Script, out Script script))
                {
                    return(script.ExecuteFunction("OnUse", this));
                }
                else
                {
                    GameLog.UserActivityError($"UseCastable: {Name} casting {castObject.Name}: castable script {castObject.Script} missing");
                    return(false);
                }
            }
            if (targets.Count == 0)
            {
                GameLog.UserActivityError("{Name}: {castObject.Name}: hey fam no targets");
            }

            foreach (var tar in targets)
            {
                if (castObject.Effects?.ScriptOverride == true)
                {
                    // TODO: handle castables with scripting
                    // DoStuff();
                    continue;
                }
                if (!castObject.Effects.Damage.IsEmpty)
                {
                    Xml.Element attackElement;
                    var         damageOutput = NumberCruncher.CalculateDamage(castObject, tar, this);
                    if (castObject.Element == Xml.Element.Random)
                    {
                        Random rnd      = new Random();
                        var    Elements = Enum.GetValues(typeof(Xml.Element));
                        attackElement = (Xml.Element)Elements.GetValue(rnd.Next(Elements.Length));
                    }
                    else if (castObject.Element != Xml.Element.None)
                    {
                        attackElement = castObject.Element;
                    }
                    else
                    {
                        attackElement = (Stats.OffensiveElementOverride != Xml.Element.None ? Stats.OffensiveElementOverride : Stats.BaseOffensiveElement);
                    }
                    GameLog.UserActivityInfo($"UseCastable: {Name} casting {castObject.Name} - target: {tar.Name} damage: {damageOutput}, element {attackElement}");

                    tar.Damage(damageOutput.Amount, attackElement, damageOutput.Type, damageOutput.Flags, this, false);

                    if (this is Monster)
                    {
                        if (tar is User)
                        {
                            (tar as User).SendSystemMessage($"{this.Name} attacks you with {castObject.Name}.");
                        }
                    }

                    if (this is User)
                    {
                        if (Equipment.Weapon != null && !Equipment.Weapon.Undamageable)
                        {
                            Equipment.Weapon.Durability -= 1 / (Equipment.Weapon.MaximumDurability * ((100 - Stats.Ac) == 0 ? 1 : (100 - Stats.Ac)));
                        }
                    }

                    if (tar.Stats.Hp <= 0)
                    {
                        deadMobs.Add(tar);
                    }
                }
                // Note that we ignore castables with both damage and healing effects present - one or the other.
                // A future improvement might be to allow more complex effects.
                else if (!castObject.Effects.Heal.IsEmpty)
                {
                    var healOutput = NumberCruncher.CalculateHeal(castObject, tar, this);
                    tar.Heal(healOutput, this);
                    if (this is User)
                    {
                        GameLog.UserActivityInfo($"UseCastable: {Name} casting {castObject.Name} - target: {tar.Name} healing: {healOutput}");
                        if (Equipment.Weapon != null && !Equipment.Weapon.Undamageable)
                        {
                            Equipment.Weapon.Durability -= 1 / (Equipment.Weapon.MaximumDurability * ((100 - Stats.Ac) == 0 ? 1 : (100 - Stats.Ac)));
                        }
                    }
                }

                // Handle statuses

                foreach (var status in castObject.Effects.Statuses.Add.Where(e => e.Value != null))
                {
                    Xml.Status applyStatus;
                    if (World.WorldData.TryGetValue <Xml.Status>(status.Value.ToLower(), out applyStatus))
                    {
                        var duration = status.Duration == 0 ? applyStatus.Duration : status.Duration;
                        GameLog.UserActivityInfo($"UseCastable: {Name} casting {castObject.Name} - applying status {status.Value} - duration {duration}");
                        tar.ApplyStatus(new CreatureStatus(applyStatus, tar, castObject, this, duration));
                    }
                    else
                    {
                        GameLog.UserActivityError($"UseCastable: {Name} casting {castObject.Name} - failed to add status {status.Value}, does not exist!");
                    }
                }

                foreach (var status in castObject.Effects.Statuses.Remove)
                {
                    Xml.Status applyStatus;
                    if (World.WorldData.TryGetValue <Xml.Status>(status.ToLower(), out applyStatus))
                    {
                        GameLog.UserActivityError($"UseCastable: {Name} casting {castObject.Name} - removing status {status}");
                        tar.RemoveStatus(applyStatus.Icon);
                    }
                    else
                    {
                        GameLog.UserActivityError($"UseCastable: {Name} casting {castObject.Name} - failed to remove status {status}, does not exist!");
                    }
                }
            }

            // Now flood away
            foreach (var dead in deadMobs)
            {
                World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.HandleDeath, dead));
            }
            Condition.Casting = false;
            return(true);
        }