Exemple #1
0
        public void TestAngle1()
        {
            int cote1          = 3;
            int coteHypotenuse = 5;

            double anglePrevu = Math.Acos(cote1 / coteHypotenuse);

            double angleTest = positionDeReference.Angle(position);

            Assert.AreEqual(anglePrevu, angleTest);
        }
        public static void Init()
        {
            max    = ServerConfig.MaxViewDistance;
            width  = max * 2 + 1;
            height = max * 2 + 1;

            angles       = new float[width * height];
            distances    = new float[width * height];
            intDistances = new int[width * height];
            directions   = new Direction[width * height];

            var centerPos = new Position(center, center);

            for (var x = 0; x < width; x++)
            {
                for (var y = 0; y < height; y++)
                {
                    var pos = new Position(x, y);

                    distances[x + y * width]    = CalcDistance(x, y, center, center);
                    intDistances[x + y * width] = (int)Math.Round(distances[x + y * width]);

                    var angle  = centerPos.Angle(pos);
                    var facing = Directions.GetFacingForAngle(angle);

                    angles[x + y * width]     = angle;
                    directions[x + y * width] = facing;
                }
            }
        }
        public static float Angle(Position p1, Position p2)
        {
            var offset = p1 - p2;

            if (offset.SquareDistance(Position.Zero) > max)
            {
                return(p1.Angle(p2));
            }

            return(angles[(offset.X + center) + (offset.Y + center) * width]);
        }
        public static Direction Direction(Position p1, Position p2)
        {
            var offset = p2 - p1;

            if (offset.SquareDistance(Position.Zero) > max)
            {
                var angle = p1.Angle(p2);
                return(Directions.GetFacingForAngle(angle));
            }

            return(directions[(offset.X + center) + (offset.Y + center) * width]);
        }
        public void TryUseItem(int time, SlotData slot, Position target)
        {
            if (!ValidTime(time))
            {
#if DEBUG
                Program.Print(PrintType.Error, "Invalid time useitem");
#endif
                Client.Disconnect();
                return;
            }

            if (slot.SlotId == HealthPotionSlotId)
            {
                if (HealthPotions > 0 && !HasConditionEffect(ConditionEffectIndex.Sick))
                {
                    Heal(100, false);
                    HealthPotions--;
                }
                return;
            }
            else if (slot.SlotId == MagicPotionSlotId)
            {
                if (MagicPotions > 0 && !HasConditionEffect(ConditionEffectIndex.Quiet))
                {
                    Heal(100, true);
                    MagicPotions--;
                }
                return;
            }

            Entity en = Parent.GetEntity(slot.ObjectId);
            if (slot.SlotId != 1)
            {
                (en as IContainer)?.UpdateInventorySlot(slot.SlotId);
            }
            if (en == null || !(en is IContainer))
            {
#if DEBUG
                Program.Print(PrintType.Error, "Undefined entity");
#endif
                return;
            }

            if (en is Player && !en.Equals(this))
            {
#if DEBUG
                Program.Print(PrintType.Error, "Trying to use items from another players inventory");
#endif
                return;
            }

            if (en is Container c)
            {
                if ((en as Container).OwnerId != -1 && (en as Container).OwnerId != Id)
                {
#if DEBUG
                    Program.Print(PrintType.Error, "Trying to use items from another players container/bag");
#endif
                    return;
                }

                if (en.Position.Distance(this) > ContainerMinimumDistance)
                {
#if DEBUG
                    Program.Print(PrintType.Error, "Too far away from container");
#endif
                    return;
                }
            }

            IContainer con  = en as IContainer;
            ItemDesc   desc = null;
            if (con.Inventory[slot.SlotId] != -1)
            {
                desc = Resources.Type2Item[(ushort)con.Inventory[slot.SlotId]];
            }

            if (desc == null)
            {
#if DEBUG
                Program.Print(PrintType.Error, "Invalid use item");
#endif
                return;
            }

            bool isAbility = slot.SlotId == 1;
            if (isAbility)
            {
                if (slot.ObjectId != Id)
                {
#if DEBUG
                    Program.Print(PrintType.Error, "Trying to use ability from a container?");
#endif
                    return;
                }

                if (UseTime + (UseDuration * (1f / UseCooldownThreshold)) > time)
                {
#if DEBUG
                    Program.Print(PrintType.Error, "Used ability too soon");
#endif
                    return;
                }

                if (MP - desc.MpCost < 0)
                {
#if DEBUG
                    Program.Print(PrintType.Error, "Not enough MP");
#endif
                    return;
                }
            }

            bool   inRange  = Position.Distance(target) <= MaxAbilityDist && Parent.GetTileF(target.X, target.Y) != null;
            Action callback = null;
            foreach (ActivateEffectDesc eff in desc.ActivateEffects)
            {
                switch (eff.Index)
                {
                case ActivateEffectIndex.Shuriken:     //Could be optimized too, it's not great..
                {
                    byte[] nova = GameServer.ShowEffect(ShowEffectIndex.Nova, Id, 0xffeba134, new Position(2.5f, 0));

                    foreach (Entity j in Parent.EntityChunks.HitTest(Position, 2.5f))
                    {
                        if (j is Enemy k &&
                            !k.HasConditionEffect(ConditionEffectIndex.Invincible) &&
                            !k.HasConditionEffect(ConditionEffectIndex.Stasis))
                        {
                            k.ApplyConditionEffect(ConditionEffectIndex.Dazed, 1000);
                        }
                    }

                    List <byte[]>    stars  = new List <byte[]>();
                    HashSet <Entity> seeked = new HashSet <Entity>();
                    int startId             = NextAEProjectileId;
                    NextAEProjectileId += eff.Amount;

                    float angle = Position.Angle(target);
                    float cone  = MathF.PI / 8;
                    for (int i = 0; i < eff.Amount; i++)
                    {
                        Entity t = this.GetNearestEnemy(8, angle, cone, target, seeked) ?? this.GetNearestEnemy(6, seeked);
                        if (t != null)
                        {
                            seeked.Add(t);
                        }
                        int   d = GetNextDamage(desc.Projectile.MinDamage, desc.Projectile.MaxDamage, ItemDatas[slot.SlotId]);
                        float a = t == null?MathUtils.NextAngle() : Position.Angle(t.Position);

                        List <Projectile> p = new List <Projectile>()
                        {
                            new Projectile(this, desc.Projectile, startId + i, time, a, Position, d)
                        };

                        stars.Add(GameServer.ServerPlayerShoot(startId + i, Id, desc.Type, Position, a, 0, p));
                        AwaitProjectiles(p);
                    }

                    foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                    {
                        if (j is Player k)
                        {
                            if (k.Client.Account.Effects || k.Equals(this))
                            {
                                k.Client.Send(nova);
                            }
                            if (k.Client.Account.AllyShots || k.Equals(this))
                            {
                                foreach (byte[] s in stars)
                                {
                                    k.Client.Send(s);
                                }
                            }
                        }
                    }
                }
                break;

                case ActivateEffectIndex.VampireBlast:     //Maybe optimize this...?
                    if (inRange)
                    {
                        byte[] line       = GameServer.ShowEffect(ShowEffectIndex.Line, Id, 0xFFFF0000, target);
                        byte[] burst      = GameServer.ShowEffect(ShowEffectIndex.Burst, Id, 0xFFFF0000, target, new Position(target.X + eff.Radius, target.Y));
                        int    lifeSucked = 0;

                        List <Entity> enemies = new List <Entity>();
                        List <Entity> players = new List <Entity>();
                        List <byte[]> flows   = new List <byte[]>();

                        foreach (Entity j in Parent.EntityChunks.HitTest(target, eff.Radius))
                        {
                            if (j is Enemy k &&
                                !k.HasConditionEffect(ConditionEffectIndex.Invincible) &&
                                !k.HasConditionEffect(ConditionEffectIndex.Stasis))
                            {
                                k.Damage(this, eff.TotalDamage, eff.Effects, true, true);
                                lifeSucked += eff.TotalDamage;
                                enemies.Add(k);
                            }
                        }

                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, eff.Radius))
                        {
                            if (j is Player k)
                            {
                                players.Add(k);
                                k.Heal(lifeSucked, false);
                            }
                        }

                        if (enemies.Count > 0)
                        {
                            for (int i = 0; i < 5; i++)
                            {
                                Entity a = enemies[MathUtils.Next(enemies.Count)];
                                Entity b = players[MathUtils.Next(players.Count)];
                                flows.Add(GameServer.ShowEffect(ShowEffectIndex.Flow, b.Id, 0xffffffff, a.Position));
                            }
                        }

                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                        {
                            if (j is Player k)
                            {
                                if (k.Client.Account.Effects)
                                {
                                    k.Client.Send(line);
                                    foreach (byte[] p in flows)
                                    {
                                        k.Client.Send(p);
                                    }
                                }

                                if (k.Client.Account.Effects || k.Equals(this))
                                {
                                    k.Client.Send(burst);
                                }
                            }
                        }
                    }
                    break;

                case ActivateEffectIndex.StasisBlast:
                    if (inRange)
                    {
                        byte[] blast = GameServer.ShowEffect(ShowEffectIndex.Collapse, Id, 0xffffffff,
                                                             target,
                                                             new Position(target.X + 3, target.Y));
                        List <byte[]> notifications = new List <byte[]>();

                        foreach (Entity j in Parent.EntityChunks.HitTest(target, 3))
                        {
                            if (j is Enemy k)
                            {
                                if (k.HasConditionEffect(ConditionEffectIndex.StasisImmune))
                                {
                                    notifications.Add(GameServer.Notification(k.Id, "Immune", 0xff00ff00));
                                    continue;
                                }

                                if (k.HasConditionEffect(ConditionEffectIndex.Stasis))
                                {
                                    continue;
                                }

                                notifications.Add(GameServer.Notification(k.Id, "Stasis", 0xffff0000));
                                k.ApplyConditionEffect(ConditionEffectIndex.Stasis, eff.DurationMS);
                                k.ApplyConditionEffect(ConditionEffectIndex.StasisImmune, eff.DurationMS + 3000);
                            }
                        }

                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                        {
                            if (j is Player k)
                            {
                                if (k.Client.Account.Effects || k.Equals(this))
                                {
                                    k.Client.Send(blast);
                                }
                                if (k.Client.Account.Notifications || k.Equals(this))
                                {
                                    foreach (byte[] n in notifications)
                                    {
                                        k.Client.Send(n);
                                    }
                                }
                            }
                        }
                    }
                    break;

                case ActivateEffectIndex.Trap:
                    if (inRange)
                    {
                        byte[] @throw = GameServer.ShowEffect(ShowEffectIndex.Throw, Id, 0xff9000ff, target);
                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                        {
                            if (j is Player k && (k.Client.Account.Effects || k.Equals(this)))
                            {
                                k.Client.Send(@throw);
                            }
                        }

                        Manager.AddTimedAction(1500, () =>
                        {
                            if (Parent != null)
                            {
                                Parent.AddEntity(new Trap(this, eff.Radius, eff.TotalDamage, eff.Effects), target);
                            }
                        });
                    }
                    break;

                case ActivateEffectIndex.Lightning:
                {
                    float  angle = Position.Angle(target);
                    float  cone  = MathF.PI / 4;
                    Entity start = this.GetNearestEnemy(MaxAbilityDist, angle, cone, target);

                    if (start == null)
                    {
                        float[] angles = new float[3] {
                            angle, angle - cone, angle + cone
                        };
                        byte[][] lines = new byte[3][];
                        for (int i = 0; i < 3; i++)
                        {
                            float x = (int)(MaxAbilityDist * MathF.Cos(angles[i])) + Position.X;
                            float y = (int)(MaxAbilityDist * MathF.Sin(angles[i])) + Position.Y;
                            lines[i] = GameServer.ShowEffect(ShowEffectIndex.Line, Id, 0xffff0088, new Position(x, y), new Position(350, 0));
                        }

                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                        {
                            if (j is Player k && k.Client.Account.Effects)
                            {
                                k.Client.Send(lines[0]);
                                k.Client.Send(lines[1]);
                                k.Client.Send(lines[2]);
                            }
                        }
                    }
                    else
                    {
                        Entity           prev    = this;
                        Entity           current = start;
                        HashSet <Entity> targets = new HashSet <Entity>();
                        List <byte[]>    pkts    = new List <byte[]>();
                        targets.Add(current);
                        (current as Enemy).Damage(this, eff.TotalDamage, eff.Effects, false, true);
                        for (int i = 1; i < eff.MaxTargets + 1; i++)
                        {
                            pkts.Add(GameServer.ShowEffect(ShowEffectIndex.Lightning, prev.Id, 0xffff0088,
                                                           new Position(current.Position.X, current.Position.Y),
                                                           new Position(350, 0)));

                            if (i == eff.MaxTargets)
                            {
                                break;
                            }

                            Entity next = current.GetNearestEnemy(10, targets);
                            if (next == null)
                            {
                                break;
                            }

                            targets.Add(next);
                            (next as Enemy).Damage(this, eff.TotalDamage, eff.Effects, false, true);
                            prev    = current;
                            current = next;
                        }

                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                        {
                            if (j is Player k && k.Client.Account.Effects)
                            {
                                foreach (byte[] p in pkts)
                                {
                                    Console.WriteLine(p.Length);
                                    k.Client.Send(p);
                                }
                            }
                        }
                    }
                }
                break;

                case ActivateEffectIndex.PoisonGrenade:
                    if (inRange)
                    {
                        Placeholder placeholder = new Placeholder();
                        Parent.AddEntity(placeholder, target);

                        byte[] @throw = GameServer.ShowEffect(ShowEffectIndex.Throw, Id, 0xffddff00, target);
                        byte[] nova   = GameServer.ShowEffect(ShowEffectIndex.Nova, placeholder.Id, 0xffddff00, new Position(eff.Radius, 0));

                        foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                        {
                            if (j is Player k && (k.Client.Account.Effects || k.Equals(this)))
                            {
                                k.Client.Send(@throw);
                            }
                        }

                        Manager.AddTimedAction(1500, () =>
                        {
                            if (placeholder.Parent != null)
                            {
                                if (Parent != null)
                                {
                                    foreach (Entity j in Parent.PlayerChunks.HitTest(Position, SightRadius))
                                    {
                                        if (j is Player k && (k.Client.Account.Effects || k.Equals(this)))
                                        {
                                            k.Client.Send(nova);
                                        }
                                    }
                                    foreach (Entity j in Parent.EntityChunks.HitTest(placeholder.Position, eff.Radius))
                                    {
                                        if (j is Enemy e)
                                        {
                                            e.ApplyPoison(this, new ConditionEffectDesc[0], (int)(eff.TotalDamage / (eff.DurationMS / 1000f)), eff.TotalDamage);
                                        }
                                    }
                                }
                                placeholder.Parent.RemoveEntity(placeholder);
                            }
                        });