Esempio n. 1
0
        public void SummonMob()
        {
            if (FieldIdMove == Constants.InvalidMap)
            {
                return;
            }

            if (!DataProvider.Maps.TryGetValue(FieldIdMove, out var field))
            {
                return;
            }

            if (field.Limitations.HasFlag(FieldLimit.SummonLimit))
            {
                return;
            }

            if (!DataProvider.Items.TryGetValue(GetMobItemID, out var itemData))
            {
                return;
            }

            Program.MainForm.LogAppend("Spawning mobs for contimove trip on map " + field.ID);

            var fh = field.GetFootholdUnderneath(MobSpawnPoint.X, MobSpawnPoint.Y, out var maxY);

            foreach (var itemDataSummon in itemData.Summons)
            {
                if (Rand32.Next() % 100 >= itemDataSummon.Chance)
                {
                    continue;
                }
                field.SpawnMobWithoutRespawning(itemDataSummon.MobID, MobSpawnPoint, (byte)(fh.HasValue ? fh.Value.ID : 0));
            }
        }
Esempio n. 2
0
        public void PrevRandomResultIsAccurate()
        {
            var rand = new Rand32(100, 200, 300);
            var prev = rand.Random();

            Assert.Equal(prev, rand.PrevRandom());
        }
        private static ItemSlotEquip ToItemSlot(
            this ItemEquipTemplate template,
            ItemVariationType type = ItemVariationType.None
            )
        {
            var variation = new ItemVariation(Rand32.Create(), type);

            return(new ItemSlotEquip
            {
                TemplateID = template.ID,

                RUC = template.TUC,
                STR = (short)variation.Get(template.IncSTR),
                DEX = (short)variation.Get(template.IncDEX),
                INT = (short)variation.Get(template.IncINT),
                LUK = (short)variation.Get(template.IncLUK),
                MaxHP = (short)variation.Get(template.IncMaxHP),
                MaxMP = (short)variation.Get(template.IncMaxMP),
                PAD = (short)variation.Get(template.IncPAD),
                MAD = (short)variation.Get(template.IncMAD),
                PDD = (short)variation.Get(template.IncPDD),
                MDD = (short)variation.Get(template.IncMDD),
                ACC = (short)variation.Get(template.IncACC),
                EVA = (short)variation.Get(template.IncEVA),
                Craft = (short)variation.Get(template.IncCraft),
                Speed = (short)variation.Get(template.IncSpeed),
                Jump = (short)variation.Get(template.IncJump),
                Durability = 100
            });
        }
Esempio n. 4
0
        public void Init(uint version)
        {
            Rand32 rand1 = new Rand32(version);
            Rand32 rand2 = new Rand32(2 * version);

            shuffle[0] = (byte)(rand1.RandomFloat() * 255.0f);
            shuffle[1] = (byte)(rand2.RandomFloat() * 255.0f);
        }
Esempio n. 5
0
        public static void HandleInteraction(Character chr, Packet packet)
        {
            var petItem = chr.GetSpawnedPet();

            if (petItem == null)
            {
                return;
            }

            bool   success    = false;
            double multiplier = 1.0;
            // 4A 00 00
            byte doMultiplier = packet.ReadByte();

            if (doMultiplier != 0 && Pet.IsNamedPet(petItem))
            {
                multiplier = 1.5;
            }

            byte interactionId = packet.ReadByte(); // dunno lol

            if (!DataProvider.Pets.TryGetValue(petItem.ItemID, out var petData) ||
                !petData.Reactions.TryGetValue(interactionId, out var petReactionData))
            {
                return;
            }

            long timeSinceLastInteraction = MasterThread.CurrentTime - chr.PetLastInteraction;

            // shouldnt be able to do this yet.
            if (petReactionData.LevelMin > petItem.Level ||
                petReactionData.LevelMax < petItem.Level ||
                timeSinceLastInteraction < 15000)
            {
                goto send_response;
            }

            // sick math

            chr.PetLastInteraction = MasterThread.CurrentTime;
            double additionalSucceedProbability = (((timeSinceLastInteraction - 15000.0) / 10000.0) * 0.01 + 1.0) * multiplier;

            var random = Rand32.Next() % 100;

            if (random >= (petReactionData.Prob * additionalSucceedProbability) ||
                petItem.Fullness < 50)
            {
                goto send_response;
            }

            success = true;
            Pet.IncreaseCloseness(chr, petItem, petReactionData.Inc);
            Pet.UpdatePet(chr, petItem);

send_response:
            SendPetInteraction(chr, interactionId, success);
        }
Esempio n. 6
0
        public void DefaultVariationResultIsAccurate()
        {
            var rand      = new Rand32(100, 200, 300);
            var variation = new ItemVariation(rand, ItemVariationType.None);

            Assert.Equal(10, variation.Get(10));
            Assert.Equal(10, variation.Get(10));
            Assert.Equal(10, variation.Get(10));
        }
Esempio n. 7
0
        public void GachaponVariationResultIsAccurate()
        {
            var rand      = new Rand32(100, 200, 300);
            var variation = new ItemVariation(rand, ItemVariationType.Gachapon);

            Assert.Equal(12, variation.Get(10));
            Assert.Equal(11, variation.Get(10));
            Assert.Equal(10, variation.Get(10));
        }
