public void Complete(Creature creature, Skill skill, Packet packet) { var itemEntityId = packet.GetLong(); var hwEntityId = packet.GetLong(); var item = creature.Inventory.GetItemSafe(itemEntityId); var hw = creature.Inventory.GetItemSafe(hwEntityId); var blessable = (item.HasTag("/equip/") && !item.HasTag("/not_bless/")); var isHolyWater = (hw.Info.Id == 63016); // There's only one item using this skill. // TODO: Check loading time if (blessable && isHolyWater) { creature.Inventory.Decrement(hw, 1); item.OptionInfo.Flags |= ItemFlags.Blessed; } else Log.Warning("Blessing.Complete: Invalid item or Holy Water."); Send.ItemBlessed(creature, item); Send.UseMotion(creature, 14, 0); Send.SkillComplete(creature, skill.Info.Id, itemEntityId, hwEntityId); }
public bool Prepare(Creature creature, Skill skill, Packet packet) { var itemEntityId = packet.GetLong(); var hwEntityId = packet.GetLong(); // Beware, the client uses the entity ids you send back for the // Complete packet. If you switch them around the handler would // bless the HW and delete the item without security checks. Send.SkillUse(creature, skill.Info.Id, itemEntityId, hwEntityId); return true; }
/// <summary> /// Prepares skill, skips right to used. /// </summary> /// <remarks> /// Doesn't check anything, like what you can gather with what, /// because at this point there's no chance for abuse. /// </remarks> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> /// <returns></returns> public bool Prepare(Creature creature, Skill skill, Packet packet) { var entityId = packet.GetLong(); var collectId = packet.GetInt(); // You shall stop creature.StopMove(); var creaturePosition = creature.GetPosition(); // Get target (either prop or creature) var targetEntity = this.GetTargetEntity(creature.Region, entityId); if (targetEntity != null) creature.Temp.GatheringTargetPosition = targetEntity.GetPosition(); // Check distance if (!creaturePosition.InRange(creature.Temp.GatheringTargetPosition, MaxDistance)) { Send.Notice(creature, Localization.Get("Your arms are too short to reach that from here.")); return false; } // ? (sets creatures position on the client side) Send.CollectAnimation(creature, entityId, collectId, creaturePosition); // Use Send.SkillUse(creature, skill.Info.Id, entityId, collectId); skill.State = SkillState.Used; return true; }
public void Prepare(Creature creature, Skill skill, Packet packet) { var itemEntityId = packet.GetLong(); var dyeEntityId = packet.GetLong(); var item = creature.Inventory.GetItem(itemEntityId); var dye = creature.Inventory.GetItem(dyeEntityId); if (item == null || dye == null) return; if (!dye.Data.HasTag("/*dye_ampul/")) return; creature.Temp.SkillItem1 = item; creature.Temp.SkillItem2 = dye; creature.Skills.ActiveSkill = skill; Send.SkillReadyDye(creature, skill.Info.Id, itemEntityId, dyeEntityId); }
/// <summary> /// Prepares skill, goes straight to being ready. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public bool Prepare(Creature creature, Skill skill, Packet packet) { var itemEntityId = packet.GetLong(); var dyeEntityId = packet.GetLong(); var item = creature.Inventory.GetItem(itemEntityId); var dye = creature.Inventory.GetItem(dyeEntityId); if (item == null || dye == null) return false; if (!dye.Data.HasTag("/*dye_ampul/")) return false; creature.Temp.SkillItem1 = item; creature.Temp.SkillItem2 = dye; Send.SkillReadyDye(creature, skill.Info.Id, itemEntityId, dyeEntityId); skill.State = SkillState.Ready; return true; }
/// <summary> /// Prepares the skill, called after entering the MML, /// goes straight to Use. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public bool Prepare(Creature creature, Skill skill, Packet packet) { var scrollId = packet.GetLong(); var title = packet.GetString(); var author = packet.GetString(); var mml = packet.GetString(); var song = packet.GetString(); // [180300, NA166 (18.09.2013)] Singing var hidden = packet.GetByte(); // bool, but the meta data is a byte // Get item var item = creature.Inventory.GetItem(scrollId); if (item == null) goto L_Fail; // Get all parts of the MML (Melody, Haromony 1+2) var mmlParts = mml.Split(','); // Check lengths if (mml.Length > MmlMaxLength || song.Length > MmlMaxLength) goto L_Fail; // Total if (mmlParts.Length > 0 && mmlParts[0].Length > skill.RankData.Var1) goto L_Fail; // Melody if (mmlParts.Length > 1 && mmlParts[1].Length > skill.RankData.Var2) goto L_Fail; // Harmony 1 if (mmlParts.Length > 2 && mmlParts[2].Length > skill.RankData.Var3) goto L_Fail; // Harmony 2 // Score level = Musical Knowledge rank var level = SkillRank.Novice; var knowledge = creature.Skills.Get(SkillId.MusicalKnowledge); if (knowledge != null) level = knowledge.Info.Rank; // Update item and send skill complete from Complete creature.Skills.Callback(SkillId.Composing, () => { // Skill training if (skill.Info.Rank == SkillRank.Novice) skill.Train(1); // Try the skill. // Scroll information item.MetaData1.SetString("TITLE", title); item.MetaData1.SetString("AUTHOR", author); item.MetaData1.SetString("SCORE", MabiZip.Compress(mml)); item.MetaData1.SetString("SCSING", MabiZip.Compress(song)); // [180300, NA166 (18.09.2013)] Singing item.MetaData1.SetByte("HIDDEN", hidden); item.MetaData1.SetShort("LEVEL", (short)level); // Update Send.ItemUpdate(creature, item); Send.SkillCompleteEntity(creature, skill.Info.Id, item.EntityId); }); // Finish Send.SkillUseEntity(creature, skill.Info.Id, scrollId); skill.State = SkillState.Used; return true; L_Fail: return false; }
public void Complete(Creature creature, Skill skill, Packet packet) { var itemEntityId = packet.GetLong(); var hwEntityId = packet.GetLong(); var item = creature.Inventory.GetItemSafe(itemEntityId); var hw = creature.Inventory.GetItemSafe(hwEntityId); var isHolyWater = (hw.Info.Id == 63016); // There's only one item using this skill. // TODO: Check loading time if (item.IsBlessable && isHolyWater) { creature.Inventory.Decrement(hw, 1); creature.Bless(item); } else Log.Warning("Blessing.Complete: Invalid item or Holy Water."); Send.UseMotion(creature, 14, 0); Send.SkillComplete(creature, skill.Info.Id, itemEntityId, hwEntityId); }
public void Use(Creature creature, Skill skill, Packet packet) { var targetPos = new Position(packet.GetLong()); // Check distance to target position if (!creature.GetPosition().InRange(targetPos, (int)skill.RankData.Var2 + DistanceBuffer)) { Send.Notice(creature, Localization.Get("Out of range.")); Send.SkillUse(creature, skill.Info.Id, 0); return; } // Stop creature's movement. creature.StopMove(); // Teleport effect (does not actually teleport) Send.Effect(creature, Effect.SilentMoveTeleport, (byte)2, targetPos.X, targetPos.Y); // Teleport player to target position creature.SetPosition(targetPos.X, targetPos.Y); Send.SkillTeleport(creature, targetPos.X, targetPos.Y); Send.SkillUse(creature, skill.Info.Id, 1); }
/// <summary> /// Handles skill usage. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { var targetAreaEntityId = packet.GetLong(); Send.Effect(attacker, 5, (byte)1, targetAreaEntityId); var cap = new CombatActionPack(attacker, skill.Info.Id); var aAction = new AttackerAction(CombatActionType.Attacker, attacker, skill.Info.Id, targetAreaEntityId); aAction.Options |= AttackerOptions.Result; aAction.Stun = UseStun; cap.Add(aAction); var attackerPosition = attacker.GetPosition(); // Calculate rectangular target area var targetAreaPos = new Position(targetAreaEntityId); var poe = targetAreaPos.GetRelative(attackerPosition, -800); var r = (Math.PI / 2) + Math.Atan2(attackerPosition.Y - targetAreaPos.Y, attackerPosition.X - targetAreaPos.X); var pivot = new Point(poe.X, poe.Y); var p1 = new Point(pivot.X - LaserRectWidth / 2, pivot.Y - LaserRectHeight / 2); var p2 = new Point(pivot.X - LaserRectWidth / 2, pivot.Y + LaserRectHeight / 2); var p3 = new Point(pivot.X + LaserRectWidth / 2, pivot.Y + LaserRectHeight / 2); var p4 = new Point(pivot.X + LaserRectWidth / 2, pivot.Y - LaserRectHeight / 2); p1 = this.RotatePoint(p1, pivot, r); p2 = this.RotatePoint(p2, pivot, r); p3 = this.RotatePoint(p3, pivot, r); p4 = this.RotatePoint(p4, pivot, r); // Attack targets var targets = attacker.Region.GetCreaturesInPolygon(p1, p2, p3, p4); foreach (var target in targets.Where(cr => !cr.IsDead && !cr.Has(CreatureStates.NamedNpc))) { var targetPosition = target.GetPosition(); var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id); tAction.Options = TargetOptions.Result | TargetOptions.KnockDown; tAction.Stun = TargetStun; tAction.Delay = 1200; cap.Add(tAction); // Var2: 300/1000, based on rank. Could be damage? var damage = skill.RankData.Var2; // Increase damage CriticalHit.Handle(attacker, attacker.GetTotalCritChance(target.Protection), ref damage, tAction); // Reduce damage SkillHelper.HandleDefenseProtection(target, ref damage); ManaShield.Handle(target, ref damage, tAction); // Apply damage target.TakeDamage(tAction.Damage = 300, attacker); target.Stability = Creature.MinStability; // Aggro target.Aggro(attacker); // Check death if (target.IsDead) tAction.Options |= TargetOptions.FinishingKnockDown; // Knock back attacker.Shove(target, KnockbackDistance); } cap.Handle(); Send.SkillUse(attacker, skill.Info.Id, 0); }
/// <summary> /// Completes skill, handling the whole item gathering process. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Complete(Creature creature, Skill skill, Packet packet) { var entityId = packet.GetLong(); var collectId = packet.GetInt(); var rnd = RandomProvider.Get(); // Check data var collectData = AuraData.CollectingDb.Find(collectId); if (collectData == null) { Log.Warning("Gathering.Complete: Unknown collect id '{0}'", collectId); this.DoComplete(creature, entityId, collectId, false, 1); return; } // Check tools if (!this.CheckHand(collectData.RightHand, creature.RightHand) || !this.CheckHand(collectData.LeftHand, creature.LeftHand)) { Log.Warning("Gathering.Complete: Collecting using invalid tool.", collectId); this.DoComplete(creature, entityId, collectId, false, 1); return; } // Reduce tool's durability if (creature.RightHand != null && collectData.DurabilityLoss > 0) { var reduce = collectData.DurabilityLoss; // Half dura loss if blessed if (creature.RightHand.IsBlessed) reduce = Math.Max(1, reduce / 2); creature.RightHand.Durability -= reduce; Send.ItemDurabilityUpdate(creature, creature.RightHand); Send.ItemExpUpdate(creature, creature.RightHand); } // Get target (either prop or creature) var targetEntity = this.GetTargetEntity(creature.Region, entityId); // Check target if (targetEntity == null || !targetEntity.HasTag(collectData.Target)) { Log.Warning("Gathering.Complete: Collecting from invalid entity '{0:X16}'", entityId); this.DoComplete(creature, entityId, collectId, false, 1); return; } // Check position var creaturePosition = creature.GetPosition(); var targetPosition = targetEntity.GetPosition(); if (!creaturePosition.InRange(targetPosition, MaxDistance)) { Send.Notice(creature, Localization.Get("Your arms are too short to reach that from here.")); this.DoComplete(creature, entityId, collectId, false, 1); return; } // Check if moved if (creature.Temp.GatheringTargetPosition.GetDistance(targetPosition) > MaxMoveDistance) { this.DoComplete(creature, entityId, collectId, false, 3); return; } // Determine success var successChance = this.GetSuccessChance(creature, collectData); var collectSuccess = rnd.NextDouble() * 100 < successChance; // Get reduction var reduction = collectData.ResourceReduction; if (ChannelServer.Instance.Weather.GetWeatherType(creature.RegionId) == WeatherType.Rain) reduction += collectData.ResourceReductionRainBonus; // Check resource if (targetEntity is Prop) { var targetProp = (Prop)targetEntity; // Check if prop was emptied if (targetProp.State == "empty") { this.DoComplete(creature, entityId, collectId, false, 2); return; } // Regenerate resources targetProp.Resource += (float)((DateTime.Now - targetProp.LastCollect).TotalMinutes * collectData.ResourceRecovering); // Fail if currently no resources available if (targetProp.Resource < reduction) { this.DoComplete(creature, entityId, collectId, false, 2); return; } // Reduce resources on success if (collectSuccess) { if (!ChannelServer.Instance.Conf.World.InfiniteResources) targetProp.Resource -= reduction; targetProp.LastCollect = DateTime.Now; } // Set prop's state to "empty" if it was emptied and is not // regenerating resources. if (collectData.ResourceRecovering == 0 && targetProp.Resource < reduction) targetProp.SetState("empty"); } else { var targetCreature = (Creature)targetEntity; // Fail if creature doesn't have enough mana if (targetCreature.Mana < reduction) { this.DoComplete(creature, entityId, collectId, false, 2); return; } if (collectSuccess && !ChannelServer.Instance.Conf.World.InfiniteResources) targetCreature.Mana -= reduction; } // Drop var receiveItemId = 0; if (collectSuccess) { // Product var itemId = receiveItemId = collectData.GetRndProduct(rnd); if (itemId != 0) { var item = new Item(itemId); if (collectData.Source == 0) { // Try to drop item in the middle, between creature // and target. If there already is an item on that // position, find another random one. var pos = targetPosition.GetRelative(creaturePosition, -FeetDropDistance); for (int i = 0; creature.Region.GetItem(a => a.GetPosition() == pos) != null && i < 10; ++i) pos = creaturePosition.GetRandomInRange(DropRange, rnd); item.Drop(creature.Region, pos, 0, creature, false); } else { creature.Inventory.Remove(creature.RightHand); creature.Inventory.Add(item, creature.Inventory.RightHandPocket); } } // Product2 itemId = collectData.GetRndProduct2(rnd); if (itemId != 0) { var item = new Item(itemId); item.Drop(creature.Region, creaturePosition, DropRange, creature, false); } } // TODO: Figure out how fail products work. //else //{ // // FailProduct // var itemId = receiveItemId = collectData.GetRndFailProduct(rnd); // if (itemId != 0) // { // var item = new Item(itemId); // if (collectData.Source == 0) // item.Drop(creature.Region, creaturePosition, DropRange); // else // { // creature.Inventory.Remove(creature.RightHand); // creature.Inventory.Add(item, creature.Inventory.RightHandPocket); // } // } // // FailProduct2 // itemId = collectData.GetRndFailProduct2(rnd); // if (itemId != 0) // { // var item = new Item(itemId); // item.Drop(creature.Region, creaturePosition.GetRandomInRange(DropRange, rnd)); // } //} // Events ChannelServer.Instance.Events.OnCreatureGathered(new CollectEventArgs(creature, collectData, collectSuccess, receiveItemId)); // Complete this.DoComplete(creature, entityId, collectId, collectSuccess, 0); }
/// <summary> /// Uses WM, attacking targets. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { var targetAreaId = packet.GetLong(); // There exists a seemingly rare case where these parameters // aren't sent. var unkInt1 = (packet.Peek() != PacketElementType.None ? packet.GetInt() : 0); var unkInt2 = (packet.Peek() != PacketElementType.None ? packet.GetInt() : 0); this.Use(attacker, skill, targetAreaId, unkInt1, unkInt2); }
/// <summary> /// Handles skill usage. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature creature, Skill skill, Packet packet) { var targetEntityId = packet.GetLong(); // Similar to WM there is a case where these aren't sent. // Apparently this can happen if you activate the skill while // targetting an enemy. var unk1 = (packet.Peek() != PacketElementType.None ? packet.GetInt() : 0); var unk2 = (packet.Peek() != PacketElementType.None ? packet.GetInt() : 0); if (_cm == null) _cm = ChannelServer.Instance.SkillManager.GetHandler<CombatMastery>(SkillId.CombatMastery); // TODO: Check duration var attackResult = false; var target = creature.Region.GetCreature(targetEntityId); if (target != null && !creature.IsStunned && creature.CanTarget(target)) { var pos = creature.GetPosition(); var targetPos = target.GetPosition(); var inRange = pos.InRange(targetPos, creature.AttackRangeFor(target)); if (!inRange) { var telePos = pos.GetRelative(targetPos, -creature.AttackRangeFor(target) + 100); // Check teleport distance if (pos.GetDistance(telePos) > skill.RankData.Var3 + 100) { Send.Notice(creature, "Out of range"); } else { Send.Effect(creature, Effect.SilentMoveTeleport, targetEntityId, (byte)0); creature.SetPosition(telePos.X, telePos.Y); Send.SkillTeleport(creature, telePos.X, telePos.Y); inRange = true; } } if (inRange) attackResult = (_cm.Use(creature, skill, targetEntityId) == CombatSkillResult.Okay); } Send.CombatAttackR(creature, attackResult); Send.SkillUse(creature, skill.Info.Id, targetEntityId, unk1, unk2); }
/// <summary> /// Handles skill usage. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { var targetAreaEntityId = packet.GetLong(); this.Use(attacker, skill, targetAreaEntityId); }
/// <summary> /// Handles skill usage. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature creature, Skill skill, Packet packet) { var targetEntityId = packet.GetLong(); var unk1 = packet.GetInt(); var unk2 = packet.GetInt(); Use(creature, skill, targetEntityId, unk1, unk2); }