/// <summary> /// Duration in milliseconds /// </summary> /// <param name="source"></param> /// <param name="skillId"></param> /// <param name="delay"></param> /// <returns></returns> public static Timer ScheduleRemoveBuff(MapleCharacter source, int skillId, uint delay) { return(Scheduler.ScheduleDelayedAction(new Action(() => { if (source != null && source.Client != null) { source.CancelBuff(skillId); } }), delay)); }
public void Kill(MapleCharacter killer, bool dropItems = true) { lock (MobLock) { //killer.Client.CheatTracker.KillTrigger(this); Alive = false; int exp = WzInfo.Exp * ServerConstants.ExpRate; MapleCharacter dropOwner = killer; int HighestExp = 0; foreach (KeyValuePair <int, long> kvp in AttackerDamageList) { MapleCharacter attacker = Map.GetCharacter(kvp.Key); if (attacker != null) { double expPercent = ((double)Math.Min(kvp.Value, WzInfo.HP) / (double)WzInfo.HP); int expToGive = (int)((expPercent * exp) * (attacker.Stats.ExpR / 100.0)); //Drops go to the person who did the most damage if (expToGive > HighestExp) { HighestExp = expToGive; dropOwner = attacker; } attacker.GainExp(expToGive, true, true); } } if (dropItems) { Map.SpawnMapItemsFromMonster(this, this.Position, dropOwner); } dropOwner.UpdateQuestKills(WzInfo.MobId); //TODO: whole party on map Map.BroadcastPacket(MapleMonster.KillMob(ObjectId)); Map.RemoveMob(ObjectId); #region Final Pact if (dropOwner.Job == JobConstants.DARKKNIGHT) { Buff buff = dropOwner.GetBuff(DarkKnight.FINAL_PACT2); if (buff != null) { buff.Stacks--; if (buff.Stacks <= 0) { dropOwner.Client.SendPacket(Skill.ShowBuffEffect(DarkKnight.FINAL_PACT2, dropOwner.Level, null, false)); dropOwner.CancelBuff(DarkKnight.FINAL_PACT2); } else { uint remainingTimeMS = buff.Duration - (uint)DateTime.UtcNow.Subtract(buff.StartTime).TotalMilliseconds; dropOwner.Client.SendPacket(Buff.UpdateFinalPactKillCount(buff.Stacks, remainingTimeMS)); } } } #endregion Map = null; foreach (MonsterBuff effect in Buffs) { effect.Dispose(true); } } }
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 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); }