Example #1
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());
                    }
                }
            }
        }
Example #2
0
        public void AddEXP(uint value, bool IsLastHit = false, bool Quest = false)
        {
            if (value == 0 || PrimaryStats.Level >= 200 || PrimaryStats.HP <= 0)
            {
                return;
            }

            var amount = (int)(value > Int32.MaxValue ? Int32.MaxValue : value);
            var amnt   = (uint)(PrimaryStats.EXP + amount);

            CharacterStatsPacket.SendGainEXP(this, amount, IsLastHit, Quest);
            var level = PrimaryStats.Level;

            var save        = false;
            var expRequired = Constants.GetLevelEXP(PrimaryStats.Level);

            if (amnt >= expRequired)
            {
                short apgain = 0;
                short spgain = 0;
                short mpgain = 0;
                short hpgain = 0;
                var   job    = (short)(PrimaryStats.Job / 100);

                var intt = PrimaryStats.GetIntAddition(true);

                amnt -= (uint)expRequired;

                level++;

                // Update EXP required...
                expRequired = Constants.GetLevelEXP(level);

                apgain += Constants.ApPerLevel;
                hpgain += RNG.Range.generate(
                    Constants.HpMpFormulaArguments[job, 0, (int)Constants.HpMpFormulaFields.HPMin],
                    Constants.HpMpFormulaArguments[job, 0, (int)Constants.HpMpFormulaFields.HPMax],
                    true
                    );

                mpgain += RNG.Range.generate(
                    Constants.HpMpFormulaArguments[job, 0, (int)Constants.HpMpFormulaFields.MPMin],
                    Constants.HpMpFormulaArguments[job, 0, (int)Constants.HpMpFormulaFields.MPMax],
                    true
                    );

                // Additional buffing through INT stats
                mpgain += (short)(
                    intt *
                    Constants.HpMpFormulaArguments[job, 0, (int)Constants.HpMpFormulaFields.MPIntStatMultiplier] /
                    200
                    );

                var improvedMaxHpIncreaseLvl = Skills.GetSkillLevel(Constants.Swordsman.Skills.ImprovedMaxHpIncrease);
                if (improvedMaxHpIncreaseLvl > 0)
                {
                    hpgain += CharacterSkills.GetSkillLevelData(Constants.Swordsman.Skills.ImprovedMaxHpIncrease, improvedMaxHpIncreaseLvl).XValue;
                }

                var improvedMaxMpIncreaseLvl = Skills.GetSkillLevel(Constants.Magician.Skills.ImprovedMaxMpIncrease);
                if (improvedMaxMpIncreaseLvl > 0)
                {
                    mpgain += CharacterSkills.GetSkillLevelData(Constants.Magician.Skills.ImprovedMaxMpIncrease, improvedMaxMpIncreaseLvl).XValue;
                }

                if (PrimaryStats.Job != 0)
                {
                    spgain = Constants.SpPerLevel;
                }

                if (level >= 200)
                {
                    amnt = 0;
                    // TODO: Announce max level!
                }

                // Overflow? lets reduce it
                if (amnt >= expRequired)
                {
                    amnt = (uint)(expRequired - 1);
                }

                _levelLog.Info(new LevelLogRecord
                {
                    level = level,
                    posX  = Position.X,
                    posY  = Position.Y,
                });

                ModifyMaxHP(hpgain);
                ModifyMaxMP(mpgain);
                SetLevel(level);
                AddAP(apgain);
                AddSP(spgain);
                ModifyHP(PrimaryStats.GetMaxHP(false));
                ModifyMP(PrimaryStats.GetMaxMP(false));
                save = true;
            }

            PrimaryStats.EXP = (int)amnt;

            // Calculate savepoints

            var stepOfSave  = CalculateSaveStep();
            var curDateTime = MasterThread.CurrentDate;

            if (!save)
            {
                if (lastSaveStep != stepOfSave)
                {
                    var levelTimeSpan = curDateTime - LastSavepoint;

                    if (levelTimeSpan.TotalSeconds >= 30)
                    {
                        _characterLog.Debug(
                            $"Saving because user reached save threshold. Current {stepOfSave} last {lastSaveStep}");
                        save          = true;
                        LastSavepoint = curDateTime;
                    }
                    else
                    {
                        AssertForHack(
                            levelTimeSpan.TotalSeconds < 20,
                            $"Getting fast EXP ({levelTimeSpan.TotalSeconds} seconds since last savepoint)",
                            levelTimeSpan.TotalSeconds < 15
                            );
                    }
                    _characterLog.Debug(
                        new SavepointLogRecord
                    {
                        level = PrimaryStats.Level,
                        posX  = Position.X,
                        posY  = Position.Y,
                        totalMillisBetween = (int)levelTimeSpan.TotalMilliseconds,
                        blocked            = save == false
                    }
                        );

                    lastSaveStep = stepOfSave;
                }
            }
            else
            {
                lastSaveStep = stepOfSave;
            }


            if (save)
            {
                LastSavepoint = curDateTime;
                Save();
            }

            CharacterStatsPacket.SendStatChange(this, (uint)CharacterStatsPacket.StatFlags.Exp, PrimaryStats.EXP);
        }