Esempio n. 8
0
        public static void HandleSummonAttack(Character chr, Packet packet)
        {
            if (!ParseAttackData(chr, packet, out AttackData ad, AttackTypes.Summon))
            {
                return;
            }

            var summonId = ad.SummonID;

            if (chr.Summons.GetSummon(summonId, out var summon))
            {
                //SendMagicAttack(chr, ad);
                SendSummonAttack(chr, summon, ad);
                var totalDamage = 0;
                foreach (var ai in ad.Attacks)
                {
                    try
                    {
                        var mob = chr.Field.GetMob(ai.MobMapId);

                        if (mob != null)
                        {
                            foreach (int amount in ai.Damages)
                            {
                                totalDamage += amount;
                                mob.GiveDamage(chr, amount);
                            }

                            var dead = mob.CheckDead(mob.Position, ai.HitDelay, chr.PrimaryStats.BuffMesoUP.N);

                            if (!dead)
                            {
                                switch (summon.SkillId)
                                {
                                case Constants.Ranger.Skills.SilverHawk:
                                case Constants.Sniper.Skills.GoldenEagle:
                                    var sld = CharacterSkills.GetSkillLevelData(summon.SkillId, summon.SkillLevel);
                                    if (!mob.IsBoss && totalDamage > 0 && Rand32.NextBetween(0, 100) < sld.Property)
                                    {
                                        int  stunTime   = ai.HitDelay + 4000;
                                        long expireTime = MasterThread.CurrentTime + stunTime;
                                        var  stat       = mob.Status.BuffStun.Set(summon.SkillId, -1, expireTime);
                                        MobPacket.SendMobStatsTempSet(mob, ai.HitDelay, stat);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Program.MainForm.LogAppend(ex.ToString());
                    }
                }
            }
        }
Esempio n. 9
0
        private static short GetItemAmount(int ItemID, int Min, int Max)
        {
            var ItemType = ItemID / 1000000;

            if (Max > 0 && (ItemType == 2 || ItemType == 3 || ItemType == 4))
            {
                return((short)(Min + Rand32.Next() % (Max - Min + 1)));
            }
            return(1);
        }
Esempio n. 10
0
        public XORCrypter(uint version)
        {
            this.table = new byte[2];

            // Init
            var rand1 = new Rand32(version);
            var rand2 = new Rand32(2 * version);

            table[0] = (byte)(rand1.RandomFloat() * 255.0f);
            table[1] = (byte)(rand2.RandomFloat() * 255.0f);
        }
        public XORCrypter(uint version)
        {
            Table = new byte[2];

            // Init
            Rand32 rand1 = new Rand32(version);
            Rand32 rand2 = new Rand32(2 * version);

            Table[0] = (byte)(rand1.RandomFloat() * 255.0f);
            Table[1] = (byte)(rand2.RandomFloat() * 255.0f);
        }
Esempio n. 12
0
        private static void Shuffle(byte[] data, uint version)
        {
            Rand32 rand32 = new Rand32((uint)Math.Pow(version, 2));

            for (int i = TABLE_SIZE - 1; i >= 1; i--)
            {
                byte rand = (byte)(rand32.Random() % (i + 1));

                byte swap = data[i];
                data[i]    = data[rand];
                data[rand] = swap;
            }
        }
Esempio n. 13
0
        private void OnMigrateIn(InPacket packet)
        {
            var characterID = packet.Decode <int>();

            if (!WvsGame.PendingMigrations.Remove(characterID))
            {
                Channel.CloseAsync();
                return;
            }

            using (var db = _container.GetInstance <DataContext>())
            {
                var character = db.Characters
                                .Include(c => c.Data)
                                .ThenInclude(a => a.Account)
                                .Include(c => c.FunctionKeys)
                                .Include(c => c.Inventories)
                                .ThenInclude(c => c.Items)
                                .Include(c => c.SkillRecords)
                                .Single(c => c.ID == characterID);

                character.Data.Account.State = AccountState.LoggedIn;
                db.Update(character);
                db.SaveChanges();

                var field     = WvsGame.FieldFactory.Get(character.FieldID);
                var fieldUser = new FieldUser(this, character);

                Random    = new Rand32(0x0, 0x0, 0x0);
                FieldUser = fieldUser;
                field.Enter(fieldUser);

                using (var p = new OutPacket(GameSendOperations.FuncKeyMappedInit))
                {
                    var functionKeys = character.FunctionKeys;

                    p.Encode <bool>(false);
                    for (var i = 0; i < 90; i++)
                    {
                        var functionKey = functionKeys.SingleOrDefault(f => f.Key == i);

                        p.Encode <byte>(functionKey?.Type ?? 0);
                        p.Encode <int>(functionKey?.Action ?? 0);
                    }

                    SendPacket(p);
                }
            }
        }
Esempio n. 14
0
        public static void OnStatChangeByMobSkill(Character chr, MobSkillLevelData msld, short delay = 0)
        {
            // See if we can actually set the effect...
            int prop = 100;

            if (msld.Prop != 0)
            {
                prop = msld.Prop;
            }

            if (Rand32.Next() % 100 >= prop)
            {
                return;                              // Luck.
            }
            BuffStat setStat = null;
            int      rValue  = msld.SkillID | (msld.Level << 16);
            var      ps      = chr.PrimaryStats;
            int      nValue  = 1;

            switch ((Constants.MobSkills.Skills)msld.SkillID)
            {
            case Constants.MobSkills.Skills.Seal: setStat = ps.BuffSeal; break;

            case Constants.MobSkills.Skills.Darkness: setStat = ps.BuffDarkness; break;

            case Constants.MobSkills.Skills.Weakness: setStat = ps.BuffWeakness; break;

            case Constants.MobSkills.Skills.Stun: setStat = ps.BuffStun; break;

            case Constants.MobSkills.Skills.Curse: setStat = ps.BuffCurse; break;

            case Constants.MobSkills.Skills.Poison:
                setStat = ps.BuffPoison;
                nValue  = msld.X;
                break;
            }

            if (setStat != null && !setStat.IsSet())
            {
                var buffTime = msld.Time * 1000;
                var stat     = setStat.Set(rValue, (short)nValue, BuffStat.GetTimeForBuff(buffTime + delay));

                if (stat != 0)
                {
                    chr.Buffs.FinalizeBuff(stat, delay);
                }
            }
        }
Esempio n. 15
0
        public static void HandleUseSummonSack(Character chr, Packet packet)
        {
            short slot   = packet.ReadShort();
            int   itemid = packet.ReadInt();

            BaseItem item = chr.Inventory.GetItem(2, slot);

            if (item == null || item.ItemID != itemid || !DataProvider.Items.TryGetValue(itemid, out ItemData data))
            {
                NoChange(chr);
                return;
            }

            if (data.Summons.Count == 0)
            {
                NoChange(chr);
                return;
            }



            if (chr.AssertForHack(
                    chr.Inventory.TakeItemAmountFromSlot(Constants.getInventory(itemid), slot, 1, false) == null,
                    "Tried to use summon sack while not having them (???)"
                    ))
            {
                return;
            }

            foreach (var isi in data.Summons)
            {
                if (DataProvider.Mobs.ContainsKey(isi.MobID))
                {
                    if (Rand32.Next() % 100 < isi.Chance)
                    {
                        chr.Field.SpawnMobWithoutRespawning(isi.MobID, chr.Position, chr.Foothold, summonType: data.Type);
                    }
                }
                else
                {
                    Program.MainForm.LogAppend("Summon sack {0} has mobid that doesn't exist: {1}", itemid, isi.MobID);
                }
            }
            NoChange(chr);
        }
Esempio n. 16
0
        public void ResetEvent()
        {
            EventDoing = false;
            Event      = GetMobItemID != 0 && (Rand32.Next() % 100) <= 30;

            int randomMinutes = (int)(Rand32.Next() % (RequiredMin - 5));

            MobGenTime = NextBoardingTime + ((60 * TimeMultiplier) * (WaitMin + randomMinutes + 2));
            var curTime       = MasterThread.CurrentTime;
            var timeTillSpawn = MobGenTime - curTime;
            var timeTillBoard = NextBoardingTime - curTime;

            if (Event)
            {
                var txt = $"Will spawn crogs on trip {FieldIdStartShipMove} -> {FieldIdEndShipMove} (map {FieldIdMove}) in {(timeTillSpawn / 1000):D} seconds";
                MessagePacket.SendNoticeGMs(txt, MessagePacket.MessageTypes.Notice);
            }
        }
Esempio n. 17
0
        public override void Prepare()
        {
            questions.Clear();

            var page = DataProvider.QuizQuestions[(byte)(1 + Rand32.Next() % 7)];

            while (questions.Count < 10)
            {
                var nextQuestion = page.RandomElement();
                if (!questions.Contains(nextQuestion))
                {
                    questions.Add(nextQuestion);
                }
            }

            QuizMap.ChatEnabled = true;
            QuizMap.PortalsOpen = false;
            base.Prepare();
        }
Esempio n. 18
0
        public override void OnHackDetected()
        {
            if (!Loaded || !HackDetected.HasValue)
            {
                return;
            }
            var character = Player.Character;
            var hack      = HackDetected.Value;

            if (hack.HasFlag(RedisBackend.HackKind.Speedhack))
            {
                MessagePacket.SendNoticeGMs(
                    $"Detected speed hacks on character '{character.Name}', map {character.MapID}...",
                    MessagePacket.MessageTypes.RedText);

                if (character.IsGM == false)
                {
                    character.PermaBan(
                        "Detected speedhack",
                        extraDelay: (int)((2 * 60) + Rand32.Next() % (5 * 60))
                        );
                }
            }

            if (hack.HasFlag(RedisBackend.HackKind.MemoryEdits))
            {
                MessagePacket.SendNoticeGMs(
                    $"Detected memory edits on character '{character.Name}', map {character.MapID}.",
                    MessagePacket.MessageTypes.RedText
                    );

                if (character.IsGM == false)
                {
                    // Add some randomness
                    character.PermaBan(
                        "Detected memory edits",
                        // Between 2 and 12 minutes
                        extraDelay: (int)((2 * 60) + Rand32.Next() % (10 * 60))
                        );
                }
            }
        }
        public static BaseItem CreateCashItem(LockerItem li, CommodityInfo ci)
        {
            li.CashId  = (long)((long)(Rand32.Next()) << 32 | Rand32.Next());
            li.CashId &= 0x00FFFFFFFFFFFFFF; // Get rid of the first byte

            var item = BaseItem.CreateFromItemID(li.ItemId);

            item.Amount     = li.Amount;
            item.CashId     = li.CashId;
            item.Expiration = li.Expiration;

            if (item is PetItem pi)
            {
                pi.Name      = DataProvider.Pets[pi.ItemID].Name;
                pi.Closeness = 0;
                pi.Fullness  = 100;
                pi.Level     = 1;
            }

            return(item);
        }
Esempio n. 20
0
        public MobGenItem(Life life, long?currentTime)
        {
            ID                = life.ID;
            Foothold          = (short)life.Foothold;
            FacesLeft         = life.FacesLeft;
            X                 = life.X;
            _initializedYAxis = false;
            _y                = life.Y;
            _cy               = life.Cy;
            MobCount          = 0;

            if (currentTime == null)
            {
                currentTime = MasterThread.CurrentTime;
            }

            var regenInterval = RegenInterval = life.RespawnTime * 1000;

            if (regenInterval >= 0)
            {
                var T1 = regenInterval / 10;
                var T2 = 6 * regenInterval / 10;

                RegenAfter = currentTime.Value;
                if (T2 != 0)
                {
                    RegenAfter += T1 + Rand32.Next() % T2;
                }
                //else
                //    RegenAfter += Rand32.Next();
            }
            else
            {
                RegenAfter = 0;
            }
        }
Esempio n. 21
0
        public static short GetVariation(short v, ItemVariation enOption)
        {
            if (v <= 0)
            {
                return(0);
            }
            if (enOption == ItemVariation.Gachapon)
            {
                // TODO: Gacha
                return(v);
            }
            // This logic has 2 bonus bits.

            int maxDiff = Math.Min(v / 10 + 1, 5); // Max stat

            // Maximum amount of bits to set
            // Note:
            // Default: 1 << (1 + 2) == 0x08 (3 bits)
            // Max:     1 << (5 + 2) == 0x80 (7 bits)
            uint maxBits  = (uint)(1 << (maxDiff + 2));
            int  randBits = (int)(Rand32.Next() % maxBits);

            // Trace.WriteLine($"{(v11 >> 6) & 1} {(v11 >> 5) & 1} | {(v11 >> 4) & 1} {(v11 >> 3) & 1} {(v11 >> 2) & 1} {(v11 >> 1) & 1} {(v11 >> 0) & 1} ");

            // 0 - 3 range
            int calculatedBoost =
                0
                + ((randBits >> 4) & 1)
                + ((randBits >> 3) & 1)
                + ((randBits >> 2) & 1)
                + ((randBits >> 1) & 1)
                + ((randBits >> 0) & 1)
                // Additional bonus
                - 2
                + ((randBits >> 5) & 1)
                + ((randBits >> 6) & 1);

            // Trace.WriteLine($"Boost w/ bonus: {calculatedBoost}");

            // Make sure we don't give negative boost
            calculatedBoost = Math.Max(0, calculatedBoost);

            //Trace.WriteLine($"Actual boost: {calculatedBoost}");


            // Normal is the only one that can go down. The rest goes up
            if (enOption == ItemVariation.Normal)
            {
                if ((Rand32.Next() & 1) == 0)
                {
                    return((short)(v - calculatedBoost));
                }
                else
                {
                    return((short)(v + calculatedBoost));
                }
            }
            else if (enOption == ItemVariation.Better)
            {
                if ((Rand32.Next() % 10) < 3)
                {
                    return(v);
                }
                else
                {
                    return((short)(v + calculatedBoost));
                }
            }
            else if (enOption == ItemVariation.Great)
            {
                if ((Rand32.Next() % 10) < 1)
                {
                    return(v);
                }
                else
                {
                    return((short)(v + calculatedBoost));
                }
            }
            else
            {
                throw new Exception("Invalid ItemVariation");
            }
        }
Esempio n. 22
0
        public static void HandleUseSkill(Character chr, Packet packet)
        {
            if (chr.PrimaryStats.HP == 0)
            {
                // We don't like zombies
                InventoryPacket.NoChange(chr);
                return;
            }

            var field = chr.Field;

            var SkillID    = packet.ReadInt();
            var SkillLevel = packet.ReadByte();


            if (SkillID == Constants.Priest.Skills.MysticDoor && MasterThread.CurrentTime - chr.tLastDoor < 3000)
            {
                //hack fix for door dc bug
                InventoryPacket.NoChange(chr);
                return;
            }

            if (!chr.Skills.Skills.ContainsKey(SkillID) ||
                SkillLevel < 1 ||
                SkillLevel > chr.Skills.Skills[SkillID])
            {
                Program.MainForm.LogAppend("Player {0} tried to use a skill without having it.", chr.ID);
                ReportManager.FileNewReport("Player {0} tried to use a skill without having it.", chr.ID, 0);
                chr.Player.Socket.Disconnect();
                return;
            }

            var isGMHideSkill = SkillID == Constants.Gm.Skills.Hide;

            // Prevent sending the hide enable/disable packet to others
            if (isGMHideSkill)
            {
                chr.SetHide(chr.GMHideEnabled == false, false);
                if (chr.GMHideEnabled == false)
                {
                    StopSkill(chr, SkillID);
                }
            }
            else if (SkillID != Constants.Cleric.Skills.Heal ||
                     chr.Inventory.GetEquippedItemId((short)Constants.EquipSlots.Slots.Weapon, false) == 0)
            {
                // If you are using Heal, and are not using a wand/weapon, it won't show anything.

                MapPacket.SendPlayerSkillAnim(chr, SkillID, SkillLevel);
            }

            var sld = DataProvider.Skills[SkillID].Levels[SkillLevel];


            if (SkillID == (int)Constants.Spearman.Skills.HyperBody && !chr.PrimaryStats.HasBuff((int)Constants.Spearman.Skills.HyperBody)) // Buff already exists, do not execute bonus again. Allow multiple casts for duration refresh
            {
                var hpmpBonus = (short)((double)chr.PrimaryStats.MaxHP * ((double)sld.XValue / 100.0d));
                chr.PrimaryStats.BuffBonuses.MaxHP = hpmpBonus;
                hpmpBonus = (short)((double)chr.PrimaryStats.MaxMP * ((double)sld.YValue / 100.0d));
                chr.PrimaryStats.BuffBonuses.MaxMP = hpmpBonus;
            }

            short skillDelay = 0;

            IEnumerable <Character> getCharactersForPartyBuff(byte Flags, bool deadPlayersToo = false)
            {
                if (chr.PartyID == 0)
                {
                    yield break;
                }

                if (PartyData.Parties.TryGetValue(chr.PartyID, out var party))
                {
                    for (var i = 5; i >= 0; i--)
                    {
                        if ((Flags >> (5 - i) & 1) == 0)
                        {
                            continue;
                        }

                        var charid = party.Members[i];
                        if (charid == 0)
                        {
                            continue;
                        }

                        var affected = Server.Instance.GetCharacter(charid);

                        if (affected != null && chr.MapID == affected.MapID &&
                            (deadPlayersToo || affected.PrimaryStats.HP > 0))
                        {
                            yield return(affected);
                        }
                    }
                }
            }

            void handlePartyEffects(byte Flags, short Delay, bool deadPlayersToo = false, Action <Character> additionalEffects = null)
            {
                handlePartyEffectsWithPlayers(getCharactersForPartyBuff(Flags, deadPlayersToo), Delay, additionalEffects);
            }

            void handlePartyEffectsWithPlayers(IEnumerable <Character> characters, short Delay, Action <Character> additionalEffects = null)
            {
                foreach (var character in characters)
                {
                    if (character == chr)
                    {
                        continue;
                    }
                    if (!computerSaysYes())
                    {
                        continue;
                    }

                    MapPacket.SendPlayerSkillAnimThirdParty(character, SkillID, SkillLevel, true, true);
                    MapPacket.SendPlayerSkillAnimThirdParty(character, SkillID, SkillLevel, true, false);
                    additionalEffects?.Invoke(character);
                }
            }

            // Runs func() for each mob inside the packet that:
            // - is not a boss (when isBossable is false)
            // - effect chance was a success
            void handleMobStatEffects(bool isBossable, Action <Mob, short> func)
            {
                var mobCount = packet.ReadByte();
                var mobs     = new List <Mob>(mobCount);

                for (var i = 0; i < mobCount; i++)
                {
                    var mobId = packet.ReadInt();
                    var mob   = field.GetMob(mobId);
                    if (mob == null)
                    {
                        continue;
                    }

                    if (chr.AssertForHack(mob.IsBoss && !isBossable, "Tried hitting boss with non-boss skill", false))
                    {
                        continue;
                    }

                    if (computerSaysYes())
                    {
                        mobs.Add(mob);
                    }
                }

                var delay = packet.ReadShort();

                mobs.ForEach(x => func(x, delay));
            }

            IEnumerable <Character> getFullMapPlayersForGMSkill()
            {
                return(field.Characters.Where(victim =>
                {
                    if (victim == chr)
                    {
                        return false;
                    }
                    if (chr.GMHideEnabled && victim.GMHideEnabled == false)
                    {
                        return false;
                    }

                    // Only Admins can buff other regular people
                    if (chr.IsGM && !chr.IsAdmin && !victim.IsGM)
                    {
                        return false;
                    }

                    return true;
                }));
            }

            bool computerSaysYes()
            {
                var chance = sld.Property;

                if (chance == 0)
                {
                    chance = 100;
                }
                return(!(Rand32.Next() % 100 >= chance));
            }

            //TODO refactor copy-pasted "nearest 6 mobs" logic
            switch (SkillID)
            {
            case Constants.Assassin.Skills.Haste:
            case Constants.Bandit.Skills.Haste:
            case Constants.Cleric.Skills.Bless:
            case Constants.Spearman.Skills.IronWill:
            case Constants.Fighter.Skills.Rage:
            case Constants.FPWizard.Skills.Meditation:
            case Constants.ILWizard.Skills.Meditation:
            case Constants.Hermit.Skills.MesoUp:
            {
                var Flags = packet.ReadByte();
                var Delay = packet.ReadShort();

                handlePartyEffects(Flags, Delay, false, victim =>
                    {
                        victim.Buffs.AddBuff(SkillID, SkillLevel);
                    });
                break;
            }

            case Constants.Spearman.Skills.HyperBody:
            {
                var Flags = packet.ReadByte();
                var Delay = packet.ReadShort();

                handlePartyEffects(Flags, Delay, false, victim =>
                    {
                        if (!victim.PrimaryStats.HasBuff((int)Constants.Spearman.Skills.HyperBody))     // Buff already exists, do not execute bonus again. Allow multiple casts for duration refresh
                        {
                            var hpmpBonus = (short)((double)victim.PrimaryStats.MaxHP * ((double)sld.XValue / 100.0d));
                            victim.PrimaryStats.BuffBonuses.MaxHP = hpmpBonus;
                            hpmpBonus = (short)((double)victim.PrimaryStats.MaxMP * ((double)sld.YValue / 100.0d));
                            victim.PrimaryStats.BuffBonuses.MaxMP = hpmpBonus;
                        }
                        victim.Buffs.AddBuff(SkillID, SkillLevel);
                    });


                break;
            }

            case Constants.Cleric.Skills.Heal:
            {
                var Flags   = packet.ReadByte();
                var Delay   = packet.ReadShort();
                var members = getCharactersForPartyBuff(Flags, false);
                var count   = members.Count();

                double healRate = 0;
                if (sld.HPProperty > 0)
                {
                    int chrInt = chr.PrimaryStats.getTotalInt();
                    int chrLuk = chr.PrimaryStats.getTotalLuk();
                    var rate   = (chrInt * 0.8) + Rand32.Next() % (chrInt * 0.2);
                    healRate = (((rate * 1.5 + chrLuk) * (chr.PrimaryStats.getTotalMagicAttack() + chr.PrimaryStats.BuffMagicAttack.N) * 0.01) * (count * 0.3 + 1.0) * sld.HPProperty * 0.01);
                }

                var bigHeal = Math.Min(((long)healRate / (count == 0 ? 1 : count)), short.MaxValue);         //prevent integer overflow caused by high stats. Set count to 1 when not in party
                var heal    = (short)bigHeal;
                chr.ModifyHP((short)Math.Min(heal, (chr.PrimaryStats.GetMaxHP() - chr.PrimaryStats.HP)));

                handlePartyEffectsWithPlayers(members, Delay, victim =>
                    {
                        int oldHP = victim.PrimaryStats.HP;
                        victim.ModifyHP((short)Math.Min(heal, (victim.PrimaryStats.GetMaxHP() - victim.PrimaryStats.HP)));
                        chr.AddEXP(20 * ((victim.PrimaryStats.HP - oldHP) / (8 * victim.Level + 190)), true);
                    });

                break;
            }

            case Constants.Priest.Skills.Dispel:
            {
                var Flags = packet.ReadByte();
                var Delay = packet.ReadShort();

                if (computerSaysYes())
                {
                    chr.Buffs.Dispell();
                }

                handlePartyEffects(Flags, Delay, false, victim =>
                    {
                        victim.Buffs.Dispell();
                    });

                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobStatus.MobStatValue Flag = 0;
                        Flag |= mob.Status.BuffPowerUp.Reset();
                        Flag |= mob.Status.BuffMagicUp.Reset();
                        Flag |= mob.Status.BuffMagicGuardUp.Reset();
                        Flag |= mob.Status.BuffPowerGuardUp.Reset();
                        Flag |= mob.Status.BuffHardSkin.Reset();
                        MobPacket.SendMobStatsTempReset(mob, Flag);
                    });

                break;
            }

            case Constants.Priest.Skills.HolySymbol:
            {
                var Flags = packet.ReadByte();
                var Delay = packet.ReadShort();

                handlePartyEffects(Flags, Delay, false, victim =>
                    {
                        victim.Buffs.AddBuff(SkillID, SkillLevel);
                    });

                break;
            }

            // DOOR
            case Constants.Priest.Skills.MysticDoor:
            {
                var x = packet.ReadShort();
                var y = packet.ReadShort();

                if (chr.DoorMapId != Constants.InvalidMap)
                {
                    DataProvider.Maps[chr.DoorMapId].DoorPool.TryRemoveDoor(chr.ID);
                }

                chr.DoorMapId = chr.MapID;
                field.DoorPool.CreateDoor(chr, x, y, MasterThread.CurrentTime + sld.BuffTime * 1000);
                chr.tLastDoor = MasterThread.CurrentTime;
                break;
            }

            // GM SKILLS
            case Constants.Gm.Skills.Haste:
            case Constants.Gm.Skills.HolySymbol:
            case Constants.Gm.Skills.Bless:
            {
                getFullMapPlayersForGMSkill().ForEach(victim =>
                    {
                        MapPacket.SendPlayerSkillAnimThirdParty(victim, SkillID, SkillLevel, true, true);
                        MapPacket.SendPlayerSkillAnimThirdParty(victim, SkillID, SkillLevel, true, false);
                        victim.Buffs.AddBuff(SkillID, SkillLevel);
                    });
                break;
            }

            case Constants.Gm.Skills.HealPlusDispell:
            {
                getFullMapPlayersForGMSkill().ForEach(victim =>
                    {
                        MapPacket.SendPlayerSkillAnimThirdParty(victim, SkillID, SkillLevel, true, true);
                        MapPacket.SendPlayerSkillAnimThirdParty(victim, SkillID, SkillLevel, true, false);
                        victim.ModifyHP(victim.PrimaryStats.GetMaxMP(false), true);
                        victim.ModifyMP(victim.PrimaryStats.GetMaxMP(false), true);
                        victim.Buffs.Dispell();
                    });
                chr.ModifyHP(chr.PrimaryStats.GetMaxMP(false), true);
                chr.ModifyMP(chr.PrimaryStats.GetMaxMP(false), true);
                chr.Buffs.Dispell();
                break;
            }

            case Constants.Gm.Skills.Resurrection:
            {
                getFullMapPlayersForGMSkill().ForEach(victim =>
                    {
                        if (victim.PrimaryStats.HP <= 0)
                        {
                            MapPacket.SendPlayerSkillAnimThirdParty(victim, SkillID, SkillLevel, true, true);
                            MapPacket.SendPlayerSkillAnimThirdParty(victim, SkillID, SkillLevel, true, false);
                            victim.ModifyHP(victim.PrimaryStats.GetMaxHP(false), true);
                        }
                    });
                break;
            }

            // MOB SKILLS
            case Constants.Page.Skills.Threaten:
            {
                var buffTime = MasterThread.CurrentTime + (sld.BuffTime * 1000);
                handleMobStatEffects(false, (mob, delay) =>
                    {
                        var stat = mob.Status.BuffPhysicalDamage.Set(
                            SkillID,
                            (short)-((mob.Data.PAD * SkillLevel) / 100),
                            buffTime + delay
                            );

                        stat |= mob.Status.BuffPhysicalDefense.Set(
                            SkillID,
                            (short)-((mob.Data.PDD * SkillLevel) / 100),
                            buffTime + delay
                            );

                        MobPacket.SendMobStatsTempSet(mob, delay, stat);
                    });
                break;
            }

            case Constants.FPWizard.Skills.Slow:
            case Constants.ILWizard.Skills.Slow:
            {
                var buffNValue = sld.XValue;
                var buffTime   = MasterThread.CurrentTime + (sld.BuffTime * 1000);

                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobPacket.SendMobStatsTempSet(mob, delay, mob.Status.BuffSpeed.Set(SkillID, buffNValue, buffTime + delay));
                    });
                break;
            }

            case Constants.Gm.Skills.ItemExplosion:
            {
                field.DropPool.Clear(RewardLeaveType.Explode);
                // TODO: Explode people and such
                break;
            }

            case Constants.WhiteKnight.Skills.MagicCrash:
            {
                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobPacket.SendMobStatsTempReset(mob, mob.Status.BuffMagicGuardUp.Reset());
                    });
                break;
            }

            case Constants.DragonKnight.Skills.PowerCrash:
            {
                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobPacket.SendMobStatsTempReset(mob, mob.Status.BuffPowerUp.Reset());
                    });
                break;
            }

            case Constants.Crusader.Skills.ArmorCrash:
            {
                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobPacket.SendMobStatsTempReset(mob, mob.Status.BuffPowerGuardUp.Reset());
                    });
                break;
            }

            case Constants.ILMage.Skills.Seal:
            case Constants.FPMage.Skills.Seal:
            {
                var buffTime = MasterThread.CurrentTime + (sld.BuffTime * 1000);
                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobPacket.SendMobStatsTempSet(mob, delay, mob.Status.BuffSeal.Set(SkillID, 1, buffTime + delay));
                    });

                break;
            }

            case Constants.Hermit.Skills.ShadowWeb:
            {
                var buffTime = MasterThread.CurrentTime + (sld.BuffTime * 1000);

                handleMobStatEffects(false, (mob, delay) =>
                    {
                        var stat = mob.Status.BuffWeb.Set(
                            SkillID,
                            (short)(mob.MaxHP / (50 - SkillLevel)),
                            buffTime + delay
                            );
                        MobPacket.SendMobStatsTempSet(mob, delay, stat);
                    });
                break;
            }

            case Constants.Priest.Skills.Doom:
            {
                var buffTime = MasterThread.CurrentTime + (sld.BuffTime * 1000);

                handleMobStatEffects(false, (mob, delay) =>
                    {
                        MobPacket.SendMobStatsTempSet(mob, delay, mob.Status.BuffDoom.Set(SkillID, 1, buffTime + delay));
                    });
                break;
            }

            // SUMMONS
            case Constants.Priest.Skills.SummonDragon:
            case Constants.Ranger.Skills.SilverHawk:
            case Constants.Sniper.Skills.GoldenEagle:
            {
                var X = packet.ReadShort();
                var Y = packet.ReadShort();

                var    fh   = field.GetFootholdUnderneath(X, Y, out var MaxY);
                ushort fhid = 0;
                fhid = fh?.ID ?? (ushort)chr.Foothold;
                var bird = new Summon(chr, SkillID, SkillLevel, X, Y, true, fhid, MasterThread.CurrentTime + sld.BuffTime * 1000);
                chr.Summons.SetSummon(bird);

                break;
            }

            case Constants.Ranger.Skills.Puppet:
            case Constants.Sniper.Skills.Puppet:
            {
                Program.MainForm.LogDebug(packet.ToString());
                var    X     = packet.ReadShort();
                var    Y     = packet.ReadShort();
                var    fh    = field.GetFootholdUnderneath(X, Y, out var MaxY);
                var    floor = field.FindFloor(new Pos(X, Y));
                ushort fhid  = 0;
                fhid = fh?.ID ?? (ushort)chr.Foothold;
                var puppet = new Puppet(chr, SkillID, SkillLevel, floor.X, floor.Y, false, fhid, MasterThread.CurrentTime + sld.BuffTime * 1000, sld.XValue);
                chr.Summons.SetSummon(puppet);
                break;
            }
            }

            if (packet.Length == packet.Position + 2)
            {
                // Read the delay...
                skillDelay = packet.ReadShort();
            }

            // Handle regular skill stuff
            if (!isGMHideSkill || chr.GMHideEnabled)
            {
                chr.Buffs.AddBuff(SkillID, SkillLevel, skillDelay);
            }

            InventoryPacket.NoChange(chr);
            chr.Skills.DoSkillCost(SkillID, SkillLevel);

            if (sld.Speed > 0)
            {
                MapPacket.SendAvatarModified(chr, MapPacket.AvatarModFlag.Speed);
            }
        }
