public override SkillResults Complete(MabiCreature creature, MabiSkill skill, MabiPacket packet) { if (creature.Temp.SkillItem1 == null || creature.Temp.SkillItem2 == null) return SkillResults.Failure; var part = packet.GetInt(); if (packet.GetElementType() == ElementType.Short) return this.CompleteRegular(creature, packet, skill.Id, part); else if (packet.GetElementType() == ElementType.Byte) return this.CompleteFixed(creature, packet, skill.Id, part); return SkillResults.Failure; }
public override SkillResults Use(MabiCreature attacker, MabiSkill skill, MabiPacket packet) { //Logger.Debug(packet); var targetId = packet.GetLong(); var unk1 = packet.GetInt(); var unk2 = packet.GetInt(); // Determine range, doesn't seem to be included in rank info. var range = this.GetRange(skill); // Add attack range from race, range must increase depending on "size". range += (uint)attacker.RaceInfo.AttackRange; var enemies = WorldManager.Instance.GetAttackableCreaturesInRange(attacker, range); if (enemies.Count < 1) { Send.Notice(attacker.Client, Localization.Get("skills.wm_no_target")); // Unable to use when there is no target. Send.SkillSilentCancel(attacker.Client, attacker); return SkillResults.OutOfRange | SkillResults.Failure; } var rnd = RandomProvider.Get(); attacker.StopMove(); // Spin motion Send.UseMotion(attacker, 8, 4); var cap = new CombatActionPack(attacker, skill.Id); // One source action, target actions are added for every target // and then we send the pack on its way. var sAction = new AttackerAction(CombatActionType.Hit, attacker, skill.Id, targetId); sAction.Options |= AttackerOptions.Result | AttackerOptions.KnockBackHit1; cap.Add(sAction); attacker.Stun = sAction.StunTime = 2500; // For aggro selection, only one enemy gets it. MabiCreature aggroTarget = null; var survived = new List<MabiCreature>(); foreach (var target in enemies) { target.StopMove(); var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Id); cap.Add(tAction); var damage = attacker.GetRndTotalDamage(); damage *= skill.RankInfo.Var1 / 100; if (CombatHelper.TryAddCritical(attacker, ref damage, attacker.CriticalChance)) tAction.Options |= TargetOptions.Critical; target.TakeDamage(tAction.Damage = damage); if (target.IsDead) tAction.Options |= TargetOptions.FinishingKnockDown; tAction.Options |= TargetOptions.KnockDown; target.Stun = tAction.StunTime = CombatHelper.GetStunTarget(CombatHelper.GetAverageAttackSpeed(attacker), true); tAction.OldPosition = CombatHelper.KnockBack(target, attacker, 375); tAction.Delay = (uint)rnd.Next(300, 351); if (target.Target == attacker) aggroTarget = target; if (!target.IsDead) survived.Add(target); } // No aggro yet, random target. if (aggroTarget == null && survived.Count > 0) aggroTarget = survived[rnd.Next(0, survived.Count)]; if (aggroTarget != null) CombatHelper.SetAggro(attacker, aggroTarget); WorldManager.Instance.HandleCombatActionPack(cap); Send.SkillUse(attacker.Client, attacker, skill.Id, targetId, unk1, unk2); //attacker.Client.SendSkillStackUpdate(attacker, skill.Id, 0); SkillHelper.DecStack(attacker, skill); SkillHelper.GiveSkillExp(attacker, skill, 20); return SkillResults.Okay; }
public override SkillResults Use(MabiCreature attacker, MabiSkill skill, MabiPacket packet) { var targetId = packet.GetLong(); var unk1 = packet.GetInt(); var unk2 = packet.GetInt(); var target = WorldManager.Instance.GetCreatureById(targetId); if (target == null) return SkillResults.InvalidTarget; //if (!WorldManager.InRange(creature, target, Range)) // return SkillResults.OutOfRange; // X% of Stamina var staminaCost = attacker.Stamina * (skill.RankInfo.Var2 / 100f); if (attacker is MabiPC) attacker.Stamina -= staminaCost; target.StopMove(); var clones = (uint)skill.RankInfo.Var1; attacker.SoulCount = 0; // Spawn clones var pos = target.GetPosition(); WorldManager.Instance.Broadcast( new MabiPacket(Op.Effect, attacker.Id) .PutInt(Effect.ShadowBunshin) .PutByte(3) .PutString("appear") .PutLong(target.Id) .PutInt(clones) .PutInt(Radius) .PutInt(450) // no changes? .PutFloat(pos.X) .PutFloat(pos.Y) , SendTargets.Range, target); // Change char look direction. WorldManager.Instance.Broadcast(PacketCreator.TurnTo(attacker, target), SendTargets.Range, attacker); // Jump to clone circle var toPos = WorldManager.CalculatePosOnLine(attacker, target, -(int)Radius); attacker.SetPosition(toPos.X, toPos.Y); WorldManager.Instance.Broadcast( new MabiPacket(Op.SetLocation, attacker.Id) .PutByte(0) .PutInt(toPos.X) .PutInt(toPos.Y) , SendTargets.Range, attacker); bool alreadyDead = false; uint i = 0; Timer timer = null; timer = new Timer(_ => { if (timer == null || i > clones) return; // Move WorldManager.Instance.Broadcast( new MabiPacket(Op.Effect, attacker.Id) .PutInt(Effect.ShadowBunshin) .PutByte(3) .PutString("move") .PutLong(target.Id) .PutInt(i) // clone nr .PutInt(i) // clone nr .PutInt(450) .PutInt(clones) // ? (4) .PutInt(120) // disappear time? , SendTargets.Range, attacker); // Attack WorldManager.Instance.Broadcast( new MabiPacket(Op.EffectDelayed, attacker.Id) .PutInt(120) // delay? .PutInt(Effect.ShadowBunshin) .PutByte(3) .PutString("attack") .PutInt(i) // clone nr , SendTargets.Range, attacker); var sAction = new AttackerAction(CombatActionType.SpecialHit, attacker, skill.Id, targetId); sAction.Options |= AttackerOptions.Result; var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Id); tAction.Delay = 100; var cap = new CombatActionPack(attacker, skill.Id); cap.Add(sAction); target.Stun = tAction.StunTime = 2000; CombatHelper.SetAggro(attacker, target); var rnd = RandomProvider.Get(); float damage = rnd.Next((int)skill.RankInfo.Var5, (int)skill.RankInfo.Var6 + 1); damage += skill.RankInfo.Var7 * staminaCost; // Crit if (CombatHelper.TryAddCritical(attacker, ref damage, attacker.CriticalChanceAgainst(target))) tAction.Options |= TargetOptions.Critical; // Def/Prot CombatHelper.ReduceDamage(ref damage, target.DefenseTotal, target.Protection); // Mana Shield tAction.ManaDamage = CombatHelper.DealManaDamage(target, ref damage); // Deal Life Damage if (damage > 0) target.TakeDamage(tAction.Damage = damage); // Save if target was already dead, to not send // finish action twice. if (!alreadyDead) { target.TakeDamage(tAction.Damage); // Only send damage taking part if target isn't dead yet. cap.Add(tAction); } alreadyDead = target.IsDead; if (target.IsDead) { tAction.OldPosition = pos; if (!alreadyDead) tAction.Options |= TargetOptions.FinishingKnockDown; else tAction.Options |= TargetOptions.KnockDown; } else if (i == clones) { // Knock back if not dead after last attack. tAction.Options |= TargetOptions.KnockDown; tAction.OldPosition = CombatHelper.KnockBack(target, attacker, 400); } WorldManager.Instance.HandleCombatActionPack(cap); if (i >= clones) { // Cancel timer after last attack. timer.Dispose(); timer = null; } i++; GC.KeepAlive(timer); }, null, 900, 450); // Something's messed up here, if the skill isn't explicitly // canceled the client gets confused. //WorldManager.Instance.CreatureSkillCancel(attacker); SkillHelper.GiveSkillExp(attacker, skill, 20); Send.SkillUse(attacker.Client, attacker, skill.Id, targetId, unk1, unk2); return SkillResults.Okay; }
public override SkillResults Use(MabiCreature creature, MabiSkill skill, MabiPacket packet) { if (creature.Temp.SkillItem1 == null || creature.Temp.SkillItem2 == null) return SkillResults.Failure; var part = packet.GetInt(); // Regular if (packet.GetElementType() == ElementType.Short) { var x = packet.GetShort(); var y = packet.GetShort(); Send.SkillUseDye(creature.Client, creature, skill.Id, part, x, y); } // Fixed else if (packet.GetElementType() == ElementType.Byte) { var unk = packet.GetByte(); Send.SkillUseDye(creature.Client, creature, skill.Id, part, unk); } return SkillResults.Okay; }
public void LoadFromPacket(MabiPacket packet) { Type = packet.GetInt(); Name = packet.GetString(); Level = (Type == 1) ? packet.GetString() : ""; Info = (Type == 1) ? packet.GetString() : ""; Password = packet.GetString(); MaxSize = packet.GetInt(); // TODO: PartyBoard Support /* PartyBoard = packet.GetByte(); 005 [..............01] Byte : 1 006 [0000000000000000] Long : 0 007 [0000000400000000] Long : 17179869184 008 [................] String : 009 [..............46] Byte : 70 010 [..............00] Byte : 0 011 [..............00] Byte : 0 012 [................] String : 013 [................] String : Unrestricted 014 [................] String : Unrestricted 015 [................] String : 016 [............0000] Short : 0 017 [........00000000] Int : 0 018 [........00000000] Int : 0 019 [........00000000] Int : 0 020 [..............01] Byte : 1 */ }