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()); } } } }
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); }
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); }