Esempio n. 23
0
        public static void HandleMagicAttack(Character chr, Packet packet)
        {
            //Program.MainForm.LogAppend("Handling Magic");
            if (!ParseAttackData(chr, packet, out AttackData ad, AttackTypes.Magic))
            {
                return;
            }

            int    TotalDamage;
            double MaxSpellDamage;
            bool   died;
            Mob    mob;

            SendMagicAttack(chr, ad);


            if (ad.SkillID != 0)
            {
                chr.Skills.UseMeleeAttack(ad.SkillID, ad);
            }

            int StolenMP       = 0;
            int MpStealSkillID = chr.Skills.GetMpStealSkillData(2, out int MpStealProp, out int MpStealPercent, out byte MpStealLevel);

            foreach (var ai in ad.Attacks)
            {
                try
                {
                    TotalDamage = 0;
                    mob         = chr.Field.GetMob(ai.MobMapId);

                    if (mob == null)
                    {
                        continue;
                    }

                    foreach (int amount in ai.Damages)
                    {
                        mob.GiveDamage(chr, amount);
                        TotalDamage += amount;
                    }

                    if (MpStealPercent > 0)
                    {
                        StolenMP += mob.OnMobMPSteal(MpStealProp, MpStealPercent / ad.Targets);
                    }

                    if (TotalDamage == 0)
                    {
                        continue;
                    }

                    died = mob.CheckDead(ai.HitPosition, ai.HitDelay, chr.PrimaryStats.BuffMesoUP.N);

                    if (!died)
                    {
                        var  sld      = DataProvider.Skills[ad.SkillID].Levels[ad.SkillLevel];
                        long buffTime = sld.BuffTime * 1000;

                        //TODO refactor element code when we get the proper element loading with calcdamage branch
                        if ((sld.ElementFlags == SkillElement.Ice || ad.SkillID == Constants.ILMage.Skills.ElementComposition) && !mob.IsBoss)
                        {
                            var stat = mob.Status.BuffFreeze.Set(ad.SkillID, 1, MasterThread.CurrentTime + buffTime);
                            MobPacket.SendMobStatsTempSet(mob, ai.HitDelay, stat);
                        }

                        if (ad.SkillID == Constants.FPMage.Skills.ElementComposition && !mob.IsBoss)
                        {
                            if (Rand32.NextBetween(0, 100) < sld.Property)
                            {
                                mob.DoPoison(chr.ID, chr.Skills.GetSkillLevel(ad.SkillID), buffTime, ad.SkillID, sld.MagicAttack, ai.HitDelay);
                            }
                        }

                        if (ad.SkillID == Constants.FPWizard.Skills.PoisonBreath)
                        {
                            if (Rand32.NextBetween(0, 100) < sld.Property)
                            {
                                mob.DoPoison(chr.ID, chr.Skills.GetSkillLevel(ad.SkillID), buffTime, ad.SkillID, sld.MagicAttack, ai.HitDelay);
                            }
                        }

                        if (StolenMP > 0)
                        {
                            chr.ModifyMP((short)StolenMP);
                            MapPacket.SendPlayerSkillAnimSelf(chr, MpStealSkillID, MpStealLevel);
                            MapPacket.SendPlayerSkillAnim(chr, MpStealSkillID, MpStealLevel);
                        }
                    }

                    switch (ad.SkillID)
                    {
                    case Constants.Magician.Skills.MagicClaw:     // If the Spell is Magic Claw (since it registers two hits)
                        MaxSpellDamage = DamageFormula.MaximumSpellDamage(chr, mob, ad.SkillID) * 2;
                        break;

                    case Constants.Cleric.Skills.Heal:     // If the Spell is Heal (since it has a special snowflake calculation for it)
                        if (mob.Data.Undead == false)
                        {
                            chr.PermaBan("Heal damaging regular mobs exploit");
                            return;
                        }
                        MaxSpellDamage = DamageFormula.MaximumHealDamage(chr, mob, ad.Targets);
                        break;

                    default:
                        MaxSpellDamage = DamageFormula.MaximumSpellDamage(chr, mob, ad.SkillID);
                        break;
                    }

                    if (TotalDamage > MaxSpellDamage)
                    {
                        if (ReportDamagehack(chr, ad, TotalDamage, (int)MaxSpellDamage))
                        {
                            return;
                        }
                    }
                }

                catch (Exception ex)
                {
                    Program.MainForm.LogAppend(ex.ToString());
                }
            }
        }
