public static void HandleMove(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) { pr.Skip(4); Point startPosition = pr.ReadPoint(); pr.Skip(4); List <MapleMovementFragment> movements = ParseMovement.Parse(pr); if (movements != null && movements.Count > 0) { c.Account.Character.Map.BroadcastPacket(summon.MovePacket(startPosition, movements), c.Account.Character); for (int i = movements.Count - 1; i >= 0; i--) { if (movements[i] is AbsoluteLifeMovement) { summon.Position = movements[i].Position; break; } } } } }
public static void HandleRemove(MapleClient c, PacketReader pr) { int objectId = pr.ReadInt(); MapleSummon summon = c.Account.Character.Map.GetSummon(objectId); if (summon != null) { if (summon.Owner.Id == c.Account.Character.Id) { c.Account.Character.RemoveSummon(summon.SourceSkillId); } } }
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 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)); } }
private static int DoMonsterDamageModifiers(int damage, MapleCharacter chr, MapleMonster mobFrom, int mobFromOID) { if (damage == 0) //guard/miss etc { Buff buff = chr.GetBuff(Priest.HOLY_MAGIC_SHELL); if (buff != null) { buff.Stacks -= 1; if (buff.Stacks == 0) { chr.CancelBuff(Priest.HOLY_MAGIC_SHELL); } } } #region Spearman if (chr.IsSpearman) { if (chr.Job >= JobConstants.BERSERKER) { if (chr.Job == JobConstants.DARKKNIGHT) { byte evilEyeRevengeLevel = chr.GetSkillLevel(DarkKnight.REVENGE_OF_THE_EVIL_EYE); if (evilEyeRevengeLevel > 0 && !chr.HasSkillOnCooldown(DarkKnight.REVENGE_OF_THE_EVIL_EYE)) { MapleSummon evilEye = chr.GetSummon(Spearman.EVIL_EYE); Buff evilEyebuff = chr.GetBuff(Spearman.EVIL_EYE); if (evilEye != null && evilEyebuff != null && evilEyebuff.Stacks != Berserker.EVIL_EYE_OF_DOMINATION) { SkillEffect effect = DataBuffer.GetCharacterSkillById(DarkKnight.REVENGE_OF_THE_EVIL_EYE).GetEffect(evilEyeRevengeLevel); int summonDamage = (int)((effect.Info[CharacterSkillStat.damage] / 100.0) * chr.Stats.GetDamage()); int healHp = (int)((effect.Info[CharacterSkillStat.x] / 100.0) * summonDamage); chr.AddHP(healHp); //instant KO: if (!mobFrom.IsBoss && summonDamage < mobFrom.HP) { if (Functions.MakeChance(effect.Info[CharacterSkillStat.z])) { summonDamage = mobFrom.HP; } } evilEye.AttackMonster(summonDamage, 0x84, mobFrom); chr.AddCooldownSilent(DarkKnight.REVENGE_OF_THE_EVIL_EYE, (uint)effect.Info[CharacterSkillStat.cooltime] * 1000, DateTime.UtcNow, false); } } if (chr.HasBuff(DarkKnight.FINAL_PACT2)) { return(0); //Invincible } } Buff crossSurgeBuff = chr.GetBuff(Berserker.CROSS_SURGE); if (crossSurgeBuff != null) { int absorbPercent = crossSurgeBuff.Effect.Info[CharacterSkillStat.y]; int absorb = (int)((chr.Stats.MaxHp - chr.Hp) * (absorbPercent / 100.0)); absorb = Math.Min(absorb, crossSurgeBuff.Effect.Info[CharacterSkillStat.z]); //normally z = 4000 damage -= absorb; } } } #endregion #region Magician else if (chr.IsMagician) { Buff buff = chr.GetBuff(Magician.MAGIC_GUARD); if (buff != null) { if (chr.Mp > 0) { int absorb = (int)((buff.Effect.Info[CharacterSkillStat.x] / 100.0) * damage); if (chr.Mp < absorb) { absorb = chr.Mp; } chr.AddMP(-absorb); damage -= absorb; } } } #endregion #region Bandit else if (chr.IsBandit) { Buff mesoGuard = chr.GetBuff(Bandit.MESOGUARD); if (mesoGuard != null) { double absorb = 0.5; double mesoLoss = mesoGuard.Effect.Info[CharacterSkillStat.x] / 100.0; double mesoLossReduction = 0.0; byte MesoMasteryLevel = chr.GetSkillLevel(ChiefBandit.MESO_MASTERY); if (MesoMasteryLevel > 0) { SkillEffect effect = DataBuffer.GetCharacterSkillById(ChiefBandit.MESO_MASTERY).GetEffect(MesoMasteryLevel); absorb += effect.Info[CharacterSkillStat.v] / 100.0; mesoLossReduction = effect.Info[CharacterSkillStat.v] / 100.0; } int damageAbsorbed = (int)(damage * absorb); if (damageAbsorbed > 0) { int mesoUse = (int)(damageAbsorbed * mesoLoss); mesoUse -= (int)(mesoUse * mesoLossReduction); if (chr.Mesos >= mesoUse) { chr.Inventory.RemoveMesos(mesoUse, false); damage -= damageAbsorbed; int mesoDrops = Functions.Random(1, 4); for (int i = 0; i < mesoDrops; i++) { chr.Map.SpawnMesoMapItem(1, chr.Position, chr.Map.GetDropPositionBelow(chr.Position, chr.Position), false, MapleDropType.Player, chr); } } } } } #endregion #region Luminous else if (chr.IsLuminous) { Buff oldBuff = chr.GetBuff(Luminous2.BLACK_BLESSING); if (oldBuff != null) { int remove = (int)(damage * 0.7); damage -= remove; if (oldBuff.Stacks < 2) { chr.CancelBuff(Luminous2.BLACK_BLESSING); } else { chr.CancelBuffSilent(Luminous2.BLACK_BLESSING); Buff newBuff = new Buff(oldBuff.SkillId, oldBuff.Effect, oldBuff.Duration, chr); newBuff.Stacks = oldBuff.Stacks - 1; chr.GiveBuff(newBuff); } } byte skillLevel = 0; if ((skillLevel = chr.GetSkillLevel(Luminous1.STANDARD_MAGIC_GUARD)) > 0) { SkillEffect effect = DataBuffer.GetCharacterSkillById(Luminous1.STANDARD_MAGIC_GUARD).GetEffect(skillLevel); double percent = effect.Info[CharacterSkillStat.x] / 100.0; int absorb = (int)(percent * damage); if (chr.Mp >= absorb) { chr.AddMP(absorb); damage -= absorb; } } } #endregion return(damage); }
public void ApplyEffect(MapleCharacter source, MapleCharacter target) { int value; if (SkillConstants.IsHealSkill(Parent.SkillId) && Info.TryGetValue(CharacterSkillStat.hp, out value)) { int healHp = (int)((value / 100.0) * source.Stats.GetDamage()); target.AddHP(healHp); } #region Mist if (SkillConstants.IsMistSkill(Parent.SkillId)) { Point sourcePos = source.Position; BoundingBox boundingBox = CalculateBoundingBox(sourcePos, source.IsFacingLeft); source.Map.SpawnMist(Parent.SkillId, Level, source, boundingBox, sourcePos, Info[CharacterSkillStat.time] * 1000, false); } else if (Parent.SkillId == Priest.MYSTIC_DOOR) { MapleMap fromMap = source.Map; if (fromMap.MysticDoorLimit) { return; } source.CancelDoor(Priest.MYSTIC_DOOR); int partyId = source.Party?.Id ?? -1; Point fromMapPosition = source.Map.GetDropPositionBelow(source.Position, source.Position); int time = Info[CharacterSkillStat.time] * 1000; MapleMap toMap = Program.GetChannelServer(source.Client.Channel).GetMap(source.Map.ReturnMap); if (toMap != null) { WzMap.Portal toPortal = toMap.TownPortal; if (toPortal != null) { Point toMapPosition = toMap.GetDropPositionBelow(toPortal.Position, toPortal.Position); MysticDoor sourceDoor = new MysticDoor(Parent.SkillId, source, fromMapPosition, fromMap, toMap, toPortal, time, true); fromMap.SpawnStaticObject(sourceDoor); source.AddDoor(sourceDoor); } } } #endregion #region Summons if (Parent.HasSummon) { source.RemoveSummon(Parent.SkillId); //Remove old one if exists WzCharacterSkill.SummonAttackInfo info = Parent.SummonInfo; MapleSummon summon = new MapleSummon(source.Map.GetNewObjectId(), Parent.SkillId, source.Position, info.Type, info.MovementType, source, Level, (uint)Info[CharacterSkillStat.time] * 1000); source.AddSummon(summon); } #endregion //Custom handling: switch (Parent.SkillId) { case Hunter.QUIVER_CARTRIDGE: QuiverCartridgeSystem qcs = source.Resource as QuiverCartridgeSystem; if (qcs != null) { qcs.SwitchCurrentArrow(source.Client); } break; case Priest.HOLY_MAGIC_SHELL: case SuperGameMaster.HEAL_DISPEL: target.AddHP(target.Stats.MaxHp); break; case Bishop.RESURRECTION: case SuperGameMaster.RESURRECTION: if (target.IsDead) { target.Revive(false, false, true); } break; } }
public static bool CheckAndApplySkillEffect(MapleCharacter chr, int skillId, WzCharacterSkill wzCharacterSkill, int skillLevel = -1, int numTargets = 0, int numAttacks = 0) { if (skillLevel == -1) { skillLevel = chr.GetSkillLevel(skillId); } if (wzCharacterSkill == null) { wzCharacterSkill = DataBuffer.GetCharacterSkillById(skillId); if (wzCharacterSkill == null) { return(false); } } if (wzCharacterSkill.HasFixedLevel && JobConstants.JobCanLearnSkill(skillId, chr.Job)) { skillLevel = 1; } if (chr.IsPhantom) //check stolen skill level { PhantomSystem resource = (PhantomSystem)chr.Resource; int chosenSkillIndex = resource.GetChosenSkillIndex(skillId); if (chosenSkillIndex > -1) { int impeccableMemory = PhantomSystem.GetStealSkill(chosenSkillIndex + 1); skillLevel = Math.Min(chr.GetSkillLevel(impeccableMemory), chr.GetSkillLevel(skillId)); } } if (skillLevel == 0 || (chr.HasSkillOnCooldown(skillId))) { string text = "Player tried using skill " + skillId + " while level 0 or on cooldown."; ServerConsole.Warning(text); FileLogging.Log("./LinkedSkills.txt", text); return(false); } SkillEffect effect = wzCharacterSkill.GetEffect((byte)skillLevel); if (effect == null) { return(false); } bool shadowPartner = false; if (numTargets > 0) { int attackCount = effect.AttackCount; if (chr.IsLuminous || (chr.IsBandit && chr.HasBuff(ChiefBandit.SHADOW_PARTNER)) || (chr.IsAssassin && chr.HasBuff(Hermit.SHADOW_PARTNER)) || (chr.IsNightWalker && chr.HasBuff(NightWalker3.SHADOW_PARTNER))) { attackCount *= 2; shadowPartner = true; } if (effect.MobCount < numTargets || attackCount < numAttacks) { return(false); } } int bulletConsume; if (effect.Info.TryGetValue(CharacterSkillStat.bulletConsume, out bulletConsume)) { if (shadowPartner) { bulletConsume *= 2; } if (!DealDamageHandler.HandleRangedAttackAmmoUsage(chr, bulletConsume)) { ServerConsole.Warning("Character with job: " + chr.Job + " tried using a skill with bulletCount: " + bulletConsume + " but doesn't have the bullets!"); return(false); } } if (chr.Mp < effect.MpCon) { return(false); } else { chr.AddMP(-effect.MpCon); } int hpCon; if (effect.Info.TryGetValue(CharacterSkillStat.hpCon, out hpCon)) { if (chr.Hp < hpCon) { return(false); } chr.AddHP(-hpCon); } #region Manual skill handlers and checks if (chr.IsAran && effect.Info.ContainsKey(CharacterSkillStat.aranComboCon)) { if (!AranSystem.HandleComboUsage(chr, effect.Info[CharacterSkillStat.aranComboCon])) { return(false); } } else if (chr.IsLuminous && chr.Job >= JobConstants.LUMINOUS2 && effect.Info.ContainsKey(CharacterSkillStat.gauge)) { LuminousSystem.HandleGaugeGain(chr, skillId, effect.Info[CharacterSkillStat.gauge]); } switch (skillId) { case Berserker.EVIL_EYE_OF_DOMINATION: { Buff evilEyeBuff = chr.GetBuff(Spearman.EVIL_EYE); MapleSummon evilEye = chr.GetSummon(Spearman.EVIL_EYE); if (evilEyeBuff == null || evilEye == null) { return(false); } uint timeUsed = (uint)((DateTime.UtcNow.Subtract(evilEyeBuff.StartTime)).TotalMilliseconds); uint timeRemainingMS = (uint)evilEyeBuff.Duration - timeUsed; Buff newBuff = new Buff(Spearman.EVIL_EYE, effect, timeRemainingMS, chr); if (evilEyeBuff.Stacks == Berserker.EVIL_EYE_OF_DOMINATION) { newBuff.Stacks = Spearman.EVIL_EYE; evilEye.MovementType = SummonMovementType.Follow; } else { newBuff.Stacks = Berserker.EVIL_EYE_OF_DOMINATION; evilEye.MovementType = SummonMovementType.CircleFollow; } chr.GiveBuff(newBuff); return(true); //no other actions needed } case Berserker.EVIL_EYE_SHOCK: { MapleSummon evilEye = chr.GetSummon(Spearman.EVIL_EYE); if (evilEye == null) { return(false); } List <MapleMonster> mobs = chr.Map.GetMobsInRange(new BoundingBox(evilEye.Position, wzCharacterSkill.TopLeft, wzCharacterSkill.BottomRight)); if (mobs.Count > 0) { int damage = (int)((effect.Info[CharacterSkillStat.damage] / 100.0) * chr.Stats.GetDamage()); int stunProp = effect.Info[CharacterSkillStat.prop]; int stunTime = effect.Info[CharacterSkillStat.time] * 1000; int mobCounter = 0; foreach (MapleMonster mob in mobs) { mob.Damage(chr, damage); if (mob.Alive) { if (Functions.MakeChance(stunProp)) { mob.ApplyStatusEffect(skillId, MonsterBuffStat.STUN, 1, stunTime, chr); } } mobCounter++; if (mobCounter == 10) { break; } } } break; } case DarkKnight.SACRIFICE: if (!chr.RemoveSummon(Spearman.EVIL_EYE)) { return(false); } chr.CancelBuff(Spearman.EVIL_EYE); int healHpR = effect.Info[CharacterSkillStat.y]; int heal = (int)((healHpR / 100.0) * chr.Stats.MaxHp); chr.AddHP(heal); break; case LuminousBasics.SUNFIRE: case LuminousBasics.ECLIPSE: case LuminousBasics.EQUILIBRIUM2: LuminousSystem.HandleChangeDarkLight(chr, skillId); break; } #endregion #region Apply Cooldown bool skipCooldown = skillId == DarkKnight.GUNGNIRS_DESCENT && (chr.HasBuff(DarkKnight.SACRIFICE) || chr.HasBuff(DarkKnight.FINAL_PACT2)); if (!skipCooldown) { int coolTime; if (effect.Info.TryGetValue(CharacterSkillStat.cooltime, out coolTime) && coolTime > 0) { chr.AddCooldown(skillId, (uint)coolTime * 1000); //time in the wz is in seconds } } #endregion effect.ApplyEffect(chr, chr); if (wzCharacterSkill.IsBuff) { effect.ApplyBuffEffect(chr); chr.Map.BroadcastPacket(SkillEffect.Packets.ShowForeignSkillEffect(chr.Id, chr.Level, skillId, effect.Level), chr); } if (wzCharacterSkill.IsPartySkill) { if (chr.Party != null) { List <MapleCharacter> partyMembersOnSameMap = chr.Party.GetCharactersOnMap(chr.Map, chr.Id); if (partyMembersOnSameMap.Count > 0) { List <MapleCharacter> partyMembersInRange = chr.Map.GetCharactersInRange(effect.CalculateBoundingBox(chr.Position, chr.IsFacingLeft), partyMembersOnSameMap); foreach (MapleCharacter partyMember in partyMembersInRange) { effect.ApplyEffect(chr, partyMember); if (wzCharacterSkill.IsBuff) { effect.ApplyBuffEffect(partyMember); } } } } else if (wzCharacterSkill.IsGmSkill && chr.IsStaff) { var targets = chr.Map.GetCharactersInRange(effect.CalculateBoundingBox(chr.Position, chr.IsFacingLeft)); foreach (MapleCharacter target in targets.Where(x => x.Id != chr.Id)) { effect.ApplyEffect(chr, target); if (wzCharacterSkill.IsBuff) { effect.ApplyBuffEffect(target); } } } } return(true); }