private static bool CheckChargeAndDamage(int skillId, byte skillLevel, PacketReader pr, out int charge, out int fixedDamage, out SkillEffect effect, out double skillDamage) { WzCharacterSkill wzSkill = DataBuffer.GetCharacterSkillById(skillId); if (wzSkill != null) { charge = wzSkill.IsKeyDownSkill ? pr.ReadInt() : 0; effect = wzSkill.GetEffect(skillLevel); if (!effect.Info.TryGetValue(CharacterSkillStat.fixdamage, out fixedDamage)) { fixedDamage = -1; int temp; if (!effect.Info.TryGetValue(CharacterSkillStat.damage, out temp)) { temp = effect.Info[CharacterSkillStat.x]; } skillDamage = temp / 100.0; } else { skillDamage = 1; } return(true); } effect = null; charge = 0; skillDamage = 1; fixedDamage = -1; return(false); }
public static void MaxSkill(string[] split, MapleClient c) { int skill = int.Parse(split[1]); WzCharacterSkill wzSkill = DataBuffer.GetCharacterSkillById(skill); if (wzSkill != null) { c.Account.Character.SetSkillLevel(skill, wzSkill.MaxLevel, wzSkill.MaxLevel, true); } }
public static void SkillInfo(string[] split, MapleClient c) { int skill = int.Parse(split[1]); byte level = byte.Parse(split[2]); WzCharacterSkill wzSkill = DataBuffer.GetCharacterSkillById(skill); SkillEffect effect = wzSkill.GetEffect(level); c.Account.Character.SendBlueMessage(string.Format("Skill {0} level {1} info:", skill, level)); foreach (var kvp in effect.Info) { c.Account.Character.SendBlueMessage(string.Format("{0} - {1}", Enum.GetName(typeof(CharacterSkillStat), kvp.Key), kvp.Value)); } }
public static void HandleSkill(MapleClient c, PacketReader pr) { int objectId = pr.ReadInt(); MapleSummon summon = c.Account.Character.Map.GetSummon(objectId); if (summon != null && summon.Owner.Id == c.Account.Character.Id && summon.MovementType != SummonMovementType.Stationary) { int skillId = pr.ReadInt(); WzCharacterSkill skillInfo = DataBuffer.GetCharacterSkillById(skillId); if (skillInfo == null) { return; } SkillEffect effect = skillInfo.GetEffect(summon.SkillLevel); switch (skillId) { case Spearman.EVIL_EYE: if (summon.SourceSkillId != Spearman.EVIL_EYE) { return; } if (DateTime.UtcNow.Subtract(summon.LastAbilityTime).TotalMilliseconds < effect.Info[CharacterSkillStat.x] * 1000) { c.CheatTracker.AddOffence(AntiCheat.OffenceType.NoDelaySummon); return; } c.Account.Character.AddHP(effect.Info[CharacterSkillStat.hp]); summon.LastAbilityTime = DateTime.UtcNow; break; case Berserker.HEX_OF_THE_EVIL_EYE: if (summon.SourceSkillId != Spearman.EVIL_EYE) { return; } effect.ApplyBuffEffect(summon.Owner); break; default: string txt = "Unhandled summon skill: " + skillId + " from summon skill: " + summon.SourceSkillId; ServerConsole.Warning(txt); Helpers.FileLogging.Log("Unhandled Summon Skills", txt); break; } //c.SendPacket(Skill.ShowOwnSkillEffect(skillId, summon.SkillLevel)); c.Account.Character.Map.BroadcastPacket(summon.GetUseSkillPacket(skillId, (byte)7), c.Account.Character); //stance ? } }
public void IncreaseLightGauge(int amount, MapleCharacter chr) { if (State == LuminousState.None) { WzCharacterSkill skill = DataBuffer.GetCharacterSkillById(LuminousBasics.SUNFIRE); skill.GetEffect(1).ApplyBuffEffect(chr); chr.AddCooldown(LuminousBasics.SUNFIRE, 180000); State = LuminousState.Light; } if (LightLevel < 5) { LightGauge += amount; if (LightGauge > 10000) { LightGauge = 0; LightLevel++; } } }
public static void HandleKeyMapChange(MapleClient c, PacketReader pr) { //ServerConsole.Info("Key packet:" + pr.ToString()); pr.Skip(4); int count = pr.ReadInt(); //StringBuilder sb = new StringBuilder("Default keys = "); for (int i = 0; i < count; i++) { uint key = (uint)pr.ReadInt(); byte type = pr.ReadByte(); int action = pr.ReadInt(); if (type == 1 && (action >= 1000)) { if (!c.Account.Character.HasSkill(action)) { WzCharacterSkill skillInfo = DataBuffer.GetCharacterSkillById(action); if (skillInfo == null || !skillInfo.HasFixedLevel) { continue; } } } c.Account.Character.ChangeKeybind(key, type, action); /*sb.Append("\n{{"); * sb.Append(key); * sb.Append(", "); * sb.Append("new Pair<byte, int>("); * sb.Append(type); * sb.Append(", "); * sb.Append(action); * sb.Append(")}},");*/ } //ServerConsole.Info(sb.ToString()); }
public void Recalculate(MapleCharacter chr) { int mhpX = 0, mmpX = 0; int mhpR = 0, mmpR = 0; int lv2mhp = 0, lv2mmp = 0; int strR = 0, dexR = 0, intR = 0, lukR = 0; int watk = 0, matk = 9; int damR = 100, pdR = 0; Str = chr.Str + 5; Dex = chr.Dex + 5; Int = chr.Int + 5; Luk = chr.Luk + 5; MinDamage = 0; MaxDamage = 0; AsrR = 0; RecoveryHp = 0; RecoveryMp = 0; RecoveryHpR = 0; RecoveryMpR = 0; RecoveryTime = 0; watk = 3; matk = 3; LifeStealR = 0; LifeStealProp = 0; MpEaterR = 0; MpEaterProp = 0; DoTTimeInc = 0; CostMpR = 0; ExpR = 100; MesoR = 100; DropR = 100; PickPocketR = 0; StunR = 0; AmmoInc = 0; MasteryR = 0; BuffTimeR = 100; PotionEffectR = 100; ElixirEffectR = 100; CritRate = 5; ExpLossReductionR = 0; #region PassiveSkills IEnumerable <Skill> passiveSkills = chr.GetSkillList().Where(x => x.SkillId % 10000 < 1000); foreach (Skill skill in passiveSkills) { if (skill.Level < 1) { continue; } WzCharacterSkill skillInfo = DataBuffer.GetCharacterSkillById(skill.SkillId); if (skillInfo == null) { continue; } SkillEffect effect = skillInfo.GetEffect(skill.Level); if (effect == null) { continue; } foreach (var kvp in effect.Info) { switch (kvp.Key) { case CharacterSkillStat.mhpX: mhpX += kvp.Value; break; case CharacterSkillStat.mmpX: mmpX += kvp.Value; break; case CharacterSkillStat.mhpR: mhpR += kvp.Value; break; case CharacterSkillStat.mmpR: mmpR += kvp.Value; break; case CharacterSkillStat.lv2mhp: lv2mhp += kvp.Value; break; case CharacterSkillStat.lv2mmp: lv2mmp += kvp.Value; break; case CharacterSkillStat.strX: Str += kvp.Value; break; case CharacterSkillStat.dexX: Dex += kvp.Value; break; case CharacterSkillStat.intX: Int += kvp.Value; break; case CharacterSkillStat.lukX: Luk += kvp.Value; break; case CharacterSkillStat.asrR: AsrR += kvp.Value; break; case CharacterSkillStat.mastery: MasteryR = Math.Max(MasteryR, kvp.Value); break; case CharacterSkillStat.costmpR: CostMpR += kvp.Value; break; case CharacterSkillStat.bufftimeR: BuffTimeR += kvp.Value; break; case CharacterSkillStat.padX: watk += kvp.Value; break; case CharacterSkillStat.madX: matk += kvp.Value; break; case CharacterSkillStat.pdR: pdR += kvp.Value; break; case CharacterSkillStat.damR: damR += kvp.Value; break; case CharacterSkillStat.cr: CritRate += kvp.Value; break; } } } #region Specific passive skill handling byte skillLevel; if (chr.IsWarrior) { if ((skillLevel = chr.GetSkillLevel(Swordman.IRON_BODY)) > 0) { mhpR += DataBuffer.CharacterSkillBuffer[Swordman.IRON_BODY].GetEffect(skillLevel).Info[CharacterSkillStat.mhpR]; } if (chr.IsFighter) { if ((skillLevel = chr.GetSkillLevel(Crusader.SELF_RECOVERY)) > 0) { var info = DataBuffer.CharacterSkillBuffer[Crusader.SELF_RECOVERY].GetEffect(skillLevel).Info; RecoveryHp += info[CharacterSkillStat.hp]; RecoveryMp += info[CharacterSkillStat.mp]; } } else if (chr.IsSpearman) { if ((skillLevel = chr.GetSkillLevel(Berserker.LORD_OF_DARKNESS)) > 0) { var info = DataBuffer.CharacterSkillBuffer[Berserker.LORD_OF_DARKNESS].GetEffect(skillLevel).Info; LifeStealProp += info[CharacterSkillStat.prop]; LifeStealR += info[CharacterSkillStat.x]; } } } else if (chr.IsMagician) { if (chr.IsFirePoisonMage) { if ((skillLevel = chr.GetSkillLevel(FirePoison2.SPELL_MASTERY)) > 0) { matk += DataBuffer.CharacterSkillBuffer[FirePoison2.SPELL_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } if ((skillLevel = chr.GetSkillLevel(FirePoison2.MP_EATER)) > 0) { var info = DataBuffer.CharacterSkillBuffer[FirePoison2.MP_EATER].GetEffect(skillLevel).Info; MpEaterProp += info[CharacterSkillStat.prop]; MpEaterR += info[CharacterSkillStat.x]; } } if (chr.IsIceLightningMage) { if ((skillLevel = chr.GetSkillLevel(IceLightning2.MP_EATER)) > 0) { var info = DataBuffer.CharacterSkillBuffer[IceLightning2.MP_EATER].GetEffect(skillLevel).Info; MpEaterProp += info[CharacterSkillStat.prop]; MpEaterR += info[CharacterSkillStat.x]; } if ((skillLevel = chr.GetSkillLevel(IceLightning2.SPELL_MASTERY)) > 0) { matk += DataBuffer.CharacterSkillBuffer[IceLightning2.SPELL_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } } if (chr.IsCleric) { if ((skillLevel = chr.GetSkillLevel(Cleric.MP_EATER)) > 0) { var info = DataBuffer.CharacterSkillBuffer[Cleric.MP_EATER].GetEffect(skillLevel).Info; MpEaterProp += info[CharacterSkillStat.prop]; MpEaterR += info[CharacterSkillStat.x]; } if ((skillLevel = chr.GetSkillLevel(Cleric.SPELL_MASTERY)) > 0) { matk += DataBuffer.CharacterSkillBuffer[Cleric.SPELL_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } if ((skillLevel = chr.GetSkillLevel(Priest.DIVINE_PROTECTION)) > 0) { AsrR += DataBuffer.CharacterSkillBuffer[Priest.DIVINE_PROTECTION].GetEffect(skillLevel).Info[CharacterSkillStat.asrR]; } } } else if (chr.IsArcher) { if (chr.IsHunter) { if ((skillLevel = chr.GetSkillLevel(Bowmaster.BOW_EXPERT)) > 0) { watk += DataBuffer.CharacterSkillBuffer[Bowmaster.BOW_EXPERT].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } } else if (chr.IsCrossbowman) { if ((skillLevel = chr.GetSkillLevel(Marksman.CROSSBOW_EXPERT)) > 0) { watk += DataBuffer.CharacterSkillBuffer[Marksman.CROSSBOW_EXPERT].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } } } else if (chr.IsThief) { if (chr.IsAssassin) { if ((skillLevel = chr.GetSkillLevel(Assassin.CLAW_MASTERY)) > 0) { AmmoInc += DataBuffer.CharacterSkillBuffer[Assassin.CLAW_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.y]; } if ((skillLevel = chr.GetSkillLevel(Hermit.ALCHEMIC_ADRENALINE)) > 0) { PotionEffectR += DataBuffer.CharacterSkillBuffer[Hermit.ALCHEMIC_ADRENALINE].GetEffect(skillLevel).Info[CharacterSkillStat.x] - 100; } if ((skillLevel = chr.GetSkillLevel(NightLord.CLAW_EXPERT)) > 0) { watk += DataBuffer.CharacterSkillBuffer[NightLord.CLAW_EXPERT].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } } else if (chr.IsBandit) { if ((skillLevel = chr.GetSkillLevel(Bandit.SHIELD_MASTERY)) > 0) { watk += DataBuffer.CharacterSkillBuffer[Bandit.SHIELD_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.y]; } if ((skillLevel = chr.GetSkillLevel(ChiefBandit.MESO_MASTERY)) > 0) { var info = DataBuffer.CharacterSkillBuffer[ChiefBandit.MESO_MASTERY].GetEffect(skillLevel).Info; MesoR += info[CharacterSkillStat.mesoR]; PickPocketR += info[CharacterSkillStat.u]; } if ((skillLevel = chr.GetSkillLevel(Shadower.DAGGER_EXPERT)) > 0) { watk += DataBuffer.CharacterSkillBuffer[Shadower.DAGGER_EXPERT].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } } } else if (chr.IsDualBlade) { if ((skillLevel = chr.GetSkillLevel(DualBlade3p.LIFE_DRAIN)) > 0) { var info = DataBuffer.CharacterSkillBuffer[DualBlade3p.LIFE_DRAIN].GetEffect(skillLevel).Info; LifeStealR += info[CharacterSkillStat.x]; LifeStealProp += info[CharacterSkillStat.prop]; } if ((skillLevel = chr.GetSkillLevel(DualBlade4.KATARA_EXPERT)) > 0) { watk += DataBuffer.CharacterSkillBuffer[DualBlade4.KATARA_EXPERT].GetEffect(skillLevel).Info[CharacterSkillStat.x]; } } else if (chr.IsPirate) { if (chr.IsBrawler) { if ((skillLevel = chr.GetSkillLevel(Brawler.PERSEVERANCE)) > 0) { var info = DataBuffer.CharacterSkillBuffer[Brawler.PERSEVERANCE].GetEffect(skillLevel).Info; int x = info[CharacterSkillStat.x]; RecoveryHpR += x; RecoveryMpR += x; RecoveryTime = info[CharacterSkillStat.y]; } if ((skillLevel = chr.GetSkillLevel(Marauder.STUN_MASTERY)) > 0) { StunR += DataBuffer.CharacterSkillBuffer[Marauder.STUN_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.subProp]; } } else if (chr.IsGunslinger) { if ((skillLevel = skillLevel = chr.GetSkillLevel(Gunslinger.GUN_MASTERY)) > 0) { AmmoInc += DataBuffer.CharacterSkillBuffer[Gunslinger.GUN_MASTERY].GetEffect(skillLevel).Info[CharacterSkillStat.y]; } } } else if (chr.IsCannonneer) { if ((skillLevel = chr.GetSkillLevel(Cannoneer3.BARREL_ROULETTE)) > 0) { damR += DataBuffer.CharacterSkillBuffer[Cannoneer3.BARREL_ROULETTE].GetEffect(skillLevel).Info[CharacterSkillStat.damR]; } } else if (chr.IsJett) { /*if ((skillLevel = chr.GetSkillLevel(Jett2.PERSEVERANCE)) > 0) * { * var info = DataBuffer.CharacterSkillBuffer[Jett2.PERSEVERANCE].GetSkillEffect(skillLevel).Info; * int x = info[CharacterSkillStat.x]; * RecoveryHpR += x; * RecoveryMpR += x; * RecoveryTime = info[CharacterSkillStat.y] * 1000; * } */ } #endregion #endregion #region Buffs foreach (Buff buff in chr.GetBuffs()) { var buffInfo = buff.Effect.BuffInfo; foreach (var pair in buffInfo) { //if (pair.Key == MapleBuffStat.ENHANCED_MAXHP || pair.Key == MapleBuffStat.STACKING_MAXHP) //mhpX += pair.Value; if (pair.Key == MapleBuffStat.MAXHP_R || pair.Key == MapleBuffStat.STACKING_MAXHP_R) { mhpR += pair.Value; } //else if (pair.Key == MapleBuffStat.ENHANCED_MAXMP || pair.Key == MapleBuffStat.STACKING_MAXMP) //mmpX += pair.Value; else if (pair.Key == MapleBuffStat.MAXMP_R || pair.Key == MapleBuffStat.STACKING_MAXMP_R) { mmpR += pair.Value; } //else if (pair.Key == MapleBuffStat.WATK || pair.Key == MapleBuffStat.ENHANCED_WATK || pair.Key == MapleBuffStat.STACKING_WATK) //watk += pair.Value; //else if (pair.Key == MapleBuffStat.MATK || pair.Key == MapleBuffStat.ENHANCED_MATK || pair.Key == MapleBuffStat.STACKING_MATK) //matk += pair.Value; //else if (pair.Key == MapleBuffStat.CRIT || pair.Key == MapleBuffStat.STACKING_CRIT) //CritRate += pair.Value; else if (pair.Key == MapleBuffStat.STACKING_STATS) { Str += pair.Value; Dex += pair.Value; Int += pair.Value; Luk += pair.Value; } else if (pair.Key == MapleBuffStat.STACKING_STATS_R) { Str += (int)(chr.Str * (pair.Value / 100.0)); //todo: check if this isnt math.ceil Dex += (int)(chr.Dex * (pair.Value / 100.0)); Int += (int)(chr.Int * (pair.Value / 100.0)); Luk += (int)(chr.Luk * (pair.Value / 100.0)); } //else if (pair.Key == MapleBuffStat.HOLY_SYMBOL) { // ExpR += pair.Value; } } } #endregion #region Equips foreach (MapleItem item in chr.Inventory.GetItemsFromInventory(MapleInventoryType.Equipped)) { MapleEquip equip = item as MapleEquip; if (equip == null) { continue; } mhpX += equip.IncMhp; mmpX += equip.IncMmp; Str += equip.Str; Dex += equip.Dex; Int += equip.Int; Luk += equip.Luk; watk += equip.Pad; matk += equip.Mad; //todo: potential stuff from here } #endregion MaxHp = chr.MaxHp; MaxHp += lv2mhp * chr.Level; MaxHp += (int)((MaxHp) * (mhpR / 100.0)); MaxHp += mhpX; if (chr.Hp > MaxHp) { chr.AddHP(-(chr.Hp - MaxHp)); } MaxMp = chr.MaxMp; MaxMp += (int)(chr.MaxMp * (double)(mmpR / 100.0)); MaxMp += lv2mmp * chr.Level; MaxMp += mhpX; if (chr.Mp > MaxMp) { chr.AddMP(-(chr.Mp - MaxMp)); } Str += (short)(chr.Str * (double)(strR / 100.0)); Dex += (short)(chr.Dex * (double)(dexR / 100.0)); Int += (short)(chr.Int * (double)(intR / 100.0)); Luk += (short)(chr.Luk * (double)(lukR / 100.0)); bool mage = false; int primaryStat = 0; int secondaryStat = 0; MapleItem weapon = chr.Inventory.GetEquippedItem((short)MapleEquipPosition.Weapon); if (weapon == null) { MinDamage = 1; MaxDamage = 1; return; } MapleItemType weaponItemType = ItemConstants.GetMapleItemType(weapon.ItemId); switch ((chr.Job % 1000) / 100) { case 1: //Warrior-type primaryStat = Str; secondaryStat = Dex; break; case 2: //Magician-type case 7: //Luminous primaryStat = Int; secondaryStat = Luk; mage = true; break; case 3: //Archer-type primaryStat = Dex; secondaryStat = Str; break; case 4: //Thief-type primaryStat = Luk; secondaryStat = Dex; break; case 5: //Pirate-type if (weaponItemType == MapleItemType.Gun || weaponItemType == MapleItemType.SoulShooter) { primaryStat = Dex; secondaryStat = Str; } else //counts for cannons too { primaryStat = Str; secondaryStat = Dex; } break; case 6: //Xenon primaryStat = (Str + Dex + Luk); break; } if (!mage) { damR += pdR; //TODO: check, Not sure about this } CalculateDamageRange(weaponItemType, primaryStat, secondaryStat, mage ? matk : watk, damR, chr.IsFighter); }
public static void HandleAttack(MapleClient c, PacketReader pr) { int objectId = pr.ReadInt(); MapleCharacter chr = c.Account.Character; MapleSummon summon = chr.Map.GetSummon(objectId); if (summon != null) { if (summon.Owner.Id != chr.Id) { return; } int tickCount = pr.ReadInt(); WzCharacterSkill skillInfo = DataBuffer.GetCharacterSkillById(summon.SourceSkillId); if (skillInfo == null || skillInfo.SummonInfo == null) { return; } WzCharacterSkill.SummonAttackInfo summonAttackInfo = skillInfo.SummonInfo; byte animation = pr.ReadByte(); byte attackByte = pr.ReadByte(); int attacks = (attackByte & 0x0F); int targets = ((attackByte >> 4) & 0x0F); if (summonAttackInfo.MobCount < targets || summonAttackInfo.AttackCount < attacks) { ServerConsole.Warning("Player " + chr.Name + "'s summon: " + summon.SourceSkillId + "has mismatching targets- or attackcount: " + attacks + "/" + summonAttackInfo.AttackCount + " attacks, " + targets + "/" + summonAttackInfo.MobCount + " mobs"); return; } pr.Skip(12); List <AttackPair> attackList = new List <AttackPair>(); for (int i = 0; i < targets; i++) { int targetObjectId = pr.ReadInt(); MapleMonster target = chr.Map.GetMob(targetObjectId); if (target == null) { ServerConsole.Debug("Error parsing summon attack, summon skillId: " + summon.SourceSkillId + " attack byte: " + attackByte); return; } AttackPair ap = new AttackPair(); ap.TargetObjectId = targetObjectId; pr.Skip(24); int damage = pr.ReadInt(); //only supports 1 damage count, not sure if there are summons with attackcount > 1 ap.Damage.Add(damage); attackList.Add(ap); pr.Skip(4); } AttackInfo attackInfo = new AttackInfo(); attackInfo.Attacks = attacks; attackInfo.AttacksByte = attackByte; attackInfo.Speed = animation; attackInfo.Targets = targets; attackInfo.TargetDamageList = attackList; foreach (AttackPair ap in attackList) { MapleMonster mob = chr.Map.GetMob(ap.TargetObjectId); if (mob != null) { long totalDamage = 0; foreach (int i in ap.Damage) { totalDamage += i; } if (totalDamage > int.MaxValue) { totalDamage = int.MaxValue; } mob.Damage(chr, (int)totalDamage); } } bool darkFlare = summon.SourceSkillId == ChiefBandit.DARK_FLARE || summon.SourceSkillId == Hermit.DARK_FLARE || summon.SourceSkillId == NightWalker3.DARK_FLARE; chr.Map.BroadcastPacket(summon.GetAttackPacket(attackInfo, darkFlare)); } }
public static void Handle(MapleClient c, PacketReader packet) { MapleCharacter chr = c.Account.Character; if (!chr.DisableActions()) { return; } try { int tickCount = packet.ReadInt(); int skillId = packet.ReadInt(); byte amount = packet.ReadByte(); //new v137, multiple sp if (amount <= 0) { amount = 1; } short skillJobId = (short)(skillId / 10000); WzCharacterSkill wzSkill = DataBuffer.GetCharacterSkillById(skillId); if (wzSkill == null) { return; } if (wzSkill.IsGmSkill && !chr.IsStaff) { return; } if (!JobConstants.JobCanLearnSkill(skillId, chr.Job)) { return; } if (wzSkill.HasFixedLevel) { return; } if (chr.Level < wzSkill.RequiredLevel) { return; } if (wzSkill.RequiredSkills != null) { foreach (var kvp in wzSkill.RequiredSkills) { if (!chr.HasSkill(kvp.Key, kvp.Value)) { return; } } } if (wzSkill.IsHyperSkill) { chr.SendPopUpMessage("Hyper skills aren't functional yet."); chr.EnableActions(); return; } if (JobConstants.IsBeginnerJob(skillJobId)) { switch (skillId) { //Three snails: case Explorer.THREE_SNAILS: case Cygnus.THREE_SNAILS: case AranBasics.THREE_SNAILS: case EvanBasics.THREE_SNAILS: case MihileBasics.THREE_SNAILS: //Recovery: case Explorer.RECOVERY: case Cygnus.RECOVERY: case AranBasics.RECOVERY: case EvanBasics.RECOVER: case MihileBasics.RECOVERY: //Nimble Feet: case Explorer.NIMBLE_FEET: case Cygnus.NIMBLE_FEET: case AranBasics.AGILE_BODY: case EvanBasics.NIMBLE_FEET: case MihileBasics.NIMBLE_FEET: //Resistance: case Resistance.POTION_MASTERY: case Resistance.INFILTRATE: case Resistance.CRYSTAL_THROW: if (chr.GetSkillLevel(skillId) + amount > 3) //already maxed { return; } int baseNum = 0; switch (skillId / 100000) { case 300: //resistance { if (!chr.IsResistance) { return; } int usedBeginnerSP = chr.GetSkillLevel(Resistance.CRYSTAL_THROW) + chr.GetSkillLevel(Resistance.INFILTRATE) + chr.GetSkillLevel(Resistance.POTION_MASTERY); if (usedBeginnerSP + amount <= 9 && chr.GetSkillLevel(skillId) + amount <= 3) { chr.IncreaseSkillLevel(skillId, amount); } break; } case 0: if (!chr.IsExplorer) { return; } goto common; case 100: //cygnus if (!chr.IsCygnus) { return; } baseNum = 10000000; goto common; case 200: //hero if (!chr.IsAran && !chr.IsEvan) { return; } baseNum = 20000000; goto common; case 500: //mihile if (!chr.IsMihile) { return; } baseNum = 50000000; common: { int usedBeginnerSP = chr.GetSkillLevel(baseNum + 1000) + chr.GetSkillLevel(baseNum + 1001) + chr.GetSkillLevel(baseNum + 1002); if (usedBeginnerSP + amount <= 6 && chr.GetSkillLevel(skillId) + amount <= 3) { chr.IncreaseSkillLevel(skillId, amount); } break; } default: return; } break; default: return; } } else { int spTableIndex = JobConstants.GetSkillBookForJob(skillJobId); if (chr.SpTable[spTableIndex] >= amount) { Skill skill = chr.GetSkill(skillId); if (skill == null) //Player doesnt have the skill yet { int maxLevel = wzSkill.HasMastery ? wzSkill.DefaultMastery : wzSkill.MaxLevel; if (amount <= maxLevel) { chr.LearnSkill(skillId, amount, wzSkill); chr.SpTable[spTableIndex] -= amount; MapleCharacter.UpdateSingleStat(c, MapleCharacterStat.Sp, chr.SpTable[0], true); } } else { if (skill.Level + amount <= skill.MasterLevel) { chr.IncreaseSkillLevel(skillId, amount); chr.SpTable[spTableIndex] -= amount; MapleCharacter.UpdateSingleStat(c, MapleCharacterStat.Sp, chr.SpTable[0], true); } } } } } finally { chr.EnableActions(false); } }
private static void HandleAttackInfo(MapleClient c, AttackInfo attackInfo, SendHeader type, SkillEffect effect) { //Anti-cheat //c.CheatTracker.Trigger(AntiCheat.TriggerType.Attack); WzCharacterSkill wzSkill = effect != null ? effect.Parent : null; MapleCharacter chr = c.Account.Character; if (attackInfo.SkillId > 0) { if (!SkillEffect.CheckAndApplySkillEffect(c.Account.Character, attackInfo.SkillId, wzSkill, -1, attackInfo.Targets, attackInfo.Attacks)) { return; } } chr.Map.BroadcastPacket(GenerateAttackInfo(type, c.Account.Character, attackInfo), c.Account.Character, false); long totalDamage = 0; #region DoTs and Pickpocket int pickPocketProp = 0; int dotSkillId = 0; int dotChance = 0; int dotDamage = 0; int dotTimeMS = 0; int dotMaxStacks = 1; #region Thief if (chr.IsThief) { byte venomSkillLevel = 0; if (chr.IsBandit) { Buff pickPocket = chr.GetBuff(ChiefBandit.PICKPOCKET); if (pickPocket != null) { pickPocketProp = pickPocket.Effect.Info[CharacterSkillStat.prop]; } venomSkillLevel = chr.GetSkillLevel(ChiefBandit.VENOM); if (venomSkillLevel > 0) { dotSkillId = ChiefBandit.VENOM; byte toxicVenomSkillLevel = chr.GetSkillLevel(Shadower.TOXIC_VENOM); if (toxicVenomSkillLevel > 0) { venomSkillLevel = toxicVenomSkillLevel; dotSkillId = Shadower.TOXIC_VENOM; } } } else if (chr.IsAssassin) { #region Assassin venomSkillLevel = chr.GetSkillLevel(Hermit.VENOM); if (venomSkillLevel > 0) { dotSkillId = Hermit.VENOM; byte toxicVenomSkillLevel = chr.GetSkillLevel(NightLord.TOXIC_VENOM); if (toxicVenomSkillLevel > 0) { venomSkillLevel = toxicVenomSkillLevel; dotSkillId = NightLord.TOXIC_VENOM; } } #endregion } else if (chr.IsDualBlade) { #region DualBlade venomSkillLevel = chr.GetSkillLevel(DualBlade3.VENOM); if (venomSkillLevel > 0) { dotSkillId = DualBlade3.VENOM; byte toxicVenomSkillLevel = chr.GetSkillLevel(DualBlade4.TOXIC_VENOM); if (toxicVenomSkillLevel > 0) { venomSkillLevel = toxicVenomSkillLevel; dotSkillId = DualBlade4.TOXIC_VENOM; } } #endregion } if (venomSkillLevel > 0) { SkillEffect venomEffect = DataBuffer.GetCharacterSkillById(dotSkillId).GetEffect(venomSkillLevel); dotChance = venomEffect.Info[CharacterSkillStat.prop]; dotDamage = (int)(chr.Stats.GetDamage() * (venomEffect.Info[CharacterSkillStat.dot] / 100.0)); dotTimeMS = venomEffect.Info[CharacterSkillStat.dotTime] * 1000; if (!venomEffect.Info.TryGetValue(CharacterSkillStat.dotSuperpos, out dotMaxStacks)) { dotMaxStacks = 1; } } } #endregion if (attackInfo.SkillId > 0 && effect.Info.TryGetValue(CharacterSkillStat.dot, out dotDamage)) //Skill has/is dot { dotTimeMS = effect.Info[CharacterSkillStat.dotTime] * 1000; if (!effect.Info.TryGetValue(CharacterSkillStat.prop, out dotChance)) { dotChance = 100; } dotSkillId = attackInfo.SkillId; dotDamage = (int)(chr.Stats.GetDamage() * (dotDamage / 100.0)); if (!effect.Info.TryGetValue(CharacterSkillStat.dotSuperpos, out dotMaxStacks)) { dotMaxStacks = 1; } } #endregion foreach (AttackPair ap in attackInfo.TargetDamageList) { MapleMonster mob = chr.Map.GetMob(ap.TargetObjectId); if (mob != null && mob.Alive) { long totalMobDamage = 0; foreach (int damage in ap.Damage) { totalMobDamage += damage; } if (totalMobDamage > 0) { totalDamage += totalMobDamage; if (totalDamage > int.MaxValue) { totalDamage = int.MaxValue; } #region Status effects if (effect != null) { foreach (MonsterBuffApplication mba in effect.MonsterBuffs) { if (Functions.MakeChance(mba.Prop)) { foreach (var kvp in mba.Buffs) { mob.ApplyStatusEffect(attackInfo.SkillId, kvp.Key, kvp.Value, mba.Duration, chr); } } } } #endregion #region MP Eater if (chr.Stats.MpEaterProp > 0) { if (Functions.MakeChance(chr.Stats.MpEaterProp)) { int mpSteal = (int)((chr.Stats.MpEaterR / 100.0) * mob.WzInfo.MP); chr.AddMP(mpSteal); } } #endregion #region Bandit if (chr.IsBandit) { if (Functions.MakeChance(pickPocketProp)) { chr.Map.SpawnMesoMapItem(1, mob.Position, chr.Map.GetDropPositionBelow(mob.Position, mob.Position), false, MapleDropType.Player, chr); } if (attackInfo.SkillId == Bandit.STEAL) { int prop = DataBuffer.GetCharacterSkillById(Bandit.STEAL).GetEffect(chr.GetSkillLevel(Bandit.STEAL)).Info[CharacterSkillStat.prop]; if (Functions.MakeChance(prop)) { MapleItem item = mob.TryGetStealableItem(chr.Id, chr.Name); if (item != null) { chr.Map.SpawnMapItem(item, mob.Position, chr.Map.GetDropPositionBelow(chr.Position, mob.Position), false, Map.MapleDropType.Player, chr); } } } } #endregion if (Functions.MakeChance(dotChance)) { mob.ApplyPoison(dotSkillId, dotTimeMS, dotDamage, 1000, chr, dotMaxStacks); } mob.Damage(chr, (int)totalDamage); } } } #region special skill handling if (type == SendHeader.RangedAttack) { if (attackInfo.Targets > 0 && chr.IsHunter) { #region QuiverCartridge QuiverCartridgeSystem qcs = chr.Resource as QuiverCartridgeSystem; if (qcs != null && qcs.ChosenArrow > -1) { int usedArrow = qcs.HandleUse(c); switch (usedArrow) { case 0: // Blood if (Functions.MakeChance(50)) //50% chance to heal 20% of damage as hp { chr.AddHP((int)(totalDamage * 0.2)); } break; case 1: // Poison //TODO: poison, 90% damage, 8 seconds, stacks 3 times break; case 2: // Magic, don't need handling I think break; } } #endregion } } if (totalDamage > 0) { BuffedCharacterStats stats = chr.Stats; if (stats.LifeStealProp > 0 && stats.LifeStealR > 0) { if (Functions.MakeChance(stats.LifeStealProp)) { int lifesteal = (int)((stats.LifeStealR / 100.0) * totalDamage); chr.AddHP(lifesteal); } } if (chr.IsMagician) { #region ArcaneAim int arcaneAimId = 0; if (chr.Job == JobConstants.FIREPOISON4) { arcaneAimId = FirePoison4.ARCANE_AIM; } else if (chr.Job == JobConstants.ICELIGHTNING4) { arcaneAimId = IceLightning4.ARCANE_AIM; } else if (chr.Job == JobConstants.BISHOP) { arcaneAimId = Bishop.ARCANE_AIM; } if (arcaneAimId > 0) { byte skillLevel = chr.GetSkillLevel(arcaneAimId); if (skillLevel > 0) { if ((DateTime.UtcNow.Subtract(chr.LastAttackTime).TotalMilliseconds) < 5000) { Buff oldBuff = chr.GetBuff(arcaneAimId); if (oldBuff != null) { int prop = oldBuff.Effect.Info[CharacterSkillStat.prop]; if (Functions.MakeChance(prop)) { Buff newBuff = new Buff(arcaneAimId, oldBuff.Effect, oldBuff.Duration, chr); int oldStacks = oldBuff.Stacks / 6; newBuff.Stacks = Math.Min(30, (oldStacks + 1) * 6); chr.GiveBuff(newBuff); } } else { SkillEffect arcaneAimEffect = DataBuffer.GetCharacterSkillById(arcaneAimId).GetEffect(skillLevel); int prop = arcaneAimEffect.Info[CharacterSkillStat.prop]; if (Functions.MakeChance(prop)) { Buff newBuff = new Buff(arcaneAimId, arcaneAimEffect, 5000, chr); newBuff.Stacks = 6; chr.GiveBuff(newBuff); } } } } } #endregion } else if (chr.IsThief) { if (chr.IsBandit) { chr.IncreaseCriticalGrowth(true); byte skillLevel = chr.GetSkillLevel(Shadower.SHADOWER_INSTINCT); if (skillLevel > 0) { ((BodyCountSystem)chr.Resource).IncreaseBodyCount(c); } } } } #endregion chr.LastAttackTime = DateTime.UtcNow; }