Esempio n. 24
0
        public static void HandleMeleeAttack(Character chr, Packet packet)
        {
            //Program.MainForm.LogAppend("Handling Melee");
            if (!ParseAttackData(chr, packet, out AttackData ad, AttackTypes.Melee))
            {
                return;
            }

            SendMeleeAttack(chr, ad);
            Mob    mob;
            bool   died;
            int    TotalDamage = 0;
            double MaxPossibleDamage;

            if (ad.SkillID != 0)
            {
                chr.Skills.UseMeleeAttack(ad.SkillID, ad);
            }

            bool pickPocketActivated = chr.PrimaryStats.HasBuff(Constants.ChiefBandit.Skills.Pickpocket);
            var  pickPocketSLD       = chr.Skills.GetSkillLevelData(Constants.ChiefBandit.Skills.Pickpocket, out byte pickPocketSkillLevel);
            bool pickOk = !ad.IsMesoExplosion && pickPocketActivated && pickPocketSkillLevel > 0 && pickPocketSLD != null;

            int StolenMP       = 0;
            int MpStealSkillID = chr.Skills.GetMpStealSkillData(2, out int MpStealProp, out int MpStealPercent, out byte MpStealLevel);

            List <Drop> dropsToPop = null;
            short       delayForMesoExplosionKill = 0;

            if (ad.SkillID == Constants.ChiefBandit.Skills.MesoExplosion)
            {
                byte items = packet.ReadByte();
                dropsToPop = new List <Drop>(items);
                byte i;
                for (i = 0; i < items; i++)
                {
                    int objectID = packet.ReadInt();
                    packet.Skip(1);

                    if (chr.Field.DropPool.Drops.TryGetValue(objectID, out var drop) &&
                        drop.Reward.Mesos)
                    {
                        dropsToPop.Add(drop);
                    }
                }

                delayForMesoExplosionKill = packet.ReadShort();
            }


            var  sld            = ad.SkillID == 0 ? null : DataProvider.Skills[ad.SkillID].Levels[ad.SkillLevel];
            long buffTime       = sld?.BuffTime * 1000 ?? 0;
            long buffExpireTime = MasterThread.CurrentTime + buffTime;

            bool IsSuccessRoll() => sld != null && (Rand32.Next() % 100) < sld.Property;


            foreach (var ai in ad.Attacks)
            {
                try
                {
                    TotalDamage = 0;
                    mob         = chr.Field.GetMob(ai.MobMapId);

                    if (mob == null)
                    {
                        continue;
                    }

                    bool boss = mob.Data.Boss;

                    if (MpStealPercent > 0)
                    {
                        StolenMP += mob.OnMobMPSteal(MpStealProp, MpStealPercent / ad.Targets);
                    }
                    if (pickOk)
                    {
                        mob.GiveMoney(chr, ai, ad.Hits);
                    }

                    foreach (var amount in ai.Damages)
                    {
                        mob.GiveDamage(chr, amount);
                        TotalDamage += amount;
                    }

                    if (TotalDamage == 0)
                    {
                        continue;
                    }

                    var maxDamage = 5 + (chr.Level * 6);
                    if (ad.SkillID == 0 && chr.Level < 10 && TotalDamage > maxDamage)
                    {
                        chr.PermaBan("Melee damage hack (low level), hit " + TotalDamage + " (max: " + maxDamage + ")");
                        return;
                    }

                    died = mob.CheckDead(ai.HitPosition, ad.IsMesoExplosion ? delayForMesoExplosionKill : ai.HitDelay, chr.PrimaryStats.BuffMesoUP.N);

                    //TODO sometimes when attacking without using a skill this gets triggered and throws a exception?
                    if (died || ad.SkillID <= 0)
                    {
                        continue;
                    }

                    if (ad.SkillID != 0)
                    {
                        MobStatus.MobStatValue addedStats = 0;

                        switch (ad.SkillID)
                        {
                        case Constants.DragonKnight.Skills.Sacrifice:
                        {
                            double percentSacrificed = sld.XValue / 100.0;
                            short  amountSacrificed  = (short)(TotalDamage * percentSacrificed);
                            chr.DamageHP(amountSacrificed);
                            break;
                        }

                        case Constants.Bandit.Skills.Steal:
                            if (!boss && IsSuccessRoll())
                            {
                                mob.GiveReward(chr.ID, 0, DropType.Normal, ai.HitPosition, ai.HitDelay, 0, true);
                            }
                            break;

                        // Debuffs

                        case Constants.Rogue.Skills.Disorder:

                            addedStats  = mob.Status.BuffPhysicalDamage.Set(ad.SkillID, (short)sld.XValue, buffExpireTime);
                            addedStats |= mob.Status.BuffPhysicalDefense.Set(ad.SkillID, (short)sld.XValue, buffExpireTime);
                            break;

                        case Constants.WhiteKnight.Skills.ChargeBlow:     // Not sure if this should add the stun
                        case Constants.Crusader.Skills.AxeComa:
                        case Constants.Crusader.Skills.SwordComa:
                        case Constants.Crusader.Skills.Shout:
                            if (!boss && IsSuccessRoll())
                            {
                                addedStats = mob.Status.BuffStun.Set(ad.SkillID, (short)-sld.BuffTime, buffExpireTime);
                            }
                            //is charge blow supposed to end the elemental charge buff?
                            break;

                        case Constants.Crusader.Skills.AxePanic:
                        case Constants.Crusader.Skills.SwordPanic:
                            if (!boss && IsSuccessRoll())
                            {
                                addedStats = mob.Status.BuffDarkness.Set(ad.SkillID, (short)1, buffExpireTime);
                                //darkness animation doesnt show in this ver?
                            }
                            break;
                        }

                        if (addedStats != 0)
                        {
                            MobPacket.SendMobStatsTempSet(mob, ai.HitDelay, addedStats);
                        }
                    }


                    if (StolenMP > 0)
                    {
                        chr.ModifyMP((short)StolenMP);
                        MapPacket.SendPlayerSkillAnimSelf(chr, MpStealSkillID, MpStealLevel);
                        MapPacket.SendPlayerSkillAnim(chr, MpStealSkillID, MpStealLevel);
                    }

                    if (ad.SkillID != 0)
                    {
                        MaxPossibleDamage = DamageFormula.MaximumMeleeDamage(chr, mob, ad.Targets, ad.SkillID);
                    }
                    else
                    {
                        MaxPossibleDamage = DamageFormula.MaximumMeleeDamage(chr, mob, ad.Targets);
                    }

                    if (TotalDamage > MaxPossibleDamage)
                    {
                        if (ReportDamagehack(chr, ad, TotalDamage, (int)MaxPossibleDamage))
                        {
                            return;
                        }
                    }
                }

                catch (Exception ex)
                {
                    Program.MainForm.LogAppend(ex.ToString());
                }
            }

            if (chr.PrimaryStats.BuffComboAttack.IsSet() && TotalDamage > 0)
            {
                if (ad.SkillID == Constants.Crusader.Skills.AxeComa ||
                    ad.SkillID == Constants.Crusader.Skills.SwordComa ||
                    ad.SkillID == Constants.Crusader.Skills.AxePanic ||
                    ad.SkillID == Constants.Crusader.Skills.SwordPanic)
                {
                    chr.PrimaryStats.BuffComboAttack.N = 1;
                    BuffPacket.SetTempStats(chr, BuffValueTypes.ComboAttack);
                    MapPacket.SendPlayerBuffed(chr, BuffValueTypes.ComboAttack);
                }
                else if (ad.SkillID != Constants.Crusader.Skills.Shout)
                {
                    if (chr.PrimaryStats.BuffComboAttack.N <= chr.PrimaryStats.BuffComboAttack.MaxOrbs)
                    {
                        chr.PrimaryStats.BuffComboAttack.N++;
                        BuffPacket.SetTempStats(chr, BuffValueTypes.ComboAttack);
                        MapPacket.SendPlayerBuffed(chr, BuffValueTypes.ComboAttack);
                    }
                }
            }


            switch (ad.SkillID)
            {
            case 0:                                                                                           // Normal wep
            {
                if (chr.Inventory.GetEquippedItemId((short)Constants.EquipSlots.Slots.Helm, true) == 1002258) // Blue Diamondy Bandana
                {
                    var mobs = chr.Field.GetMobsInRange(chr.Position, new Pos(-10000, -10000), new Pos(10000, 10000));

                    foreach (var m in mobs)
                    {
                        MobPacket.SendMobDamageOrHeal(chr.Field, m, 1337, false, false);

                        if (m.GiveDamage(chr, 1337))
                        {
                            m.CheckDead();
                        }
                    }
                }
                break;
            }

            case Constants.ChiefBandit.Skills.MesoExplosion:
            {
                byte i = 0;
                foreach (var drop in dropsToPop)
                {
                    var delay = (short)Math.Min(1000, delayForMesoExplosionKill + (100 * (i % 5)));
                    chr.Field.DropPool.RemoveDrop(drop, RewardLeaveType.Explode, delay);
                    i++;
                }
                break;
            }

            case Constants.WhiteKnight.Skills.ChargeBlow:
                if (IsSuccessRoll())
                {
                    // RIP. It cancels your charge
                    var removedBuffs = chr.PrimaryStats.RemoveByReference(chr.PrimaryStats.BuffCharges.R);
                    BuffPacket.SetTempStats(chr, removedBuffs);
                    MapPacket.SendPlayerBuffed(chr, removedBuffs);
                }
                break;

            case Constants.WhiteKnight.Skills.BwFireCharge:
            case Constants.WhiteKnight.Skills.BwIceCharge:
            case Constants.WhiteKnight.Skills.BwLitCharge:
            case Constants.WhiteKnight.Skills.SwordFireCharge:
            case Constants.WhiteKnight.Skills.SwordIceCharge:
            case Constants.WhiteKnight.Skills.SwordLitCharge:
            {
                var buff = chr.PrimaryStats.BuffCharges.Set(
                    ad.SkillID,
                    sld.XValue,
                    BuffStat.GetTimeForBuff(1000 * sld.BuffTime)
                    );
                BuffPacket.SetTempStats(chr, buff);
                MapPacket.SendPlayerBuffed(chr, buff);
                break;
            }

            case Constants.DragonKnight.Skills.DragonRoar:
            {
                // Apply stun
                var buff = chr.PrimaryStats.BuffStun.Set(
                    ad.SkillID,
                    1,
                    BuffStat.GetTimeForBuff(1000 * sld.YValue)
                    );
                BuffPacket.SetTempStats(chr, buff);
                MapPacket.SendPlayerBuffed(chr, buff);
                break;
            }
            }
        }