Example #3
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);
        }
Example #4
0
        public static void HandleStats(Character chr, Packet packet)
        {
            uint flag = packet.ReadUInt();

            if (chr.AssertForHack(chr.PrimaryStats.AP <= 0, "Trying to use AP, but nothing left."))
            {
                InventoryPacket.NoChange(chr);
                return;
            }

            short jobTrack = Constants.getJobTrack(chr.PrimaryStats.Job);

            switch ((StatFlags)flag)
            {
            case StatFlags.Str:
            {
                if (chr.PrimaryStats.Str >= Constants.MaxStat)
                {
                    InventoryPacket.NoChange(chr);
                    return;
                }
                chr.AddStr(1);
                break;
            }

            case StatFlags.Dex:
            {
                if (chr.PrimaryStats.Dex >= Constants.MaxStat)
                {
                    InventoryPacket.NoChange(chr);
                    return;
                }
                chr.AddDex(1);
                break;
            }

            case StatFlags.Int:
            {
                if (chr.PrimaryStats.Int >= Constants.MaxStat)
                {
                    InventoryPacket.NoChange(chr);
                    return;
                }
                chr.AddInt(1);
                break;
            }

            case StatFlags.Luk:
            {
                if (chr.PrimaryStats.Luk >= Constants.MaxStat)
                {
                    InventoryPacket.NoChange(chr);
                    return;
                }
                chr.AddLuk(1);
                break;
            }

            case StatFlags.MaxHp:
            {
                if (chr.PrimaryStats.MaxHP >= Constants.MaxMaxHp)
                {
                    InventoryPacket.NoChange(chr);
                    return;
                }
                short hpGain = 0;

                hpGain += RNG.Range.generate(
                    Constants.HpMpFormulaArguments[jobTrack, 1, (int)Constants.HpMpFormulaFields.HPMin],
                    Constants.HpMpFormulaArguments[jobTrack, 1, (int)Constants.HpMpFormulaFields.HPMax],
                    true
                    );

                byte improvedMaxHpIncreaseLvl = chr.Skills.GetSkillLevel(Constants.Swordsman.Skills.ImprovedMaxHpIncrease);
                if (improvedMaxHpIncreaseLvl > 0)
                {
                    hpGain += CharacterSkills.GetSkillLevelData(Constants.Swordsman.Skills.ImprovedMaxHpIncrease, improvedMaxHpIncreaseLvl).XValue;
                }

                chr.ModifyMaxHP(hpGain);
                break;
            }

            case StatFlags.MaxMp:
            {
                if (chr.PrimaryStats.MaxMP >= Constants.MaxMaxMp)
                {
                    InventoryPacket.NoChange(chr);
                    return;
                }
                short mpGain = 0;
                short intt   = chr.PrimaryStats.GetIntAddition(true);

                mpGain += RNG.Range.generate(
                    Constants.HpMpFormulaArguments[jobTrack, 1, (int)Constants.HpMpFormulaFields.MPMin],
                    Constants.HpMpFormulaArguments[jobTrack, 1, (int)Constants.HpMpFormulaFields.MPMax],
                    true
                    );

                // Additional buffing through INT stats
                mpGain += (short)(
                    intt *
                    Constants.HpMpFormulaArguments[jobTrack, 1, (int)Constants.HpMpFormulaFields.MPIntStatMultiplier] /
                    200
                    );

                byte improvedMaxMpIncreaseLvl = chr.Skills.GetSkillLevel(Constants.Magician.Skills.ImprovedMaxMpIncrease);
                if (improvedMaxMpIncreaseLvl > 0)
                {
                    mpGain += CharacterSkills.GetSkillLevelData(Constants.Magician.Skills.ImprovedMaxMpIncrease, improvedMaxMpIncreaseLvl).XValue;
                }

                chr.ModifyMaxMP(mpGain);
                break;
            }

            default:
            {
                Program.MainForm.LogAppend("Unknown type {0:X4}", flag);
                break;
            }
            }

            chr.AddAP(-1, true);
            chr.PrimaryStats.CalculateAdditions(false, false);
        }