/// <summary> /// Handles part of the skill training. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> private void OnPlayerUsesItem(Creature creature, Item item) { // Get skill var skill = creature.Skills.Get(SkillId.Cooking); if (skill == null) return; // Check if item is food if (!item.HasTag("/food/")) return; // Get quality and method var method = item.MetaData1.GetString("MKACT"); if (method == null) return; var quality = item.MetaData1.GetInt("QUAL"); var rating = this.GetRating(quality); var isDelicious = (rating >= DeliciousRating); if (skill.Info.Rank == SkillRank.RF) { if (method == CookingMethod.Simmering) skill.Train(3); // Eat a simmered dish without sharing. else if (method == CookingMethod.Baking) { if (isDelicious) skill.Train(4); // Eat a deliciously baked dish. } return; } if (skill.Info.Rank == SkillRank.RE) { if (method == CookingMethod.Simmering) { if (isDelicious) skill.Train(3); // Eat a deliciously simmered dish. } return; } if (skill.Info.Rank == SkillRank.RD) { if (method == CookingMethod.Boiling) skill.Train(3); // Eat a boiled dish without sharing. else if (method == CookingMethod.Simmering) { if (isDelicious) skill.Train(4); // Eat a deliciously simmered dish. } return; } if (skill.Info.Rank == SkillRank.RC) { if (method == CookingMethod.Boiling) { if (isDelicious) skill.Train(3); // Eat a deliciously boiled dish. } return; } if (skill.Info.Rank == SkillRank.RB) { if (method == CookingMethod.DeepFrying) skill.Train(3); // Eat a deep-fried dish without sharing. else if (method == CookingMethod.Boiling) { if (isDelicious) skill.Train(4); // Eat a deliciously boiled dish. } return; } if (skill.Info.Rank == SkillRank.RA) { if (method == CookingMethod.StirFrying) skill.Train(3); // Eat a stir-fried dish without sharing. else if (method == CookingMethod.DeepFrying) { if (isDelicious) skill.Train(4); // Eat a deliciously deep-fried dish. } return; } if (skill.Info.Rank >= SkillRank.R9 && skill.Info.Rank <= SkillRank.R7) { if (method == CookingMethod.StirFrying) { if (isDelicious) skill.Train(3); // Eat a deliciously stir-fried dish. } return; } // TODO: Jam and pies don't have jam and pie tags, // how to identify them for the last two ranks // without hard-coded ids? if (skill.Info.Rank == SkillRank.R6) { //if (item.HasTag("/jam/")) // skill.Train(3); // Eat Jam return; } if (skill.Info.Rank == SkillRank.R5) { //if (item.HasTag("/pie/")) // skill.Train(3); // Eat a Pie return; } }
/// <summary> /// Unequips item in left hand/magazine, if item in right hand is moved. /// </summary> /// <param name="item"></param> /// <param name="source"></param> /// <param name="target"></param> private void CheckLeftHand(Item item, Pocket source, Pocket target) { var pocketOfInterest = Pocket.None; if (source == Pocket.RightHand1 || source == Pocket.RightHand2) pocketOfInterest = source; if (target == Pocket.RightHand1 || target == Pocket.RightHand2) pocketOfInterest = target; if (pocketOfInterest == Pocket.None) return; // Check LeftHand first, switch to Magazine if it's empty var leftPocket = pocketOfInterest + 2; // Left Hand 1/2 var leftItem = _pockets[leftPocket].GetItemAt(0, 0); if (leftItem == null) { leftPocket += 2; // Magazine 1/2 leftItem = _pockets[leftPocket].GetItemAt(0, 0); // Nothing to remove if (leftItem == null) return; } // Don't remove if combination is valid, this should allow weapons // to be switched while having a shield equipped. // Combinations of righthand/lefthand are (always?) valid, // unless it involves bows and their ammunition. if (item.HasTag("/righthand/") && leftItem.HasTag("/lefthand/")) { if (!item.HasTag("/bow/|/crossbow/") && !leftItem.HasTag("/arrow/|/bolt/")) return; } // Try inventory first. // TODO: List of pockets stuff can be auto-moved to. var success = _pockets[Pocket.Inventory].Add(leftItem); // Fallback, temp inv if (!success) success = _pockets[Pocket.Temporary].Add(leftItem); if (success) { _pockets[leftPocket].Remove(leftItem); Send.ItemMoveInfo(_creature, leftItem, leftPocket, null); Send.EquipmentMoved(_creature, leftPocket); } }
public override bool TryAdd(Item newItem, byte targetX, byte targetY, out Item collidingItem) { collidingItem = null; if (targetX + newItem.Data.Width > _width || targetY + newItem.Data.Height > _height) return false; var collidingItems = this.GetCollidingItems(targetX, targetY, newItem); if (collidingItems.Count > 1) return false; if (collidingItems.Count > 0) collidingItem = collidingItems[0]; if (collidingItem != null && ( // Colliding item is sac and new item can fill be put into it (collidingItem.Data.StackType == StackType.Sac && collidingItem.Data.StackItemId != 0 && (collidingItem.Data.StackItemId == newItem.Info.Id || collidingItem.Data.StackItemId == newItem.Data.StackItemId)) || // Colliding item is a quiver (general arrow sac) that // a regular arrow can be put into. // Corner case, due to quiver being a sac without stack item id, // instead of a stackable for some reason. They possibly wanted // to be able to put different kinds of arrows into it, // otherwise they probably would have made it stackable or // specified a stack item id. (collidingItem.HasTag("/largearrowsac/") && newItem.HasTag("/arrow_bag_bundle/")) || // Item is stackable and can be put into the colliding stack (newItem.Data.StackType == StackType.Stackable && newItem.Info.Id == collidingItem.Info.Id)) ) { if (collidingItem.Info.Amount < collidingItem.Data.StackMax) { var diff = (ushort)(collidingItem.Data.StackMax - collidingItem.Info.Amount); var amount = collidingItem.Info.Amount; collidingItem.Info.Amount += Math.Min(diff, newItem.Info.Amount); newItem.Info.Amount -= Math.Min(diff, newItem.Info.Amount); if (amount != collidingItem.Info.Amount) return true; } } if (collidingItem != null) { _items.Remove(collidingItem.EntityId); collidingItem.Move(newItem.Info.Pocket, newItem.Info.X, newItem.Info.Y); this.ClearFromMap(collidingItem); } _items.Add(newItem.EntityId, newItem); newItem.Move(this.Pocket, targetX, targetY); this.AddToMap(newItem); return true; }
/// <summary> /// Drops creature's drop items. /// </summary> /// <param name="killer"></param> /// <param name="rnd"></param> /// <param name="pos"></param> private void DropItems(Creature killer, Random rnd, Position pos) { // Normal var dropped = new HashSet<int>(); foreach (var dropData in this.Drops.Drops) { if (dropData == null || !AuraData.ItemDb.Exists(dropData.ItemId)) { Log.Warning("Creature.Kill: Invalid drop '{0}' from '{1}'.", (dropData == null ? "null" : dropData.ItemId.ToString()), this.RaceId); continue; } var dropRate = dropData.Chance * ChannelServer.Instance.Conf.World.DropRate; var dropChance = rnd.NextDouble() * 100; var month = ErinnTime.Now.Month; // Tuesday: Increase in dungeon item drop rate. // Wednesday: Increase in item drop rate from animals and nature. // +50%, bonus is unofficial. if ((month == ErinnMonth.Baltane && this.Region.IsDungeon) || (month == ErinnMonth.AlbanHeruin && !this.Region.IsDungeon)) dropRate *= 1.5f; if (dropChance < dropRate) { // Only drop any item once if (dropped.Contains(dropData.ItemId)) continue; var item = new Item(dropData); // Equip stat modification // http://wiki.mabinogiworld.com/view/Category:Weapons if (item.HasTag("/righthand/weapon/|/twohand/weapon/")) { var num = rnd.Next(100); // Durability if (num == 0) item.OptionInfo.DurabilityMax += 4000; else if (num <= 5) item.OptionInfo.DurabilityMax += 3000; else if (num <= 10) item.OptionInfo.DurabilityMax += 2000; else if (num <= 25) item.OptionInfo.DurabilityMax += 1000; // Attack if (num == 0) { item.OptionInfo.AttackMin += 3; item.OptionInfo.AttackMax += 3; } else if (num <= 30) { item.OptionInfo.AttackMin += 2; item.OptionInfo.AttackMax += 2; } else if (num <= 60) { item.OptionInfo.AttackMin += 1; item.OptionInfo.AttackMax += 1; } // Crit if (num == 0) item.OptionInfo.Critical += 3; else if (num <= 30) item.OptionInfo.Critical += 2; else if (num <= 60) item.OptionInfo.Critical += 1; // Balance if (num == 0) item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 12); else if (num <= 10) item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 10); else if (num <= 30) item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 8); else if (num <= 50) item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 6); else if (num <= 70) item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 4); else if (num <= 90) item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 2); } item.Drop(this.Region, pos, Item.DropRadius, killer, false); dropped.Add(dropData.ItemId); } } // Static foreach (var item in this.Drops.StaticDrops) item.Drop(this.Region, pos, Item.DropRadius, killer, false); this.Drops.ClearStaticDrops(); }
/// <summary> /// Called once ready to pull the fish out. /// </summary> /// <remarks> /// When you catch something just before running out of bait, /// and you send MotionCancel2 from Cancel, there's a /// visual bug on Aura, where the item keeps flying to you until /// you move. This does not happen on NA for unknown reason. /// The workaround: Check for cancellation in advance and only /// send the real in effect if the skill wasn't canceled. /// </remarks> /// <param name="creature"></param> /// <param name="method">Method used on this try</param> /// <param name="success">Success of manual try</param> public void OnResponse(Creature creature, FishingMethod method, bool success) { // Get skill var skill = creature.Skills.Get(SkillId.Fishing); if (skill == null) { Log.Error("Fishing.OnResponse: Missing skill."); return; } var rnd = RandomProvider.Get(); // Update prop state // TODO: update prop state method creature.Temp.FishingProp.SetState("empty"); // Get auto success if (method == FishingMethod.Auto) success = rnd.NextDouble() < skill.RankData.Var3 / 100f; // Perfect fishing if (ChannelServer.Instance.Conf.World.PerfectFishing) success = true; // Check fishing ground if (creature.Temp.FishingDrop == null) { Send.ServerMessage(creature, "Error: No items found."); Log.Error("Fishing.OnResponse: Failing, no drop found."); success = false; } // Check equipment if (!this.CheckEquipment(creature)) { Send.ServerMessage(creature, "Error: Missing equipment."); Log.Error("Fishing.OnResponse: Failing, Missing equipment."); // TODO: Security violation once we're sure this can't happen // without modding. success = false; } var cancel = false; // Reduce durability if (creature.RightHand != null && !ChannelServer.Instance.Conf.World.NoDurabilityLoss) { var reduce = 15; // Half dura loss if blessed if (creature.RightHand.IsBlessed) reduce = Math.Max(1, reduce / 2); creature.RightHand.Durability -= reduce; Send.ItemDurabilityUpdate(creature, creature.RightHand); // Check rod durability if (creature.RightHand.Durability == 0) cancel = true; } // Remove bait if (creature.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteBait) { creature.Inventory.Decrement(creature.Magazine); // Check if bait was removed because it was empty if (creature.Magazine == null) cancel = true; } // Fail Item item = null; if (!success) { Send.Notice(creature, Localization.Get("I was hesistating for a bit, and it got away...")); // More responses? Send.Effect(creature, Effect.Fishing, (byte)FishingEffectType.Fall, true); } // Success else { var propName = "prop_caught_objbox_01"; var propSize = 0; var size = 0; // Create item item = new Item(creature.Temp.FishingDrop); // Check fish var fish = AuraData.FishDb.Find(creature.Temp.FishingDrop.ItemId); if (fish != null) { propName = fish.PropName; propSize = fish.PropSize; // Random fish size, unofficial if (fish.SizeMin + fish.SizeMax != 0) { var min = fish.SizeMin + (int)Math.Max(0, (item.Data.BaseSize - fish.SizeMin) / 100f * skill.RankData.Var4); var max = fish.SizeMax; size = Math2.Clamp(fish.SizeMin, fish.SizeMax, rnd.Next(min, max + 1) + (int)skill.RankData.Var1); var scale = (1f / item.Data.BaseSize * size); item.MetaData1.SetFloat("SCALE", scale); } } // Set equipment durability if (item.HasTag("/equip/") && item.OptionInfo.DurabilityMax >= 1) item.Durability = 0; // Drop if inv add failed List<Item> changed; if (!creature.Inventory.Insert(item, false, out changed)) item.Drop(creature.Region, creature.GetPosition().GetRandomInRange(100, rnd)); var itemEntityId = (changed == null || changed.Count == 0 ? item.EntityId : changed.First().EntityId); // Show acquire using the item's entity id if it wasn't added // to a stack, or using the stack's id if it was. Send.AcquireInfo2(creature, "fishing", itemEntityId); // Holding up fish effect if (!cancel) Send.Effect(creature, Effect.Fishing, (byte)FishingEffectType.ReelIn, true, creature.Temp.FishingProp.EntityId, item.Info.Id, size, propName, propSize); } creature.Temp.FishingDrop = null; // Handle training this.Training(creature, skill, success, item); // Cancel if (cancel) { creature.Skills.CancelActiveSkill(); return; } // Next round this.StartFishing(creature, 6000); }
/// <summary> /// Called when player uses an item. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> private void OnPlayerUsesItem(Creature creature, Item item) { var userSkill = creature.Skills.Get(SkillId.Healing); if (userSkill != null && userSkill.Info.Rank >= SkillRank.RF && userSkill.Info.Rank <= SkillRank.RE && item.HasTag("/potion/hp/")) userSkill.Train(5); // Drink a Life Potion. }
/// <summary> /// Handles skill training. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="success"></param> /// <param name="item"></param> /// <exception cref="ArgumentException"></exception> public void Training(Creature creature, Skill skill, bool success, Item item) { if (success && item == null) throw new ArgumentException("Item shouldn't be null if fishing was successful."); if (skill.Info.Rank == SkillRank.Novice) { skill.Train(2); // Attempt to fish. if (success && item.HasTag("/fish/")) skill.Train(1); // Catch a fish. if (!success) skill.Train(3); // Fail at fishing. return; } if (skill.Info.Rank >= SkillRank.RF && skill.Info.Rank <= SkillRank.R1) { if (success) { if (item.HasTag("/fish/")) skill.Train(1); // Catch a fish. else if (item.QuestId != 0) skill.Train(2); // Catch a quest scroll. else skill.Train(3); // Catch an item. } if (skill.Info.Rank <= SkillRank.RA) skill.Train(4); // Attempt to fish. return; } }
private void OnPlayerUsesItem(Creature creature, Item item) { var skill = creature.Skills.Get(SkillId.PotionMaking); if (skill == null) return; if (skill.Info.Rank >= SkillRank.RF && skill.Info.Rank <= SkillRank.RE) { if (item.HasTag("/potion/hp/")) skill.Train(1); // Drink an HP Potion. else if (item.HasTag("/potion/mana/")) skill.Train(2); // Drink an MP Potion. else if (item.HasTag("/potion/stamina/")) skill.Train(3); // Drink a Stamina Potion. return; } if (skill.Info.Rank == SkillRank.RB) { if (item.HasTag("/potion/wound/")) skill.Train(6); // Try drinking a Wound Remedy Potion. return; } }
/// <summary> /// Returns success chance, based on skill, option set, and powder /// used. /// <remarks> /// Unofficial. It kinda matches the debug output of the client, /// but it is a little off. /// </remarks> /// </summary> /// <param name="creature"></param> /// <param name="rightHand"></param> /// <param name="skill"></param> /// <param name="optionSetData"></param> /// <returns></returns> private float GetChance(Creature creature, Item rightHand, Skill skill, OptionSetData optionSetData) { // Check right hand, only use it if it's powder if (rightHand != null && !rightHand.HasTag("/enchant/powder/")) rightHand = null; // Get base chance, based on skill and powder var baseChance = _baseChanceB00; // (Blessed) Magic Powder/None if (skill.Info.Id == SkillId.Enchant && rightHand != null) { if (rightHand.HasTag("/powder02/")) // Elite Magic Powder baseChance = _baseChanceB05; else if (rightHand.HasTag("/powder03/")) // Elven Magic Powder baseChance = _baseChanceB10; else if (rightHand.HasTag("/powder01/")) // Ancient Magic Powder baseChance = _baseChanceB50; else if (rightHand.HasTag("/powder04/") && rightHand.Info.Id == 85865) // Notorious Magic Powder baseChance = _baseChanceB60; } // Get chance var rank = Math2.Clamp(0, _baseChanceB00.Length - 1, (int)optionSetData.Rank - 1); var chance = baseChance[rank]; var intBonus = 1f; var thursdayBonus = 0f; // Int bonus if using powder if (skill.Info.Id == SkillId.Enchant && rightHand != null) intBonus = 1f + ((creature.Int - 35f) / 350f); // Thursday bonus if (ErinnTime.Now.Month == 4) thursdayBonus = Math.Max(0, (15 - rank) / 2f); // Result var result = Math2.Clamp(0, 90, chance * intBonus + thursdayBonus); // Debug if (creature.Titles.SelectedTitle == TitleId.devCAT) { Send.ServerMessage(creature, "Debug: Enchant success chance: {0:0} (base: {1:0}, int: {2:0}, thu: {3:0})", result, chance, (chance / 1f * (intBonus - 1f)), thursdayBonus); } return result; }
/// <summary> /// /// </summary> /// <param name="creature"></param> /// <param name="itemEntityId"></param> /// <param name="moveToInventory"></param> /// <param name="directBankTransaction"></param> /// <returns></returns> public bool Buy(Creature creature, long itemEntityId, bool moveToInventory, bool directBankTransaction) { var shop = this; var owner = creature.Temp.CurrentShopOwner; // Get item // In theory someone could buy an item without it being visible // to him, but he would need the current entity id that // changes on each restart. It's unlikely to ever be a problem. var item = shop.GetItem(itemEntityId); if (item == null) { // Don't warn, this might happen when items are moved while // a player has the shop open. Send.MsgBox(creature, Localization.Get("The item is not available.")); return false; } // Check stock if (item.Stock == 0) { Send.MsgBox(creature, Localization.Get("This item is not in stock anymore.")); return false; } // Determine which payment method to use, the same way the client // does to display them. Points > Stars > Ducats > Gold. var paymentMethod = PaymentMethod.Gold; if (item.OptionInfo.StarPrice > 0) paymentMethod = PaymentMethod.Stars; if (item.OptionInfo.DucatPrice > 0) paymentMethod = PaymentMethod.Ducats; if (item.OptionInfo.PointPrice > 0) paymentMethod = PaymentMethod.Points; // Allow direct transaction only for buying with gold if (directBankTransaction && paymentMethod != PaymentMethod.Gold) { Send.MsgBox(creature, Localization.Get("You can't by this item via direct bank transaction.")); return false; } // Get buying price var price = int.MaxValue; switch (paymentMethod) { case PaymentMethod.Gold: price = item.OptionInfo.Price; break; case PaymentMethod.Stars: price = item.OptionInfo.StarPrice; break; case PaymentMethod.Ducats: price = item.OptionInfo.DucatPrice; break; case PaymentMethod.Points: price = item.OptionInfo.PointPrice; break; } // The client expects the price for a full stack to be sent in the // ItemOptionInfo, so we have to calculate the actual price here. // However, the points payment method prices are absolute, the // client displays them as is. if (item.Data.StackType == StackType.Stackable && paymentMethod != PaymentMethod.Points) price = (int)(price / (float)item.Data.StackMax * item.Amount); // Wednesday: Decrease in prices (5%) for items in NPC shops, // including Remote Shop Coupons and money deposit for Exploration Quests. if (ErinnTime.Now.Month == ErinnMonth.AlbanHeruin) price = (int)(price * 0.95f); // Check currency var canPay = false; switch (paymentMethod) { case PaymentMethod.Gold: // Disable direct bank transaction if price is less than 50k if (directBankTransaction && price < 50000) directBankTransaction = false; // Check gold var gold = 0; if (directBankTransaction) { gold = creature.Client.Account.Bank.Gold; price = price + (int)(price * 0.05f); // Fee } else gold = creature.Inventory.Gold; canPay = (gold >= price); break; case PaymentMethod.Stars: canPay = (creature.Inventory.Stars >= price); break; case PaymentMethod.Ducats: canPay = false; break; // TODO: Implement ducats. case PaymentMethod.Points: canPay = (creature.Points >= price); break; } if (!canPay) { switch (paymentMethod) { case PaymentMethod.Gold: Send.MsgBox(creature, Localization.Get("Insufficient amount of gold.")); break; case PaymentMethod.Stars: Send.MsgBox(creature, Localization.Get("Insufficient amount of stars.")); break; case PaymentMethod.Ducats: Send.MsgBox(creature, Localization.Get("Insufficient amount of ducats.")); break; case PaymentMethod.Points: Send.MsgBox(creature, Localization.Get("You don't have enough Pon.\nYou will need to buy more.")); break; } return false; } // Buy, adding item, and removing currency var success = false; var newItem = new Item(item); // Set guild data if (newItem.HasTag("/guild_robe/") && creature.Guild != null && creature.Guild.HasRobe) { // EBCL1:4:-11042446;EBCL2:4:-7965756;EBLM1:1:45;EBLM2:1:24;EBLM3:1:6;GLDNAM:s:Name; newItem.Info.Color1 = creature.Guild.Robe.RobeColor; newItem.Info.Color2 = GuildRobe.GetColor(creature.Guild.Robe.BadgeColor); newItem.Info.Color3 = GuildRobe.GetColor(creature.Guild.Robe.EmblemMarkColor); newItem.MetaData1.SetInt("EBCL1", (int)GuildRobe.GetColor(creature.Guild.Robe.EmblemOutlineColor)); newItem.MetaData1.SetInt("EBCL2", (int)GuildRobe.GetColor(creature.Guild.Robe.StripesColor)); newItem.MetaData1.SetByte("EBLM1", creature.Guild.Robe.EmblemMark); newItem.MetaData1.SetByte("EBLM2", creature.Guild.Robe.EmblemOutline); newItem.MetaData1.SetByte("EBLM3", creature.Guild.Robe.Stripes); newItem.MetaData1.SetString("GLDNAM", creature.Guild.Name); } // Cursor if (!moveToInventory) success = creature.Inventory.Add(newItem, Pocket.Cursor); // Inventory else success = creature.Inventory.Add(newItem, false); if (success) { // Reset gold price if payment method wasn't gold, as various // things depend on the gold price, like repair prices. // If any payment method but gold was used, the gold price // would be 0. if (paymentMethod != PaymentMethod.Gold) newItem.ResetGoldPrice(); // Reduce gold/points switch (paymentMethod) { case PaymentMethod.Gold: if (directBankTransaction) creature.Client.Account.Bank.RemoveGold(creature, price); else creature.Inventory.Gold -= price; break; case PaymentMethod.Stars: creature.Inventory.Stars -= price; break; case PaymentMethod.Ducats: break; // TODO: Implement ducats. case PaymentMethod.Points: creature.Points -= price; break; } // Reduce stock if (item.Stock > 0) { // Don't let it go below 0, that would mean unlimited. item.Stock = Math.Max(0, item.Stock - 1); if (item.Stock == 0) { // Refresh shop, so the item disappears. Send.ClearNpcShop(creature); Send.AddToNpcShop(creature, this.GetTabs(creature, owner)); } Send.ServerMessage(creature, "Debug: Stock remaining: {0}", item.Stock); } } return success; }
/// <summary> /// Checks if creature is able to enter a dungeon with the given item, /// at his current position, if so, a dungeon is created and the /// party is moved inside. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> /// <returns></returns> public bool CheckDrop(Creature creature, Item item) { var currentRegionId = creature.RegionId; if (!_entryRegionIds.Contains(currentRegionId)) return false; var pos = creature.GetPosition(); var clientEvent = creature.Region.GetClientEvent(a => a.Data.IsAltar); if (clientEvent == null) { Log.Warning("DungeonManager.CheckDrop: No altar found."); return false; } if (!clientEvent.IsInside(pos.X, pos.Y)) { // Tell player to step on altar? return false; } var parameter = clientEvent.Data.Parameters.FirstOrDefault(a => a.EventType == EventType.Altar); if (parameter == null || parameter.XML == null || parameter.XML.Attribute("dungeonname") == null) { Log.Warning("DungeonManager.CheckDrop: No dungeon name found in altar event '{0:X16}'.", clientEvent.EntityId); return false; } var dungeonName = parameter.XML.Attribute("dungeonname").Value.ToLower(); // Check script var dungeonScript = ChannelServer.Instance.ScriptManager.DungeonScripts.Get(dungeonName); if (dungeonScript == null) { Send.ServerMessage(creature, "This dungeon hasn't been added yet."); Log.Warning("DungeonManager.CheckDrop: No routing dungeon script found for '{0}'.", dungeonName); return false; } // Check arenas if (dungeonScript.Name == "tircho_alby_dungeon" && item.HasTag("/alby_battle_arena/")) { creature.Warp(28, 1174, 795); return true; } // Check route if (!dungeonScript.Route(creature, item, ref dungeonName)) { // The response in case of a fail is handled by the router. return false; } // Check party if (creature.IsInParty && creature.Party.Leader != creature) { // Unofficial Send.Notice(creature, Localization.Get("Only the leader may create the dungeon.")); return false; } return this.CreateDungeonAndWarp(dungeonName, item.Info.Id, creature); }
/// <summary> /// Warps creature, based on the item's properties. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> /// <param name="warpPartyMembers"></param> /// <returns>Whether a warp happened or not.</returns> public static bool Warp(Creature creature, Item item, bool warpPartyMembers) { if (creature == null) throw new ArgumentNullException("creature"); if (item == null) throw new ArgumentNullException("item"); // Check meta data if (!item.MetaData1.Has("TARGET")) { Send.ServerMessage(creature, Localization.Get("No target found.")); return false; } // Get target var target = item.MetaData1.GetString("TARGET"); // Get location based on target Location loc; if (target.StartsWith("pos")) // pos@regionId,x,y { var match = Regex.Match(target, @"pos@(?<regionId>[0-9]+),(?<x>[0-9]+),(?<y>[0-9]+)"); if (!match.Success) { Log.Warning("HiddenTownBack: Invalid position target: {0}", target); Send.ServerMessage(creature, Localization.Get("Invalid target.")); return false; } loc.RegionId = Convert.ToInt32(match.Groups["regionId"].Value); loc.X = Convert.ToInt32(match.Groups["x"].Value); loc.Y = Convert.ToInt32(match.Groups["y"].Value); } else if (target.StartsWith("portal")) // portal@name { // Remove "portal@" prefix target = target.Substring(7).Trim(); // Get portal data var portalData = AuraData.PortalDb.Find(target); if (portalData == null) { Log.Warning("HiddenTownBack: Unknown target: {0}", target); Send.ServerMessage(creature, Localization.Get("Unknown target.")); return false; } // Get location try { loc = new Location(portalData.Location); } catch { Log.Warning("HiddenTownBack: Invalid portal location: {0}", target); Send.ServerMessage(creature, Localization.Get("Invalid portal location.")); return false; } } else if (target == "last_town") { loc = new Location(creature.LastTown); } else { Log.Warning("HiddenTownBack: Unknown target type: {0}", target); Send.ServerMessage(creature, Localization.Get("Unknown target type.")); return false; } // Warp party if (warpPartyMembers && item.HasTag("/party_enable/") && creature.Party.Leader == creature) { var partyMembers = creature.Party.GetMembersInRange(creature); foreach (var member in partyMembers) member.Warp(loc); } // Warp user after we got the party members creature.Warp(loc); return true; }
/// <summary> /// Returns stability reduction for creature and weapon. /// </summary> /// <remarks> /// http://wiki.mabinogiworld.com/view/Knock_down_gauge#Knockdown_Timer_Rates /// </remarks> /// <param name="weapon"></param> /// <returns></returns> public float GetStabilityReduction(Creature creature, Item weapon) { var count = weapon != null && (weapon.HasTag("/weapon/") || weapon.HasTag("/ego_weapon/") || weapon.HasTag("/instrument/")) ? weapon.Info.KnockCount + 1 : creature.RaceData.KnockCount + 1; var speed = weapon != null && (weapon.HasTag("/weapon/") || weapon.HasTag("/ego_weapon/") || weapon.HasTag("/instrument/")) ? (AttackSpeed)weapon.Data.AttackSpeed : (AttackSpeed)creature.RaceData.AttackSpeed; // All values have been taken from the weapons data, the values in // comments were estimates, mainly based on logs. switch (count) { default: case 1: return 105; case 2: switch (speed) { default: case AttackSpeed.VerySlow: return 67; // 70 case AttackSpeed.Slow: return 65; // 68 case AttackSpeed.Normal: return 65; // 68 case AttackSpeed.Fast: return 65; // 68 case AttackSpeed.VeryFast: return 65; } case 3: switch (speed) { default: case AttackSpeed.VerySlow: return 55; // 60 case AttackSpeed.Slow: return 52; // 56 case AttackSpeed.Normal: return 50; // 53 case AttackSpeed.Fast: return 49; // 50 case AttackSpeed.VeryFast: return 48; } case 4: switch (speed) { default: case AttackSpeed.VerySlow: return 42; case AttackSpeed.Slow: return 40; case AttackSpeed.Normal: return 39; case AttackSpeed.Fast: return 36; case AttackSpeed.VeryFast: return 37; } case 5: switch (speed) { default: case AttackSpeed.VerySlow: return 36; case AttackSpeed.Slow: return 33; case AttackSpeed.Normal: return 31.5f; case AttackSpeed.Fast: return 30; // 40 case AttackSpeed.VeryFast: return 29.5f; // 35 } } }
/// <summary> /// Returns stun time for the target. /// </summary> /// <param name="weapon"></param> /// <param name="knockback"></param> /// <returns></returns> public static short GetTargetStun(Creature creature, Item weapon, bool knockback) { var count = weapon != null && (weapon.HasTag("/weapon/") || weapon.HasTag("/ego_weapon/") || weapon.HasTag("/instrument/")) ? weapon.Info.KnockCount + 1 : creature.RaceData.KnockCount + 1; var speed = weapon != null && (weapon.HasTag("/weapon/") || weapon.HasTag("/ego_weapon/") || weapon.HasTag("/instrument/")) ? (AttackSpeed)weapon.Data.AttackSpeed : (AttackSpeed)creature.RaceData.AttackSpeed; return GetTargetStun(count, speed, knockback); }
/// <summary> /// Gets the prop ID /// </summary> /// <param name="item"></param> /// <returns></returns> private int GetPropId(Item item) { if (item != null) { if (item.HasTag("/halloween_campfire_kit/")) { return HalloweenPropId; } else if (item.HasTag("/burner/")) { return ChristmasPropId; } else if (item.Info.Id == 63291) { return SeventhAnnvPropId; } else if (item.Info.Id == 63343) { return EighthAnnvPropId; } } return PropId; }
/// <summary> /// Returns option set id from "enchant scrolls", based on their data. /// </summary> /// <param name="enchant"></param> /// <returns></returns> private int GetOptionSetid(Item enchant) { var optionSetId = 0; // Elementals if (enchant.HasTag("/elemental/")) { optionSetId = enchant.MetaData1.GetInt("ENELEM"); } // Enchants else if (enchant.MetaData1.Has("ENPFIX") || enchant.MetaData1.Has("ENSFIX")) { var prefixId = enchant.MetaData1.GetInt("ENPFIX"); var suffixId = enchant.MetaData1.GetInt("ENSFIX"); if (prefixId != 0) optionSetId = prefixId; else if (suffixId != 0) optionSetId = suffixId; } // Fallback? (Pages) else { var prefixId = enchant.OptionInfo.Prefix; var suffixId = enchant.OptionInfo.Suffix; if (prefixId != 0) optionSetId = prefixId; else if (suffixId != 0) optionSetId = suffixId; } return optionSetId; }
/// <summary> /// Updates equip objectives. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> private void OnPlayerEquipsItem(Creature creature, Item item) { if (creature == null || !creature.IsPlayer || item == null || !item.Info.Pocket.IsEquip()) return; var quests = creature.Quests.GetAllIncomplete(this.Id); foreach (var quest in quests) { var progress = quest.CurrentObjectiveOrLast; if (progress == null) return; var objective = this.Objectives[progress.Ident]; if (objective == null || objective.Type != ObjectiveType.Equip) return; var equipObjective = (objective as QuestObjectiveEquip); if (!progress.Done && item.HasTag(equipObjective.Tag)) { quest.SetDone(progress.Ident); Send.QuestUpdate(creature, quest); } } }
/// <summary> /// Handles item burning, retruns whether it was successful. /// </summary> /// <param name="creature"></param> /// <param name="item"></param> /// <param name="campfire"></param> /// <param name="enchantersBurn"></param> public bool Burn(Creature creature, Item item, Prop campfire, bool enchantersBurn) { var skill = creature.Skills.Get(SkillId.Enchant); var enchantBurnSuccess = false; var powderBurnSuccess = false; var exp = 0; // Enchanter's Burn if (enchantersBurn) { var rnd = RandomProvider.Get(); var isEquip = item.HasTag("/equip/"); var hasEnchantBurnItems = (creature.Inventory.Has(51102) && creature.Inventory.Has(63016)); // Mana Herb + Holy Water // Enchant burning if (!isEquip || !hasEnchantBurnItems) { // Unofficial Send.SystemMessage(creature, Localization.Get("You don't the necessary items.")); return false; } // Get chances // All unofficial var rank = (skill == null ? 16 : (int)skill.Info.Rank); var enchantChance = (skill == null ? 0 : skill.RankData.Var3); // Campfire r8+ bonus if (enchantChance > 0 && campfire.Temp.CampfireSkillRank.Rank >= SkillRank.R8) enchantChance += (16 - rank); // Powder = double enchant chance, based on the Wiki saying // r1 doesn't guarantee getting the enchants, but it does // guarantee getting powder. var powderChance = enchantChance * 2; // Debug if (creature.Titles.SelectedTitle == TitleId.devCAT) Send.ServerMessage(creature, "Debug: Chance for enchant: {0:0}, chance for powder: {1:0}", enchantChance, powderChance); // Try prefix if (item.OptionInfo.Prefix != 0 && rnd.Next(100) < enchantChance) { var enchant = Item.CreateEnchant(item.OptionInfo.Prefix); creature.AcquireItem(enchant); enchantBurnSuccess = true; } // Try suffix if (item.OptionInfo.Suffix != 0 && rnd.Next(100) < enchantChance) { var enchant = Item.CreateEnchant(item.OptionInfo.Suffix); creature.AcquireItem(enchant); enchantBurnSuccess = true; } // Try suffix if (item.OptionInfo.Prefix + item.OptionInfo.Suffix != 0 && rnd.Next(100) < powderChance) { var powder = new Item(62003); // Blessed Magic Powder creature.AcquireItem(powder); powderBurnSuccess = true; } // Reduce items creature.Inventory.Remove(51102, 1); // Mana Herb creature.Inventory.Remove(63016, 1); // Holy Water // Training this.BurnTraining(skill, enchantBurnSuccess, powderBurnSuccess); // Success/Fail motion Send.UseMotion(creature, 14, enchantBurnSuccess ? 0 : 3); } // Add exp based on item buying price (random+unofficial) if (item.OptionInfo.Price > 0) { exp = 40 + (int)(item.OptionInfo.Price / (float)item.Data.StackMax / 100f * item.Info.Amount); creature.GiveExp(exp); } // Remove item from cursor creature.Inventory.Remove(item); // Effect Send.Effect(MabiId.Broadcast, creature, Effect.BurnItem, campfire.EntityId, enchantBurnSuccess); Send.Notice(creature, NoticeType.MiddleSystem, Localization.Get("Burning EXP {0}"), exp); return true; }
/// <summary> /// Returns a list of bonuses that the given item would get with /// the given quality. /// </summary> /// <remarks> /// Reference: http://mabination.com/threads/85245-Player-made-Item-Quality /// </remarks> /// <param name="item"></param> /// <param name="quality"></param> /// <returns></returns> private Dictionary<Bonus, int> GetBonusesFor(Item item, int quality) { var bonuses = new Dictionary<Bonus, int>(); // Weapons (except bows) if (item.HasTag("/weapon/") && !item.HasTag("/bow/|/bow01|/crossbow/")) { // Balance if (quality >= 98) bonuses[Bonus.Balance] = 10; else if (quality >= 95) bonuses[Bonus.Balance] = 9; else if (quality >= 92) bonuses[Bonus.Balance] = 8; else if (quality >= 90) bonuses[Bonus.Balance] = 7; else if (quality >= 85) bonuses[Bonus.Balance] = 6; else if (quality >= 80) bonuses[Bonus.Balance] = 5; else if (quality >= 70) bonuses[Bonus.Balance] = 4; else if (quality >= 60) bonuses[Bonus.Balance] = 3; else if (quality >= 50) bonuses[Bonus.Balance] = 2; else if (quality >= 30) bonuses[Bonus.Balance] = 1; // Critical if (quality >= 95) bonuses[Bonus.Critical] = 5; else if (quality >= 90) bonuses[Bonus.Critical] = 4; else if (quality >= 80) bonuses[Bonus.Critical] = 3; else if (quality >= 70) bonuses[Bonus.Critical] = 2; else if (quality >= 50) bonuses[Bonus.Critical] = 1; // Max Attack if (quality >= 75) bonuses[Bonus.AttackMax] = 2; else if (quality >= 20) bonuses[Bonus.AttackMax] = 1; else if (quality < -80) bonuses[Bonus.AttackMax] = -1; // Min Attack if (quality >= 75) bonuses[Bonus.AttackMin] = 2; else if (quality >= 20) bonuses[Bonus.AttackMin] = 1; else if (quality < -80) bonuses[Bonus.AttackMin] = -1; // Durability if (quality >= 80) { bonuses[Bonus.Durability] = 5; bonuses[Bonus.DurabilityMax] = 5; } else if (quality >= 60) { bonuses[Bonus.Durability] = 4; bonuses[Bonus.DurabilityMax] = 4; } else if (quality >= 50) { bonuses[Bonus.Durability] = 3; bonuses[Bonus.DurabilityMax] = 3; } else if (quality >= 45) { bonuses[Bonus.Durability] = 2; bonuses[Bonus.DurabilityMax] = 2; } else if (quality >= 40) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } else if (quality >= -20) { } else if (quality >= -60) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = 0; } else if (quality >= -80) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = -1; } else { bonuses[Bonus.Durability] = -3; bonuses[Bonus.DurabilityMax] = -2; } } // Bows else if (item.HasTag("/bow/|/bow01/|/crossbow/")) { // Balance if (quality >= 98) bonuses[Bonus.Balance] = 5; else if (quality >= 80) bonuses[Bonus.Balance] = 4; else if (quality >= 70) bonuses[Bonus.Balance] = 3; else if (quality >= 50) bonuses[Bonus.Balance] = 2; else if (quality >= 30) bonuses[Bonus.Balance] = 1; // Critical if (quality >= 98) bonuses[Bonus.Critical] = 5; else if (quality >= 95) bonuses[Bonus.Critical] = 4; else if (quality >= 80) bonuses[Bonus.Critical] = 3; else if (quality >= 70) bonuses[Bonus.Critical] = 2; else if (quality >= 10) bonuses[Bonus.Critical] = 1; // Max Attack if (quality >= 90) bonuses[Bonus.AttackMax] = 2; else if (quality >= 10) bonuses[Bonus.AttackMax] = 1; else bonuses[Bonus.AttackMax] = -1; // Min Attack if (quality >= 95) bonuses[Bonus.AttackMin] = 2; else if (quality >= 30) bonuses[Bonus.AttackMin] = 1; else if (quality < -10) bonuses[Bonus.AttackMin] = -1; // Durability if (quality >= 98) { bonuses[Bonus.Durability] = 3; bonuses[Bonus.DurabilityMax] = 3; } else if (quality >= 90) { bonuses[Bonus.Durability] = 2; bonuses[Bonus.DurabilityMax] = 2; } else if (quality >= 50) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } else if (quality >= -10) { } else if (quality >= -30) { bonuses[Bonus.Durability] = -1; bonuses[Bonus.DurabilityMax] = -1; } else { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = -2; } } // Armors and clothes else if (item.HasTag("/armor/cloth/|/armor/lightarmor/|/armor/heavyarmor/")) { // Defense if (quality >= 90) bonuses[Bonus.Defense] = 1; // Protection if (quality >= 95) bonuses[Bonus.Protection] = 3; else if (quality >= 75) bonuses[Bonus.Protection] = 2; else if (quality >= 50) bonuses[Bonus.Protection] = 1; // Durability if (quality >= 80) { bonuses[Bonus.Durability] = 5; bonuses[Bonus.DurabilityMax] = 5; } else if (quality >= 70) { bonuses[Bonus.Durability] = 4; bonuses[Bonus.DurabilityMax] = 4; } else if (quality >= 55) { bonuses[Bonus.Durability] = 3; bonuses[Bonus.DurabilityMax] = 3; } else if (quality >= 35) { bonuses[Bonus.Durability] = 2; bonuses[Bonus.DurabilityMax] = 2; } else if (quality >= -20) { } else if (quality >= -60) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = 0; } else if (quality >= -80) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = -1; } else { bonuses[Bonus.Durability] = -3; bonuses[Bonus.DurabilityMax] = -2; } } // Gloves and Gauntles else if (item.HasTag("/hand/glove/|/hand/gauntlet/")) { // Protection if (quality >= 80) bonuses[Bonus.Protection] = 1; } // Boots, Shoes, and Greaves else if (item.HasTag("/foot/shoes/|/foot/armorboots/")) { // Durability if (quality >= 95) { bonuses[Bonus.Durability] = 5; bonuses[Bonus.DurabilityMax] = 5; } else if (quality >= 85) { bonuses[Bonus.Durability] = 4; bonuses[Bonus.DurabilityMax] = 4; } else if (quality >= 60) { bonuses[Bonus.Durability] = 3; bonuses[Bonus.DurabilityMax] = 3; } else if (quality >= 40) { bonuses[Bonus.Durability] = 2; bonuses[Bonus.DurabilityMax] = 2; } else if (quality >= 20) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } else if (quality >= -20) { } else if (quality >= -60) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = 0; } else if (quality >= -80) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = -1; } else { bonuses[Bonus.Durability] = -3; bonuses[Bonus.DurabilityMax] = -2; } } // Shields else if (item.HasTag("/lefthand/shield/")) { // Defense if (quality >= 90) bonuses[Bonus.Defense] = 1; // Durability if (quality >= 95) { bonuses[Bonus.Durability] = 5; bonuses[Bonus.DurabilityMax] = 5; } else if (quality >= 90) { bonuses[Bonus.Durability] = 4; bonuses[Bonus.DurabilityMax] = 4; } else if (quality >= 85) { bonuses[Bonus.Durability] = 3; bonuses[Bonus.DurabilityMax] = 3; } else if (quality >= 80) { bonuses[Bonus.Durability] = 2; bonuses[Bonus.DurabilityMax] = 2; } else if (quality >= 40) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } else if (quality >= -20) { } else if (quality >= -60) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = 0; } else if (quality >= -80) { bonuses[Bonus.Durability] = -2; bonuses[Bonus.DurabilityMax] = -1; } else { bonuses[Bonus.Durability] = -3; bonuses[Bonus.DurabilityMax] = -2; } } // Hats else if (item.HasTag("/headgear/")) { // Durability if (quality >= 90) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } } // Helmets else if (item.HasTag("/helmet/")) { // Durability if (quality >= 80) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } } // Robes else if (item.HasTag("/robe/")) { if (quality >= 80) { bonuses[Bonus.Durability] = 1; bonuses[Bonus.DurabilityMax] = 1; } } return bonuses; }
/// <summary> /// Handles skill training. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="item"></param> /// <param name="result"></param> private void OnProgress(Creature creature, Skill skill, Item item, ProgressResult result) { if (skill.Info.Rank == SkillRank.RF) { if (item.HasTag("/weapon/|/tool/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging a tool or a weapon. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging a tool or a weapon. case ProgressResult.VeryBad: skill.Train(3); break; // Achieve a failing result forging a tool or a weapon. case ProgressResult.Bad: skill.Train(4); break; // Achieve a bad result forging a tool or a weapon. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge a tool or a weapon. } } return; } if (skill.Info.Rank == SkillRank.RE) { if (item.HasTag("/shield/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging a shield. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging a shield. case ProgressResult.VeryBad: skill.Train(3); break; // Achieve a failing result forging a shield. case ProgressResult.Bad: skill.Train(4); break; // Achieve a bad result forging a shield. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge a shield. } } return; } if (skill.Info.Rank == SkillRank.RD) { if (item.HasTag("/helmet/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging a helmet. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging a helmet. case ProgressResult.VeryBad: skill.Train(3); break; // Achieve a failing result forging a helmet. case ProgressResult.Bad: skill.Train(4); break; // Achieve a bad result forging a helmet. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge a helmet. } } return; } if (skill.Info.Rank == SkillRank.RC) { if (item.HasTag("/gauntlet/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging gauntlets. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging gauntlets. case ProgressResult.VeryBad: skill.Train(3); break; // Achieve a failing result forging gauntlets. case ProgressResult.Bad: skill.Train(4); break; // Achieve a bad result forging gauntlets. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge gauntlets. } } return; } if (skill.Info.Rank == SkillRank.RB) { if (item.HasTag("/armorboots/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging greaves. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging greaves. case ProgressResult.VeryBad: skill.Train(3); break; // Achieve a failing result forging greaves. case ProgressResult.Bad: skill.Train(4); break; // Achieve a bad result forging greaves. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge greaves. } } return; } if (skill.Info.Rank == SkillRank.RA) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Greatly successful in making Armor case ProgressResult.Good: skill.Train(2); break; // Successful in making Armors case ProgressResult.VeryBad: skill.Train(3); break; // If unsuccessful in making Armor case ProgressResult.Bad: skill.Train(4); break; // The result of making Armor is very poor. case ProgressResult.Finish: skill.Train(5); break; // Completed making Armor 100%. } } return; } if (skill.Info.Rank == SkillRank.R9) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Greatly successful in making Armor case ProgressResult.Good: skill.Train(2); break; // Successful in making Armors case ProgressResult.Finish: skill.Train(3); break; // Completed making Armor 100%. } } else if (item.HasTag("/weapon/|/tool/")) { switch (result) { case ProgressResult.Good: skill.Train(4); break; // Successful in making a tool or a weapon. case ProgressResult.Finish: skill.Train(5); break; // Completed making tool or a weapon 100%. } } return; } if (skill.Info.Rank == SkillRank.R8) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Greatly successful in making Armor case ProgressResult.Good: skill.Train(2); break; // Successful in making Armors case ProgressResult.Finish: skill.Train(3); break; // Completed making Armor 100%. } } else if (item.HasTag("/shield/")) { switch (result) { case ProgressResult.Good: skill.Train(4); break; // Successful in making a Shield. case ProgressResult.Finish: skill.Train(5); break; // Completed making a Shield 100%. } } return; } if (skill.Info.Rank == SkillRank.R7) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging armor. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging armor. case ProgressResult.Finish: skill.Train(3); break; // Successfully forge armor. } } else if (item.HasTag("/helmet/")) { switch (result) { case ProgressResult.Good: skill.Train(4); break; // Achieve a good result forging a helmet. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge a helmet. } } return; } if (skill.Info.Rank == SkillRank.R6) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging armor. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging armor. case ProgressResult.Finish: skill.Train(3); break; // Successfully forge armor. } } else if (item.HasTag("/gauntlet/")) { switch (result) { case ProgressResult.Good: skill.Train(4); break; // Achieve a good result forging gauntlets. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge gauntlets. } } return; } if (skill.Info.Rank == SkillRank.R5) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging armor. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging armor. case ProgressResult.Finish: skill.Train(3); break; // Successfully forge armor. } } else if (item.HasTag("/armorboots/")) { switch (result) { case ProgressResult.Good: skill.Train(4); break; // Achieve a good result forging greaves. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge greaves. } } return; } if (skill.Info.Rank >= SkillRank.R4 && skill.Info.Rank <= SkillRank.R3) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.VeryGood: skill.Train(1); break; // Achieve a great result forging armor. case ProgressResult.Good: skill.Train(2); break; // Achieve a good result forging armor. case ProgressResult.Finish: skill.Train(3); break; // Successfully forge armor. } } else if (item.HasTag("/weapon/|/tool/")) { switch (result) { case ProgressResult.Good: skill.Train(4); break; // Achieve a good result forging a tool or a weapon. case ProgressResult.Finish: skill.Train(5); break; // Successfully forge a tool or a weapon. } } return; } if (skill.Info.Rank >= SkillRank.R2 && skill.Info.Rank <= SkillRank.R1) { if (item.HasTag("/armor/")) { switch (result) { case ProgressResult.Good: skill.Train(1); break; // Achieve a good result forging armor. case ProgressResult.Finish: skill.Train(2); break; // Successfully forge armor. } } else if (item.HasTag("/weapon/|/tool/")) { switch (result) { case ProgressResult.Good: skill.Train(3); break; // Achieve a good result forging a tool or a weapon. case ProgressResult.Finish: skill.Train(4); break; // Successfully forge a tool or a weapon. } } return; } }
/// <summary> /// Gets the prop ID /// </summary> /// <param name="item"></param> /// <returns></returns> private int GetPropId(Item item) { if (item != null) { if (item.HasTag("/halloween_campfire_kit/")) { return HalloweenPropId; } else if (item.HasTag("/burner/")) { return ChristmasPropId; } else if (item.HasTag("/anniversary_campfire_kit/")) { return SeventhAnnvPropId; } } return PropId; }
public static Packet AddItemInfo(this Packet packet, Item item, ItemPacketType type) { var isEgoWeapon = item.HasTag("/ego_weapon/"); var isGuildRobe = item.HasTag("/guild_robe/"); packet.PutLong(item.EntityId); packet.PutByte((byte)type); packet.PutBin(item.Info); if (isGuildRobe) // EBCL1:4:-16351525;EBCL2:4:-875718;EBLM1:1:46;EBLM2:1:11;EBLM3:1:4; (GLDNAM:s:European;) packet.PutString(item.MetaData1.ToString()); if (type == ItemPacketType.Public) { packet.PutByte(1); // Affects color of dropped item's name (blue or green), // indicating its value. packet.PutByte((byte)item.UpgradeEffectCount); //packet.PutByte(0); // Bitmask // if & 1 // float packet.PutByte(1); packet.PutFloat(1); // Size multiplicator *hint: Server side giant key mod* packet.PutByte(item.FirstTimeAppear); // 0: No bouncing, 1: Bouncing, 2: Delayed bouncing } else if (type == ItemPacketType.Private) { packet.PutBin(item.OptionInfo); // Ego data if (isEgoWeapon) { packet.PutString(item.EgoInfo.Name); packet.PutByte((byte)item.EgoInfo.Race); packet.PutByte(0); // ? increased from 14 to 18 when I fed a bottle to a sword packet.PutByte(item.EgoInfo.SocialLevel); packet.PutInt(item.EgoInfo.SocialExp); packet.PutByte(item.EgoInfo.StrLevel); packet.PutInt(item.EgoInfo.StrExp); packet.PutByte(item.EgoInfo.IntLevel); packet.PutInt(item.EgoInfo.IntExp); packet.PutByte(item.EgoInfo.DexLevel); packet.PutInt(item.EgoInfo.DexExp); packet.PutByte(item.EgoInfo.WillLevel); packet.PutInt(item.EgoInfo.WillExp); packet.PutByte(item.EgoInfo.LuckLevel); packet.PutInt(item.EgoInfo.LuckExp); packet.PutByte(item.EgoInfo.AwakeningEnergy); packet.PutInt(item.EgoInfo.AwakeningExp); packet.PutLong(0); packet.PutLong(item.EgoInfo.LastFeeding); // Last feeding time? packet.PutInt(0); } packet.PutString(item.MetaData1.ToString()); packet.PutString(item.MetaData2.ToString()); // Upgrades var upgradeEffects = item.GetUpgradeEffects(); packet.PutByte((byte)upgradeEffects.Length); foreach (var upgradeEffect in upgradeEffects) packet.PutBin(upgradeEffect); // Special upgrades? (example) //0608 [0000000000000000] Long : 0 //0609 [........00000002] Int : 2 //0610 [........00000024] Int : 36 //0611 [........00000008] Int : 8 //0612 [........00000026] Int : 38 //0613 [........00000004] Int : 4 packet.PutLong(item.QuestId); if (isGuildRobe) packet.PutString(item.MetaData1.GetString("GLDNAM")); // In NA235 (Sep. 2016) we found an additional integer for // Scythe that Reaps Darkness here, with no known purpose. // In NA236 we had to remove said int again. // It will be missed. //if (item.Info.Id == 41237) // packet.PutInt(0); // [190100, NA200 (2015-01-15)] ? { packet.PutByte(item.IsNew); packet.PutByte(0); } } return packet; }