Esempio n. 25
0
        public MaplePacket Read(DateTime pTransmitted, bool bMaple2)
        {
            if (mCursor < _expectedDataSize)
            {
                return(null);
            }
            if (bMaple2)
            {
                mRawSeq = BitConverter.ToUInt16(mBuffer, 0);
                if (mOutbound && DecodeSeqBase(IV) != Build || !mOutbound && DecodeSeqBase(Rand32.CrtRand(IV)) != Build)
                {
                    throw new Exception("Failed to confirm packet header");
                }
            }
            else
            {
                if (!mAES.ConfirmHeader(mBuffer, 0))
                {
                    throw new Exception("Failed to confirm packet header");
                }
            }

            int headerLength = bMaple2 ? 6 : MapleAES.GetHeaderLength(mBuffer, mCursor, _usesOldHeader);

            _expectedDataSize = headerLength;
            if (mCursor < headerLength)
            {
                return(null);
            }

            int packetSize = MapleAES.GetPacketLength(mBuffer, mCursor, _usesOldHeader, bMaple2);

            _expectedDataSize = packetSize + headerLength;
            if (mCursor < (packetSize + headerLength))
            {
                return(null);
            }

            byte[] packetBuffer = new byte[packetSize];
            Buffer.BlockCopy(mBuffer, headerLength, packetBuffer, 0, packetSize);

            uint preDecodeIV;

            if (bMaple2)
            {
                preDecodeIV = IV;

                mCrypt.Decrypt(packetBuffer, packetSize, BlockIV, IV);
                ShiftIV();
            }
            else
            {
                preDecodeIV = BitConverter.ToUInt32(mAES.mIV, 0);
                Decrypt(packetBuffer, _transformMethod);
            }

            var postDecodeIV = bMaple2 ? IV : BitConverter.ToUInt32(mAES.mIV, 0);

            mCursor -= _expectedDataSize;
            if (mCursor > 0)
            {
                Buffer.BlockCopy(mBuffer, _expectedDataSize, mBuffer, 0, mCursor);
            }
            ushort opcode;

            if (_usesByteHeader)
            {
                opcode = (ushort)(packetBuffer[0]);
                Buffer.BlockCopy(packetBuffer, 1, packetBuffer, 0, packetSize - 1);
                Array.Resize(ref packetBuffer, packetSize - 1);
            }
            else
            {
                opcode = (ushort)(packetBuffer[0] | (packetBuffer[1] << 8));
                Buffer.BlockCopy(packetBuffer, 2, packetBuffer, 0, packetSize - 2);
                Array.Resize(ref packetBuffer, packetSize - 2);
            }

            _expectedDataSize = bMaple2 ? 6 : 4;

            Definition definition = Config.Instance.GetDefinition(Build, Locale, mOutbound, opcode);

            return(new MaplePacket(pTransmitted, mOutbound, Build, Locale, opcode, definition == null ? "" : definition.Name, packetBuffer, preDecodeIV, postDecodeIV));
        }
Esempio n. 26
0
 private void AdvanceIV()
 {
     Iv = Rand32.CrtRand(Iv);
 }
Esempio n. 27
0
 public ItemVariation(Rand32 rand, ItemVariationType type)
 {
     this.rand = rand;
     this.type = type;
 }
Esempio n. 28
0
        public static List <Reward> GetRewards(Character Owner, Map Field, int ID, char Type, bool PremiumMap, double Showdown)
        {
            double HourDropRateIncrease = 1.0;
            var    curDate = MasterThread.CurrentDate;

            if (curDate.Hour >= 13 && curDate.Hour < 19)
            {
                HourDropRateIncrease = ms_fIncDropRate_WSE;
            }

            double dRegionalIncRate       = Field.m_dIncRate_Drop;
            double dwOwnerDropRate        = Owner.m_dIncDropRate;
            double dwOwnerDropRate_Ticket = Owner.m_dIncDropRate_Ticket;

            var Result = new List <Reward>();

            if (!DataProvider.Drops.TryGetValue($"{Type}{ID}", out var Rewards))
            {
                return(Result);
            }

            foreach (var Drop in Rewards)
            {
                if ((Drop.Premium && !PremiumMap))
                {
                    continue;
                }

                var itemDropRate = 1.0;
                if (Drop.Mesos == 0)
                {
                    itemDropRate = dwOwnerDropRate_Ticket;
                }

                var maxDropChance = (long)(1000000000.0
                                           / (ms_fIncDropRate * HourDropRateIncrease)
                                           / dRegionalIncRate
                                           / Showdown
                                           / dwOwnerDropRate
                                           / itemDropRate
                                           / MonsterCarnivalRewardRate);

                var luckyNumber = Rand32.Next() % maxDropChance;

                if (luckyNumber >= Drop.Chance)
                {
                    continue;
                }

                // Don't care about items that are 'expired'
                if (Drop.Mesos != 0 && Drop.DateExpire <= curDate)
                {
                    continue;
                }

                var Reward = new Reward()
                {
                    Mesos = Drop.Mesos != 0,
                    Drop  = Drop.Mesos != 0 ? Drop.Mesos : Drop.ItemID,
                    Data  = Drop.Mesos != 0 ? null : BaseItem.CreateFromItemID(Drop.ItemID, GetItemAmount(Drop.ItemID, Drop.Min, Drop.Max))
                };

                if (!Reward.Mesos)
                {
                    Reward.Data.GiveStats(ItemVariation.Normal);
                    if (Drop.Period > 0)
                    {
                        Reward.Data.Expiration = Tools.GetFileTimeWithAddition(new TimeSpan(Drop.Period, 0, 0, 0));
                    }
                    else if (Drop.DateExpire != DateTime.MaxValue)
                    {
                        Reward.Data.Expiration = Drop.DateExpire.ToFileTimeUtc();
                    }
                }

                if (!Drop.Premium || PremiumMap)
                {
                    if (Reward.Mesos)
                    {
                        int minDrop      = 4 * Reward.Drop / 5;
                        int maxDrop      = 2 * Reward.Drop / 5 + 1;
                        int DroppedMesos = (int)(minDrop + Rand32.Next() % maxDrop);

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

                        DroppedMesos = (int)(DroppedMesos * dwOwnerDropRate_Ticket);
                        Reward.Drop  = DroppedMesos;
                    }
                }

                Result.Add(Reward);
            }

            return(Result);
        }
Esempio n. 29
0
        public LoadFailReasons Load(string IP)
        {
            var imitateId  = RedisBackend.Instance.GetImitateID(ID);
            var imitating  = imitateId.HasValue;
            var originalId = ID;

            if (imitating)
            {
                ID = imitateId.Value;
                _characterLog.Debug($"Loading character {ID} from IP {IP}... (IMITATION from ID {originalId})");
            }
            else
            {
                _characterLog.Debug($"Loading character {ID} from IP {IP}...");
            }

            // Initial load

            using (var data = (MySqlDataReader)Server.Instance.CharacterDatabase.RunQuery(
                       "SELECT " +
                       "characters.*, users.admin, users.superadmin, users.donator, users.beta, users.last_ip, users.online " +
                       "FROM characters " +
                       "LEFT JOIN users ON users.id = characters.userid " +
                       "WHERE characters.id = @id",
                       "@id", originalId))
            {
                if (!data.Read())
                {
                    _characterLog.Debug("Loading failed: unknown character.");
                    return(LoadFailReasons.UnknownCharacter);
                }

                if (data.GetString("last_ip") != IP && !imitating)
                {
#if DEBUG
                    Program.MainForm.LogAppend("Allowed player " + this.ID +
                                               " to log in from different IP because source is running in debug mode!");
#else
                    _characterLog.Debug("Loading failed: not from previous IP.");
                    return(LoadFailReasons.NotFromPreviousIP);
#endif
                }
                UserID     = data.GetInt32("userid");
                Name       = data.GetString("name");
                GMLevel    = data.GetByte("admin");
                Donator    = data.GetBoolean("donator");
                BetaPlayer = data.GetBoolean("beta");


                if (imitating)
                {
                    ImitatorName = Name;
                }
                else
                {
                    ImitatorName = null;
                }
            }

            var tmpUserId = UserID;

            using (var data = (MySqlDataReader)Server.Instance.CharacterDatabase.RunQuery(
                       "SELECT " +
                       "characters.*, users.last_ip, users.online, users.quiet_ban_expire, users.quiet_ban_reason " +
                       "FROM characters " +
                       "LEFT JOIN users ON users.id = characters.userid " +
                       "WHERE characters.id = @id",
                       "@id", ID))
            {
                if (!data.Read())
                {
                    _characterLog.Debug("Loading failed: unknown character.");
                    if (imitating)
                    {
                        // Reset!
                        RedisBackend.Instance.SetImitateID(originalId, 0);
                    }

                    return(LoadFailReasons.UnknownCharacter);
                }

                UserID = data.GetInt32("userid"); // For cashitem loading
                Name   = data.GetString("name");

                Gender           = data.GetByte("gender");
                Skin             = data.GetByte("skin");
                Hair             = data.GetInt32("hair");
                Face             = data.GetInt32("eyes");
                PetCashId        = data.GetInt64("pet_cash_id");
                MutedUntil       = data.GetDateTime("quiet_ban_expire");
                MuteReason       = data.GetByte("quiet_ban_reason");
                LastSavepoint    = data.GetDateTime("last_savepoint");
                LastPlayTimeSave = MasterThread.CurrentTime;

                var _mapId = data.GetInt32("map");

                Map field;
                if (!DataProvider.Maps.TryGetValue(_mapId, out field))
                {
                    Program.MainForm.LogAppend(
                        "The map of {0} is not valid (nonexistant)! Map was {1}. Returning to 0", ID, _mapId);
                    field       = DataProvider.Maps[0];
                    MapPosition = 0;
                }
                Field = field;

                // Push back player when there's a forced return value
                if (field.ForcedReturn != Constants.InvalidMap)
                {
                    _mapId = field.ForcedReturn;
                    if (!DataProvider.Maps.TryGetValue(_mapId, out field))
                    {
                        Program.MainForm.LogAppend(
                            "The map of {0} is not valid (nonexistant)! Map was {1}. Returning to 0", ID, _mapId);
                        // Note: using Field here
                        Field = DataProvider.Maps[0];
                    }
                    else
                    {
                        Field = DataProvider.Maps[_mapId];
                    }
                    MapPosition = 0;
                }
                else
                {
                    MapPosition = (byte)data.GetInt16("pos");
                }

                // Select portal to spawn on.
                {
                    Portal portal = Field.SpawnPoints.Find(x => x.ID == MapPosition);
                    if (portal == null)
                    {
                        portal = Field.GetRandomStartPoint();
                    }
                    Position = new Pos(portal.X, portal.Y);
                }
                Stance   = 0;
                Foothold = 0;

                CalcDamageRandomizer = new Rand32();
                RndActionRandomizer  = new Rand32();


                PrimaryStats = new CharacterPrimaryStats(this)
                {
                    Level             = data.GetByte("level"),
                    Job               = data.GetInt16("job"),
                    Str               = data.GetInt16("str"),
                    Dex               = data.GetInt16("dex"),
                    Int               = data.GetInt16("int"),
                    Luk               = data.GetInt16("luk"),
                    HP                = data.GetInt16("chp"),
                    MaxHP             = data.GetInt16("mhp"),
                    MP                = data.GetInt16("cmp"),
                    MaxMP             = data.GetInt16("mmp"),
                    AP                = data.GetInt16("ap"),
                    SP                = data.GetInt16("sp"),
                    EXP               = data.GetInt32("exp"),
                    Fame              = data.GetInt16("fame"),
                    BuddyListCapacity = data.GetInt32("buddylist_size")
                };

                // Make sure we don't update too many times
                lastSaveStep = CalculateSaveStep();
            }

            Inventory = new CharacterInventory(this);
            Inventory.LoadInventory();

            UserID = tmpUserId;

            Ring.LoadRings(this);

            Skills = new CharacterSkills(this);
            Skills.LoadSkills();

            Storage = new CharacterStorage(this);
            Storage.Load();

            Buffs = new CharacterBuffs(this);

            Summons = new CharacterSummons(this);

            Quests = new CharacterQuests(this);
            Quests.LoadQuests();

            Variables = new CharacterVariables(this);
            Variables.Load();

            GameStats = new CharacterGameStats(this);
            GameStats.Load();

            Wishlist = new List <int>();
            using (var data = (MySqlDataReader)Server.Instance.CharacterDatabase.RunQuery("SELECT serial FROM character_wishlist WHERE charid = " + ID))
            {
                while (data.Read())
                {
                    Wishlist.Add(data.GetInt32(0));
                }
            }

            // Loading done, switch back ID
            ID = originalId;

            InitDamageLog();

            SetIncExpRate();

            var muteTimeSpan = RedisBackend.Instance.GetCharacterMuteTime(ID);
            if (muteTimeSpan.HasValue)
            {
                HacklogMuted = MasterThread.CurrentDate.Add(muteTimeSpan.Value);
            }
            else
            {
                HacklogMuted = DateTime.MinValue;
            }

            Undercover = RedisBackend.Instance.IsUndercover(ID);

            RedisBackend.Instance.SetPlayerOnline(
                UserID,
                Server.Instance.GetOnlineId()
                );

            _characterLog.Debug("Loaded!");
            return(LoadFailReasons.None);
        }
Esempio n. 30
0
        public static void HandleMobControl(Character victim, Packet packet)
        {
            int mobid = packet.ReadInt();
            var mob   = victim.Field.GetMob(mobid);


            short moveID = packet.ReadShort();
            var   x      = packet.ReadByte();
            bool  bNextAttackPossible = (x & 0x0F) != 0;
            sbyte action = packet.ReadSByte();

            int actualAction = action < 0 ? -1 : (byte)(action >> 1);

            uint dwData = packet.ReadUInt();


            var movePath = new MovePath();

            movePath.DecodeFromPacket(packet, MovePath.MovementSource.Mob);

            if (mob == null)
            {
                return;
            }

            if (mob.Controller != victim &&
                (!bNextAttackPossible || mob.NextAttackPossible || !mob.Field.FindNewController(mob, victim, true)))
            {
                SendMobRequestEndControl(victim, mobid);
                return;
            }


            victim.TryTraceMovement(movePath);

            if (mob.Controller != null && victim.ID != mob.Controller.ID)
            {
                Program.MainForm.LogAppend("returning mobpacket"); return;
            }

            var  lastMoveMillis         = MasterThread.CurrentTime - mob.LastMove;
            bool justStartedControlling = (MasterThread.CurrentTime - mob.LastControllerAssignTime) < 2000;

            PacketHelper.ValidateMovePath(mob, movePath);

            //Program.MainForm.LogDebug("[" + DateTime.Now.ToString() + "]" + "Received movement packet from " + victim.Name + ". Original pos: x:" + movePath.OriginalPosition.X + " y: " + movePath.OriginalPosition.Y + "\r\nNew position: x: " + movePath.NewPosition.X + " y: " + movePath.NewPosition.Y);


            // Skill related?
            if (actualAction >= 21 && actualAction <= 25)
            {
                short attackDelay = (short)(dwData >> 16);
                byte  level       = (byte)(dwData >> 8);
                byte  skillId     = (byte)(dwData);

                if (mob.DoSkill(skillId, level, attackDelay) == false)
                {
                    // invalid
                    return;
                }
            }
            else if (actualAction > 12 && actualAction < 20)
            {
                // regular attack?
                var attackIdx = (byte)(actualAction - 12);
                if (mob.Data.Attacks == null ||
                    !mob.Data.Attacks.ContainsKey(attackIdx))
                {
                    Program.MainForm.LogAppend(
                        "Unknown attack for mob: " + mob.MobID + "; " + attackIdx + "; " + packet);
                }
                else
                {
                    var attack = mob.Data.Attacks[attackIdx];
                    mob.MP         = Math.Max(0, mob.MP - attack.MPConsume);
                    mob.LastAttack = MasterThread.CurrentTime;
                }
            }


            if ((MasterThread.CurrentTime - mob.LastAttack) > 5000)
            {
                // Reassign controller!
                MobDamageInfo lastHitCharacter;
                if (mob.IsControlled)
                {
                    var currentControllerID = mob.Controller.ID;
                    lastHitCharacter = mob.DamageLog.Log.FirstOrDefault(mobDamageInfo =>
                    {
                        if (mobDamageInfo.CharacterID == currentControllerID)
                        {
                            return(false);
                        }
                        if (mob.Field.GetPlayer(mobDamageInfo.CharacterID) == null)
                        {
                            return(false);
                        }

                        return((MasterThread.CurrentDate - mobDamageInfo.Time).TotalSeconds <= 5.0);
                    });
                }
                else
                {
                    lastHitCharacter = mob.DamageLog.Log.FirstOrDefault(mobDamageInfo =>
                    {
                        if (mob.Field.GetPlayer(mobDamageInfo.CharacterID) == null)
                        {
                            return(false);
                        }

                        return((MasterThread.CurrentDate - mobDamageInfo.Time).TotalSeconds <= 5.0);
                    });
                }

                if (lastHitCharacter != null)
                {
                    Program.MainForm.LogDebug("Setting new controller: " + Server.Instance.GetCharacter(lastHitCharacter.CharacterID));
                    mob.SetController(mob.Field.GetPlayer(lastHitCharacter.CharacterID), true, false);
                    return;
                }
            }


            mob.NextAttackPossible = bNextAttackPossible;

            // Prepare next skill
            byte forceControllerSkillLevel = 0;

            if (mob.NextAttackPossible == false ||
                mob.SkillCommand != 0 ||
                (mob.HasAnyStatus && mob.Status.BuffSealSkill.IsSet()) ||
                mob.Data.Skills == null ||
                mob.Data.Skills.Count == 0 ||
                (MasterThread.CurrentTime - mob.LastSkillUse) < 3000)
            {
                // No skill
            }
            else
            {
                var availableSkills = mob.Data.Skills.Where(skill =>
                {
                    Dictionary <byte, MobSkillLevelData> msdLevels;
                    if (!DataProvider.MobSkills.TryGetValue(skill.SkillID, out msdLevels) ||
                        !msdLevels.ContainsKey(skill.Level))
                    {
                        return(false);
                    }

                    // Handle HP restriction
                    var msd = msdLevels[skill.Level];
                    if (msd.HPLimit > 0 && (mob.HP / (double)mob.MaxHP * 100.0) > msd.HPLimit)
                    {
                        return(false);
                    }

                    // Skip if we already used a skill and it was not yet cooled down
                    if (mob.SkillsInUse.TryGetValue(msd.SkillID, out long lastUse) &&
                        (lastUse + (msd.Cooldown * 1000)) > MasterThread.CurrentTime)
                    {
                        return(false);
                    }

                    // Do not reach the summon limit
                    if (skill.SkillID == (byte)Constants.MobSkills.Skills.Summon &&
                        mob.SummonCount + msd.Summons.Count > msd.SummonLimit)
                    {
                        return(false);
                    }


                    // Can we boost stats?
                    if (mob.HasAnyStatus)
                    {
                        short currentX = 0;
                        int maxX       = Math.Abs(100 - msd.X);

                        switch ((Constants.MobSkills.Skills)skill.SkillID)
                        {
                        case Constants.MobSkills.Skills.WeaponAttackUp:
                        case Constants.MobSkills.Skills.WeaponAttackUpAoe:
                            currentX = mob.Status.BuffPowerUp.N;
                            break;

                        case Constants.MobSkills.Skills.MagicAttackUp:
                        case Constants.MobSkills.Skills.MagicAttackUpAoe:
                            currentX = mob.Status.BuffMagicUp.N;
                            break;

                        case Constants.MobSkills.Skills.WeaponDefenseUp:
                        case Constants.MobSkills.Skills.WeaponDefenseUpAoe:
                            currentX = mob.Status.BuffPowerGuardUp.N;
                            break;

                        case Constants.MobSkills.Skills.MagicDefenseUp:
                        case Constants.MobSkills.Skills.MagicDefenseUpAoe:
                            currentX = mob.Status.BuffMagicGuardUp.N;
                            break;
                        }

                        if (currentX == 0)
                        {
                            return(true);
                        }

                        if (Math.Abs(100 - currentX) >= maxX)
                        {
                            return(false);
                        }
                    }
                    return(true);
                }).ToArray();

                if (availableSkills.Length > 0)
                {
                    var randomSkill = availableSkills[Rand32.Next() % availableSkills.Length];
                    mob.SkillCommand          = randomSkill.SkillID;
                    forceControllerSkillLevel = randomSkill.Level;
                }
            }

            byte forceControllerSkillID = mob.SkillCommand;

            // Fix crash (zero level skill)
            if (forceControllerSkillLevel == 0)
            {
                forceControllerSkillID = 0;
            }

            SendMobControlResponse(victim, mobid, moveID, bNextAttackPossible, (short)mob.MP, forceControllerSkillID, forceControllerSkillLevel);

            SendMobControlMove(victim, mob, bNextAttackPossible, (byte)action, dwData, movePath);

            mob.CheckVacHack(lastMoveMillis, movePath.OriginalPosition, movePath.NewPosition, victim);

            // Good luck on getting less.
            if (lastMoveMillis < 500 && !justStartedControlling && !victim.IsAFK)
            {
                if (victim.AssertForHack(mob.HackReportCounter++ > 5,
                                         $"Movement speed too high! {lastMoveMillis}ms since last movement."))
                {
                    mob.HackReportCounter = 0;
                }
            }
        }