/// <title>Saga.NpcTakeItem</title> /// <code> /// Saga.NpcTakeItem(cid, QuestID, ItemId, Count); /// </code> /// <description> /// Takes a npc item as with a message that the npc took it. /// </description> /// <example> public static int TakeItem(uint cid, uint itemid, byte count) { Character value; if (LifeCycle.TryGetById(cid, out value)) { //HELPER VARIABLES DEFAULT_FACTORY_ITEMS.ItemInfo info; Singleton.Item.TryGetItem(itemid, out info); //int stackcount = 0; Predicate<Rag2Item> callback = delegate(Rag2Item item) { bool result = item.info.item == itemid; //if (result) stackcount += item.info.max_stack - item.count; return result; }; //CHECK IF RIGHT AMOUNT OF ITEMS WAS FOUND List<int> FoundItems = value.ITEMS.FindAll(callback); //if (count > stackcount) return -1; //DO THE ACTUAL TAKING int acount = count; foreach (int currentInxdex in FoundItems) { Stackable<Rag2Item> item = value.ITEMS[currentInxdex]; int MinCount = Math.Min(acount, Math.Min(item.Count, info.max_stack)); acount -= MinCount; if ((item.Count -= MinCount) == 0) { value.ITEMS.RemoveAt(currentInxdex); SMSG_DELETEITEM spkt = new SMSG_DELETEITEM(); spkt.Container = 2; spkt.Index = (byte)currentInxdex; spkt.UpdateReason = (byte)ITEMUPDATEREASON.GIVE_TO_NPC; spkt.SessionId = value.id; value.client.Send((byte[])spkt); } else { SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Amount = (byte)item.Count; spkt.UpdateReason = (byte)ITEMUPDATEREASON.GIVE_TO_NPC; spkt.UpdateType = 4; spkt.Container = 2; spkt.SessionId = value.id; spkt.Index = (byte)currentInxdex; value.client.Send((byte[])spkt); break; } } return count; } else { return -1; } }
private void CM_QUESTITEMSTART(CMSG_QUESTITEMSTART cpkt) { Rag2Item item = this.character.container[cpkt.Index]; if (item == null) return; if (item.info.quest == 0) return; byte result = 1; if (Singleton.Database.IsQuestComplete(this.character, item.info.quest)) { result = 1; } else if (this.character.QuestObjectives[item.info.quest] != null) { result = 2; } else { try { QuestBase Quest; if (Singleton.Quests.TryFindQuests(item.info.quest, out Quest) == false || Quest.OnStart(this.character.id) < 0) { result = 1; QuestBase.InvalidateQuest(Quest, this.character); } else { result = 0; int newLength = this.character.container[cpkt.Index].count - 1; if (newLength > 0) { this.character.container[cpkt.Index].count = newLength; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)newLength; spkt2.UpdateReason = 8; spkt2.UpdateType = 4; spkt2.Container = 2; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.Index; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 8; spkt3.Container = 2; spkt3.Index = cpkt.Index; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } Quest.CheckQuest(this.character); } } catch (Exception) { Trace.TraceError("Error starting quest: {0}", item.info.quest); } } SMSG_USEQUESTITEM spkt = new SMSG_USEQUESTITEM(); spkt.Index = cpkt.Index; spkt.Result = result; spkt.SessionId = this.character.id; this.Send((byte[])spkt); }
/// <summary> /// This function occurs when you want to sell a item. The sell price of the item is /// one-fourth of the actual market value. /// </summary> /// <param name="cpkt"></param> private void CM_NPCINTERACTION_SHOPSELL(CMSG_NPCSHOPSELL cpkt) { BaseNPC npc = this.character.Target as BaseNPC; BaseShopCollection list = this.character.Tag as BaseShopCollection; if (npc != null && list != null) { #region OBTAIN ITEM FROM INVENTORY //OBTAIN THE REQUIRED ITEM FROM THE MERCHANT Rag2Item item = this.character.container[cpkt.Index]; if (item == null || cpkt.Amount > item.count) return; #endregion OBTAIN ITEM FROM INVENTORY #region MERCHANDISE - CHECK MERCHANTS MONEY //CHECK IF THE MERCHANT HAS ENOUGH MONEY double durabillity_scalar = (item.info.max_durability > 0) ? item.durabillty / item.info.max_durability : 1; uint req_money = (uint)((double)((item.info.price / 4) * cpkt.Amount) * durabillity_scalar); if (npc.Zeny < req_money) { Common.Errors.GeneralErrorMessage(this.character, 3); return; } #endregion MERCHANDISE - CHECK MERCHANTS MONEY #region MERCHANDISE - CHECK IF ITEM CAN BE SOLD //CHECKS IF THE ITEM IS TRADEABLE if (item.info.trade == 0) { Common.Errors.GeneralErrorMessage(this.character, 4); return; } #endregion MERCHANDISE - CHECK IF ITEM CAN BE SOLD #region MERCHANDISE - UPDATE ZENY this.character.ZENY += req_money; npc.Zeny -= req_money; CommonFunctions.UpdateZeny(this.character); CommonFunctions.UpdateShopZeny(this.character); #endregion MERCHANDISE - UPDATE ZENY #region INVENTORY - ITEM int newCount = item.count - cpkt.Amount; if (newCount == 0) { //SEND INVENTORY - ITEM DELETE REASON WITH REASON: Sold this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt = new SMSG_DELETEITEM(); spkt.Container = 2; spkt.Index = cpkt.Index; spkt.UpdateReason = 3; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } else { //SEND INVENTORY - ITEM UPDATE REASON WITH REASON: Sold this.character.container[cpkt.Index].count = newCount; SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Amount = (byte)newCount; spkt.UpdateReason = 3; spkt.UpdateType = 4; spkt.Container = 2; spkt.SessionId = this.character.id; spkt.Index = cpkt.Index; this.Send((byte[])spkt); } #endregion INVENTORY - ITEM #region MERCHANDISE - STACK ON REBUY LIST //STRUCTURIZE NEW STACKED RAG2 ITEM Rag2Item newItem = item.Clone(cpkt.Amount); this.character.REBUY.Add(newItem); //POPS THE FIRST ITEM OFF THE LIST if (this.character.REBUY.Count > 16) this.character.REBUY.RemoveAt(0); CommonFunctions.SendRebuylist(this.character); #endregion MERCHANDISE - STACK ON REBUY LIST #region PLAYER - OPTION //Type is used to calc type of item //(21 seems to be used for Applogy Item) if (newItem.info.type == 21) { Common.Skills.DeleteAddition(this.character, newItem.info.option_id); } #endregion PLAYER - OPTION } }
/// <summary> /// Registers a item from your inventory onto the market. /// </summary> /// <param name="cpkt"></param> private void CM_MARKET_REGISTERITEM(CMSG_MARKETREGISTER cpkt) { SMSG_MARKETREGISTER spkt = new SMSG_MARKETREGISTER(); byte result = 0; try { Rag2Item item = this.character.container[cpkt.Index]; if (item == null) return; uint requiredZeny = (uint)(50 * cpkt.Days); //NOT ENOUGH MONEY TO REGISTER ITEM if (requiredZeny > this.character.ZENY) { result = 6; } //CHECK REGISTERED ITEM COUNT else if (Singleton.Database.GetOwnerItemCount(this.character) == 20) { result = 8; } //EVERYTHING OKAY else { //Create mail argument Rag2Item bitem = item.Clone(cpkt.Count); MarketItemArgument argument = new MarketItemArgument(); argument.item = bitem; argument.expires = DateTime.Now.AddDays(cpkt.Days); argument.cat = (byte)item.info.categorie; argument.price = cpkt.Price; argument.sender = this.character.Name; argument.itemname = item.info.name; argument.id = Singleton.Database.RegisterNewMarketItem(this.character, argument); spkt.Item = bitem; spkt.AuctionID = argument.id; spkt.Zeny = cpkt.Price; spkt.ExpireDate = argument.expires; this.character.ZENY -= requiredZeny; CommonFunctions.UpdateZeny(this.character); int newCount = item.count - cpkt.Count; if (newCount > 0) { item.count = newCount; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Index = cpkt.Index; spkt2.UpdateReason = (byte)ItemUpdateReason.AuctionRegister; spkt2.UpdateType = 4; spkt2.SessionId = this.character.id; spkt2.Amount = (byte)item.count; spkt2.Container = 2; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt2 = new SMSG_DELETEITEM(); spkt2.Index = cpkt.Index; spkt2.UpdateReason = (byte)ItemUpdateReason.AuctionRegister; spkt2.UpdateReason = 4; spkt2.SessionId = this.character.id; spkt2.Container = 2; this.Send((byte[])spkt2); } } } //DATABASE ERROR catch (Exception e) { result = 1; Console.WriteLine(e); } finally { spkt.SessionId = this.character.id; spkt.Result = result; this.Send((byte[])spkt); } }
/// <summary> /// This function is used when a player discards item x from either their storage /// or from their inventory. Also here we safely check for any weird stuff. /// </summary> /// <remarks> /// This function should also check if you have the item you want to delete is a quest item /// because if the quest is active you shouln't be allowed to discard your item. /// </remarks> /// <param name="cpkt"></param> private void CM_DISCARDITEM(CMSG_DELETEITEM cpkt) { Rag2Item item = null; if (cpkt.Container == 2) { item = this.character.container[cpkt.Index]; if (item == null) { Common.Errors.GeneralErrorMessage( this.character, (uint)Generalerror.InventoryItemNotFound ); return; } else { if (QuestBase.IsDiscardAble(item.info.item, this.character)) { Common.Errors.GeneralErrorMessage( this.character, (uint)Generalerror.CannotDiscard ); return; } } } else if (cpkt.Container == 3) { item = this.character.STORAGE[cpkt.Index]; if (item == null) { Common.Errors.GeneralErrorMessage( this.character, (uint)Generalerror.StorageItemNotFound ); return; } else { if (QuestBase.IsDiscardAble(item.info.item, this.character)) { Common.Errors.GeneralErrorMessage( this.character, (uint)Generalerror.CannotDiscard ); return; } } } else { Common.Errors.GeneralErrorMessage( this.character, (uint)Generalerror.WrongServerIndex ); return; } //VALIDATE ITEM INFORMATION if (cpkt.Amount > item.count || cpkt.Amount > item.info.max_stack) return; //PROCESS DISCARDING int nCount = item.count - cpkt.Amount; if (nCount == 0) { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt = new SMSG_DELETEITEM(); spkt.Container = cpkt.Container; spkt.Index = cpkt.Index; spkt.UpdateReason = 1; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } else { item.count = nCount; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)nCount; spkt2.UpdateReason = 1; spkt2.UpdateType = 4; spkt2.Container = cpkt.Container; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.Index; this.Send((byte[])spkt2); } }
/// <summary> /// This function occurs when you want to rebuy a item. /// </summary> /// <param name="cpkt"></param> private void CM_NPCINTERACTION_SHOPREBUY(CMSG_NPCREBUY cpkt) { BaseNPC npc = this.character.Target as BaseNPC; BaseShopCollection list = this.character.Tag as BaseShopCollection; if (npc != null && list != null) { #region OBTAIN ITEM FROM REBUYLIST //OBTAIN THE REQUIRED ITEMS FROM THE MERCHANT int Index = cpkt.Index - 1; if (Index >= this.character.REBUY.Count) return; Rag2Item item = this.character.REBUY[Index]; if (item == null) return; if (cpkt.Amount > item.count) return; #endregion OBTAIN ITEM FROM REBUYLIST #region MERCHANDISE - CHECK PLAYER'S MONEY double durabillity_scalar = (item.info.max_durability > 0) ? item.durabillty / item.info.max_durability : 1; uint req_zeny = (uint)((double)((item.info.price / 4) * cpkt.Amount) * durabillity_scalar); if (this.character.ZENY < req_zeny) { Common.Errors.GeneralErrorMessage(this.character, 2); return; } #endregion MERCHANDISE - CHECK PLAYER'S MONEY #region MERCHANDISE - CHECK INVENTORY //TEMP HELPER VARIABLES int nstacked = 0; List<int> update_queue = new List<int>(); //WALKTHROUGH EVERY ITEM AND CHECK IF IT CAN BE STACKED foreach (int index in this.character.container.FindAllItems(item.info.item)) { Rag2Item invItem = this.character.container[index]; nstacked += (item.info.max_stack - invItem.count); if (invItem.count < item.info.max_stack) update_queue.Add(index); } //CALCULATE THE AMOUNT OF NEW SLOTS REQUIRED int req_hslot = (int)cpkt.Amount % (int)this.character.container.Capacity; int div_rem = (int)((cpkt.Amount - nstacked) / item.info.max_stack); int div_rem2 = (req_hslot > 0) ? 1 : 0; int req_slots = div_rem + div_rem2; if (this.character.container.Count + req_slots > this.character.container.Capacity) { Common.Errors.GeneralErrorMessage(this.character, 1); return; } #endregion MERCHANDISE - CHECK INVENTORY #region MERCHANDISE - UPDATE ZENY this.character.ZENY -= req_zeny; npc.Zeny += req_zeny; CommonFunctions.UpdateZeny(this.character); CommonFunctions.UpdateShopZeny(this.character); #endregion MERCHANDISE - UPDATE ZENY #region PLAYER - INVENTORY ITEMS //AMOUNT USED IN DECREMENT CALCULATIONS int amount = (int)cpkt.Amount; //ITERATE THROUGH ALL AVAILABLE ITEM THAT CAN BE PROCESSED FOR UPDATES foreach (int invIndex in update_queue) { Rag2Item invItem = this.character.container[invIndex]; int leftover = item.info.max_stack - invItem.count; invItem.count += Math.Max(0, leftover); amount -= leftover; SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Index = (byte)invIndex; spkt.UpdateReason = 2; spkt.UpdateType = 4; spkt.Container = 2; spkt.Amount = (byte)invItem.count; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } //ITERATE THROUGH EVERY FREE INDEX AND PROCESS IT foreach (int invIndex in this.character.container.FindFreeIndexes()) { if (amount == 0) break; int leftover = Math.Min(amount, item.info.max_stack); Rag2Item invItem = item.Clone(leftover); this.character.container[invIndex] = invItem; amount -= leftover; SMSG_ADDITEM spkt = new SMSG_ADDITEM(); spkt.Container = 2; spkt.UpdateReason = 2; spkt.SetItem(invItem, invIndex); spkt.SessionId = this.character.id; this.Send((byte[])spkt); //Type is used to calc type of item //(21 seems to be used for Applogy Item) if (invItem.info.type == 21) { Common.Skills.UpdateAddition(this.character, invItem.info.option_id); } } #endregion PLAYER - INVENTORY ITEMS #region MERCHANDISE - REBUYLIST if (amount == 0) { this.character.REBUY.RemoveAt(Index); CommonFunctions.SendRebuylist(this.character); } else { item.count = amount; CommonFunctions.SendRebuylist(this.character); } #endregion MERCHANDISE - REBUYLIST } }
/// <summary> /// This occurs after adding a auge skill to the weaponary /// </summary> /// <param name="cpkt"></param> private void CM_WEAPONAUGE(CMSG_WEAPONAUGE cpkt) { Rag2Item item = this.character.container[cpkt.Index]; Weapon wep = this.character.weapons[cpkt.WeaponSlot]; if (item == null) return; wep._augeskill = item.info.skill; Point oldPos = this.character.Position; Regiontree tree = this.character.currentzone.Regiontree; bool IsActiveItem = cpkt.WeaponSlot == (byte)((character.weapons.ActiveWeaponIndex == 0) ? character.weapons.PrimaryWeaponIndex : character.weapons.SeconairyWeaponIndex); //Update item count int newLength = item.count - 1; if (newLength > 0) { item.count = newLength; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)newLength; spkt2.UpdateReason = 0; spkt2.UpdateType = 4; spkt2.Container = 2; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.Index; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 0; spkt3.Container = 2; spkt3.Index = cpkt.Index; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } //Update all objects foreach (Character regionObject in tree.SearchActors(SearchFlags.Characters)) { if (regionObject.id == this.character.id) { SMSG_ENCHANTMENT spkt = new SMSG_ENCHANTMENT(); spkt.Unknown1 = 1; spkt.Unknown2 = cpkt.WeaponSlot; spkt.Weaponslot = cpkt.Slot; spkt.SkillId = wep._augeskill; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } else if (IsActiveItem && Point.IsInSightRangeByRadius(regionObject.Position, oldPos)) { SMSG_SHOWWEAPON spkt = new SMSG_SHOWWEAPON(); spkt.ActorID = this.character.id; spkt.AugeID = this.character.ComputeAugeSkill(); spkt.SessionId = regionObject.id; regionObject.client.Send((byte[])spkt); } } }
/// <summary> /// This function process all inventory interaction. For example to equip a /// item or a to switch item from your inventory to the storage. Because this /// is populair place to exploit we do some heavy loaded item checking. /// </summary> /// <param name="cpkt"></param> private void CM_MOVEITEM(CMSG_MOVEITEM cpkt) { if (cpkt.MovementType == 1) { #region EQUIPMENT TO INVENTORY SWAP int result = 0; Rag2Item[] Equips = this.character.Equipment; Rag2Collection Inventory = this.character.container; //PROCESS EQUIPMENT SWAPPING int dest = 255; if (cpkt.DestinationIndex == 255) { Rag2Item temp = Equips[cpkt.SourceIndex]; dest = this.character.container.Add(temp); if (dest == -1) { result = 14; goto Notifycation; } Equips[cpkt.SourceIndex] = null; #warning "Equipment deapplied" temp.Activate(AdditionContext.Deapplied, this.character); Tasks.LifeCycle.Update(this.character); } else { Rag2Item temp2 = this.character.container[cpkt.DestinationIndex]; if (temp2 == null) { result = 16; goto Notifycation; } Rag2Item temp = Equips[cpkt.SourceIndex]; Equips[cpkt.SourceIndex] = temp2; this.character.container[cpkt.SourceIndex] = temp; #warning "Equipment applied/deapplied" temp.Activate(AdditionContext.Deapplied, this.character); temp2.Activate(AdditionContext.Reapplied, this.character); Tasks.LifeCycle.Update(this.character); } //MOVE THE ITEM SMSG_MOVEITEM spkt = new SMSG_MOVEITEM(); spkt.DestinationIndex = (byte)dest; spkt.SourceIndex = cpkt.SourceIndex; spkt.MovementType = cpkt.MovementType; spkt.SessionId = this.character.id; this.Send((byte[])spkt); Regiontree tree = this.character.currentzone.Regiontree; int SourceIndex = cpkt.SourceIndex; int ShieldIndex = (this.character.weapons.ActiveWeaponIndex == 1) ? 15 : 14; if (SourceIndex < 6 || SourceIndex == 8 || SourceIndex == ShieldIndex) foreach (Character regionObject in tree.SearchActors(SearchFlags.Characters)) { //FORWARD CHANGE TO ALL ACTORS Rag2Item equip = Equips[cpkt.SourceIndex]; SMSG_CHANGEEQUIPMENT spkt2 = new SMSG_CHANGEEQUIPMENT(); spkt2.Slot = cpkt.SourceIndex; spkt2.ActorID = this.character.id; spkt2.ItemID = (equip != null) ? equip.info.item : 0; spkt2.Dye = (byte)((equip != null) ? equip.dyecolor : 0); spkt2.SessionId = regionObject.id; regionObject.client.Send((byte[])spkt2); } Notifycation: //NOTIFY THE USER OF AN ERROR SMSG_MOVEREPLY spkt3 = new SMSG_MOVEREPLY(); spkt3.MovementType = cpkt.MovementType; spkt3.Message = (byte)result; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); #endregion EQUIPMENT TO INVENTORY SWAP } else if (cpkt.MovementType == 2) { #region INVENTORY TO EQUIPMENT SWAP //INVENTORY TO EQUIPMENT byte result = 0; Rag2Item[] Equips = this.character.Equipment; //CHECK INVENTORY ITEM Rag2Item InventoryItem = this.character.container[cpkt.SourceIndex]; if (InventoryItem == null) { result = 16; goto Notifycation; } //CHECK LEVEL if (this.character._level < InventoryItem.info.req_clvl) { result = 1; goto Notifycation; } //CHECK GENDER if ((InventoryItem.info.req_male + InventoryItem.info.req_female < 2) && ((InventoryItem.info.req_male == 1 && this.character.gender == 2) || (InventoryItem.info.req_female == 1 && this.character.gender == 1))) { result = 2; goto Notifycation; } //CHECK RACE if ((this.character.race == 1 && InventoryItem.info.req_norman == 1) || (this.character.race == 2 && InventoryItem.info.req_ellr == 1) || (this.character.race == 3 && InventoryItem.info.req_dimago == 1)) { result = 3; goto Notifycation; } //CHECK STRENGTH if (this.character.stats.CHARACTER.strength < InventoryItem.info.req_str) { result = 4; goto Notifycation; } //CHECK DEXTERITY if (this.character.stats.CHARACTER.dexterity < InventoryItem.info.req_dex) { result = 5; goto Notifycation; } //CHECK CONCENCENTRATION if (this.character.stats.CHARACTER.concentration < InventoryItem.info.req_con) { result = 6; goto Notifycation; } //CHECK LUCK if (this.character.stats.CHARACTER.luck < InventoryItem.info.req_luc) { result = 7; goto Notifycation; } //CHECK JOB //UNSEAL THE ITEM if (InventoryItem.tradeable == true) { InventoryItem.tradeable = false; SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Container = 2; spkt.Index = cpkt.SourceIndex; spkt.UpdateReason = (byte)ItemUpdateReason.NoReason; spkt.UpdateType = 7; spkt.Amount = 1; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } //EVERYTHING IS OKAY PROCESS SWAPPING { InventoryItem.active = 1; SMSG_MOVEITEM spkt = new SMSG_MOVEITEM(); spkt.DestinationIndex = cpkt.DestinationIndex; spkt.SourceIndex = cpkt.SourceIndex; spkt.MovementType = cpkt.MovementType; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } //PROCESS EQUIPMENT SWAPPING Rag2Item temp = Equips[cpkt.DestinationIndex]; Equips[cpkt.DestinationIndex] = this.character.container[cpkt.SourceIndex]; if (temp != null) { this.character.container[cpkt.SourceIndex] = temp; temp.Activate(AdditionContext.Deapplied, this.character); InventoryItem.Activate(AdditionContext.Applied, this.character); Tasks.LifeCycle.Update(this.character); } else { this.character.container.RemoveAt(cpkt.SourceIndex); InventoryItem.Activate(AdditionContext.Applied, this.character); Tasks.LifeCycle.Update(this.character); } Regiontree tree = this.character.currentzone.Regiontree; int DestIndex = cpkt.DestinationIndex; int ShieldIndex = (this.character.weapons.ActiveWeaponIndex == 1) ? 15 : 14; if (DestIndex < 6 || DestIndex == 8 || DestIndex == ShieldIndex) foreach (Character regionObject in tree.SearchActors(SearchFlags.Characters)) { //FORWARD CHANGE TO ALL ACTORS Rag2Item equip = Equips[cpkt.DestinationIndex]; SMSG_CHANGEEQUIPMENT spkt2 = new SMSG_CHANGEEQUIPMENT(); spkt2.Slot = cpkt.SourceIndex; spkt2.ActorID = this.character.id; spkt2.ItemID = (equip != null) ? equip.info.item : 0; spkt2.Dye = (byte)((equip != null) ? equip.dyecolor : 0); regionObject.client.Send((byte[])spkt2); } Notifycation: //NOTIFY THE USER OF AN ERROR SMSG_MOVEREPLY spkt3 = new SMSG_MOVEREPLY(); spkt3.MovementType = cpkt.MovementType; spkt3.Message = result; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); #endregion INVENTORY TO EQUIPMENT SWAP } else if (cpkt.MovementType == 3) { #region INVENTORY TO STORAGE SWAP //STORAGE TO INVENTORY byte result = 0; //CHECK STORAGE ITEM Rag2Item storageItem = null; Rag2Item invenItem = this.character.container[cpkt.SourceIndex]; if (invenItem == null) { result = 16; goto Notifycation; } //CHECK PROVIDED AMOUNT if (cpkt.Amount > invenItem.count) { result = 25; goto Notifycation; } //CHECK MAX STACK LIMITS if (cpkt.Amount > invenItem.info.max_stack) { result = 24; goto Notifycation; } //CHECK DESTINATION if (cpkt.DestinationIndex == 255) { if (this.character.STORAGE.Count == this.character.STORAGE.Capacity) { result = 17; goto Notifycation; } } else { storageItem = this.character.STORAGE[cpkt.DestinationIndex]; if (storageItem == null) { result = 19; goto Notifycation; } if (storageItem.Equals(invenItem)) { result = 23; goto Notifycation; } if (storageItem.count + cpkt.Amount > invenItem.info.max_stack) { result = 24; goto Notifycation; } } //PROCESS MOVEMENT - PART 1 if (cpkt.DestinationIndex == 255) { storageItem = invenItem.Clone(cpkt.Amount); int index = this.character.STORAGE.Add(storageItem); SMSG_ADDITEM spkt4 = new SMSG_ADDITEM(); spkt4.Container = 3; spkt4.SessionId = this.character.id; spkt4.UpdateReason = 0; spkt4.SetItem(invenItem, index); this.Send((byte[])spkt4); } else { storageItem.count += cpkt.Amount; SMSG_UPDATEITEM spkt4 = new SMSG_UPDATEITEM(); spkt4.Amount = (byte)storageItem.count; spkt4.Container = 3; spkt4.Index = cpkt.DestinationIndex; spkt4.UpdateReason = 0; spkt4.UpdateType = 2; this.Send((byte[])spkt4); } //PROCESS MOVEMENT - PART 2 int nCount = invenItem.count - cpkt.Amount; if (nCount > 0) { invenItem.count = nCount; SMSG_UPDATEITEM spkt4 = new SMSG_UPDATEITEM(); spkt4.Amount = (byte)nCount; spkt4.Container = 2; spkt4.Index = cpkt.SourceIndex; spkt4.UpdateReason = (byte)ItemUpdateReason.StorageSent; spkt4.UpdateType = 2; this.Send((byte[])spkt4); } else { this.character.container.RemoveAt(cpkt.SourceIndex); SMSG_DELETEITEM spkt2 = new SMSG_DELETEITEM(); spkt2.Container = 2; spkt2.Index = cpkt.SourceIndex; spkt2.UpdateReason = (byte)ItemUpdateReason.StorageSent; spkt2.SessionId = this.character.id; this.Send((byte[])spkt2); } Notifycation: SMSG_MOVEREPLY spkt3 = new SMSG_MOVEREPLY(); spkt3.Message = (byte)result; spkt3.MovementType = cpkt.MovementType; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); //Type is used to calc type of item //(21 seems to be used for Applogy Item) if (result == 0 && invenItem.info.type == 21) { Common.Skills.UpdateAddition(this.character, 101); } #endregion INVENTORY TO STORAGE SWAP } else if (cpkt.MovementType == 4) { #region STORAGE TO INVENTORY SWAP //CHECK STORAGE ITEM int result = 0; Rag2Item invenItem = null; Rag2Item storageItem = this.character.STORAGE[cpkt.SourceIndex]; if (storageItem == null) { result = 19; goto Notifycation; } //CHECK PROVIDED AMOUNT if (cpkt.Amount > storageItem.count) { result = 25; goto Notifycation; } //CHECK MAX STACK LIMITS if (cpkt.Amount > storageItem.info.max_stack) { result = 24; goto Notifycation; } //CHECK DESTINATION if (cpkt.DestinationIndex == 255) { if (this.character.container.Count == this.character.container.Capacity) { result = 14; goto Notifycation; } } else { invenItem = this.character.container[cpkt.DestinationIndex]; if (invenItem == null) { result = 16; goto Notifycation; } if (invenItem.Equals(storageItem)) { result = 23; goto Notifycation; } if (invenItem.count + cpkt.Amount > storageItem.info.max_stack) { result = 24; goto Notifycation; } } //PROCESS MOVEMENT - PART 1 if (cpkt.DestinationIndex == 255) { invenItem = storageItem.Clone(cpkt.Amount); int index = this.character.container.Add(invenItem); SMSG_ADDITEM spkt4 = new SMSG_ADDITEM(); spkt4.Container = 2; spkt4.SessionId = this.character.id; spkt4.UpdateReason = (byte)ItemUpdateReason.StorageReceived; spkt4.SetItem(invenItem, index); this.Send((byte[])spkt4); } else { invenItem.count += cpkt.Amount; SMSG_UPDATEITEM spkt4 = new SMSG_UPDATEITEM(); spkt4.Amount = (byte)invenItem.count; spkt4.Container = 2; spkt4.Index = cpkt.DestinationIndex; spkt4.UpdateReason = (byte)ItemUpdateReason.StorageReceived; spkt4.UpdateType = 2; this.Send((byte[])spkt4); } //PROCESS MOVEMENT - PART 2 int nCount = storageItem.count - cpkt.Amount; if (nCount > 0) { storageItem.count = nCount; SMSG_UPDATEITEM spkt4 = new SMSG_UPDATEITEM(); spkt4.Amount = (byte)nCount; spkt4.Container = 3; spkt4.Index = cpkt.SourceIndex; spkt4.UpdateReason = 0; spkt4.UpdateType = 2; this.Send((byte[])spkt4); } else { this.character.STORAGE.RemoveAt(cpkt.SourceIndex); SMSG_DELETEITEM spkt2 = new SMSG_DELETEITEM(); spkt2.Container = 3; spkt2.Index = cpkt.SourceIndex; spkt2.UpdateReason = 0; spkt2.SessionId = this.character.id; this.Send((byte[])spkt2); } Notifycation: SMSG_MOVEREPLY spkt3 = new SMSG_MOVEREPLY(); spkt3.MovementType = cpkt.MovementType; spkt3.Message = (byte)result; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); //Type is used to calc type of item //(21 seems to be used for Applogy Item) if (result == 0 && invenItem.info.type == 21) { Common.Skills.UpdateAddition(this.character, 101); } #endregion STORAGE TO INVENTORY SWAP } }
/// <summary> /// Resets your characters stats. /// </summary> /// <param name="cpkt"></param> private void CM_USESTATRESETITEM(CMSG_STATRESETPOTION cpkt) { Rag2Item InventoryItem = this.character.container[cpkt.SlotId]; if (InventoryItem != null) { //Update stats lock (this.character.stats) { Saga.PrimaryTypes.CharacterStats.Stats stats = this.character.stats.CHARACTER; int remaining = stats.concentration + stats.dexterity + stats.intelligence + stats.strength + this.character.stats.REMAINING; lock (character._status) { //Update strength character._status.MaxPAttack -= (ushort)(2 * stats.strength); character._status.MinPAttack -= (ushort)(1 * stats.strength); character._status.MaxHP -= (ushort)(10 * stats.strength); stats.strength = 0; //Update Dextericty character._status.BaseMHitrate -= (ushort)(1 * stats.dexterity); stats.dexterity = 0; //Update Intellect character._status.MaxMAttack -= (ushort)(6 * stats.intelligence); character._status.MinMAttack -= (ushort)(3 * stats.intelligence); character._status.BaseRHitrate -= (ushort)(1 * stats.intelligence); stats.intelligence = 0; //Update Concentration character._status.MaxRAttack -= (ushort)(4 * stats.concentration); character._status.MinRAttack -= (ushort)(2 * stats.concentration); character._status.BasePHitrate -= (ushort)(2 * stats.concentration); stats.concentration = 0; this.character.stats.REMAINING = (ushort)remaining; } } //Reset stat points SMSG_EXTSTATS spkt = new SMSG_EXTSTATS(); spkt.base_stats_1 = character.stats.BASE; spkt.base_stats_2 = character.stats.CHARACTER; spkt.base_stats_jobs = character.stats.EQUIPMENT; spkt.base_stats_bonus = character.stats.ENCHANTMENT; spkt.statpoints = character.stats.REMAINING; spkt.SessionId = character.id; this.Send((byte[])spkt); //Use the item int newLength = InventoryItem.count - 1; if (newLength > 0) { InventoryItem.count = newLength; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)newLength; spkt2.UpdateReason = 0; spkt2.UpdateType = 4; spkt2.Container = 2; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.SlotId; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.SlotId); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 0; spkt3.Container = 2; spkt3.Index = cpkt.SlotId; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } } }
/// <summary> /// Uses a supplement stone. /// </summary> /// <param name="cpkt"></param> private void CM_USESUPLEMENTSTONE(CMSG_USESUPPLEMENTSTONE cpkt) { //TODO: ADD HANDLER SO SUPPLY STONES TAKE EFFECT byte result = 0; uint skill = 0; try { Rag2Item Supplement = this.character.container[cpkt.IventoryId]; Rag2Item Equipment = (cpkt.Container == 1) ? this.character.container[cpkt.ContainerSlot] : this.character.Equipment[cpkt.ContainerSlot]; bool IsEquipmentItem = cpkt.Container != 1; if (Supplement == null || Equipment == null) { result = (byte)Generalerror.ItemEnchantmentFailed; } else { skill = Supplement.info.skill; //If it is a equipment item and activated //(active is set to 0 if durabillity is 0 or doesn't meet job criteria) if (IsEquipmentItem && Equipment.active == 1) { uint oldskill = Equipment.Enchantments[cpkt.EnchantmentSlot]; if (oldskill > 0) { #warning "Skill Deapplied" Factory.Spells.Info info1; Factory.Additions.Info info2; if (skill > 0) { if (Singleton.SpellManager.TryGetSpell(oldskill, out info1) && Singleton.Additions.TryGetAddition(info1.addition, out info2)) { info2.Do(character, character, AdditionContext.Deapplied); } } } if (skill > 0) { #warning "Skill Applied" Factory.Spells.Info info1; Factory.Additions.Info info2; if (skill > 0) { if (Singleton.SpellManager.TryGetSpell(skill, out info1) && Singleton.Additions.TryGetAddition(info1.addition, out info2)) { info2.Do(character, character, AdditionContext.Applied); } } } } Equipment.Enchantments[cpkt.EnchantmentSlot] = skill; int newLength = Supplement.count - 1; if (newLength > 0) { Supplement.count = newLength; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)newLength; spkt2.UpdateReason = 0; spkt2.UpdateType = 4; spkt2.Container = 2; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.IventoryId; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.IventoryId); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 0; spkt3.Container = 2; spkt3.Index = cpkt.IventoryId; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } } } catch (Exception e) { Console.WriteLine(e); result = (byte)Generalerror.ItemEnchantmentFailed; } finally { SMSG_USESUPPLEMENTSTONE spkt = new SMSG_USESUPPLEMENTSTONE(); spkt.Result = result; spkt.InventoryId = cpkt.IventoryId; spkt.Container = cpkt.Container; spkt.ContainerSlot = cpkt.ContainerSlot; spkt.EnchantmentSlot = cpkt.EnchantmentSlot; spkt.Skill = skill; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } }
/// <summary> /// Uses a map item to unhide a hidden region. /// </summary> /// <remarks> /// As a programmer would know a byte had eight bits. /// Each bit represents a region that can be unhidden. /// These bit's are invered however, so 128 means first /// region is unhidden. While 255 would mean all eight /// regions are unhiden. /// /// 128 = 7 = Region 1 /// 64 = 6 = Region 2 /// 32 = 5 = Region 3 /// 16 = 4 = Region 4 /// 8 = 3 = Region 5 /// 4 = 2 = Region 6 /// 2 = 1 = Region 7 /// 1 = 0 = Region 8 /// /// </remarks> /// <param name="cpkt"></param> private void CM_USEMAPITEM(CMSG_USEMAP cpkt) { Rag2Item item = character.container[cpkt.Index]; byte result = 0; byte map = 0; byte zone = 0; int value = 0; try { if (item != null) { map = (byte)(item.info.skill / 10); zone = (byte)(item.info.skill % 10); value = (int)Math.Pow(2, (8 - zone)); //ALREADY LEARNED if ((this.character.ZoneInformation[map] & value) == value) { result = 1; } //EVERYTHING IS OKAY else { //UPDATE ITEM COUNT int newLength = item.count - 1; if (newLength > 0) { item.count = newLength; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)newLength; spkt2.UpdateReason = 0; spkt2.UpdateType = 4; spkt2.Container = 2; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.Index; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 0; spkt3.Container = 2; spkt3.Index = cpkt.Index; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } //UPDATE MAP STATE this.character.ZoneInformation[map] |= (byte)value; } } } catch (Exception e) { result = 1; Console.WriteLine(e); } finally { SMSG_SHOWMAP spkt = new SMSG_SHOWMAP(); spkt.Reason = result; spkt.Map = map; spkt.Zone = zone; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } }
/// <summary> /// Occurs when sorting the inventory /// </summary> /// <param name="cpkt"></param> private void CM_IVENTORY_SORT(CMSG_SORTINVENTORYLIST cpkt) { if (cpkt.SortType > 1) return; for (int i = 0; i < this.character.container.Capacity; i++) { Rag2Item a = character.container[i]; if (a == null) continue; Predicate<KeyValuePair<byte, Rag2Item>> FindRag2Items = delegate(KeyValuePair<byte, Rag2Item> b) { return b.Value.info == a.info && b.Value.clvl == a.clvl; }; bool result = false; int count = a.info.max_stack - a.count; List<KeyValuePair<byte, Rag2Item>> items = new List<KeyValuePair<byte, Rag2Item>>(); foreach (KeyValuePair<byte, Rag2Item> b in this.character.container.GetAllItems(FindRag2Items)) { if (b.Value.count < b.Value.info.max_stack && b.Key != i) items.Add(b); } foreach (KeyValuePair<byte, Rag2Item> b in items) { if (b.Value.count > count) { a.count = a.info.max_stack; b.Value.count -= count; count = 0; SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Container = 2; spkt.UpdateType = 4; spkt.SessionId = this.character.id; spkt.Index = b.Key; spkt.Amount = (byte)b.Value.count; spkt.UpdateReason = 0; this.Send((byte[])spkt); result = true; break; } else { a.count += b.Value.count; count -= b.Value.count; this.character.container.RemoveAt(b.Key); SMSG_DELETEITEM spkt = new SMSG_DELETEITEM(); spkt.Index = b.Key; spkt.UpdateReason = 0; spkt.SessionId = this.character.id; spkt.Container = 2; result = true; this.Send((byte[])spkt); } } if (result == true) { SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Container = 2; spkt.UpdateType = 4; spkt.SessionId = this.character.id; spkt.Index = (byte)i; spkt.Amount = (byte)a.count; spkt.UpdateReason = 0; this.Send((byte[])spkt); } } }
/// <summary> /// Sends a new mail message /// </summary> private void CM_NEWMAILITEM(CMSG_SENDMAIL cpkt) { //HELPER VARIABLES byte result = 1; uint req_zeny = 0; Rag2Item item = null; MailItem mailmessage = new MailItem(); mailmessage.Content = cpkt.Content; mailmessage.Recieptent = cpkt.Name; mailmessage.Topic = cpkt.Topic; mailmessage.item = item; if ((cpkt.HasItem & 2) == 2) { item = this.character.container[cpkt.Slot]; if (item != null) { req_zeny = 10; mailmessage.item = item.Clone(cpkt.StackCount); } } if ((cpkt.HasItem & 1) == 1) { req_zeny = 10 + cpkt.Zeny; mailmessage.Zeny = cpkt.Zeny; } try { //RECIEVER DOES NOT EXISTS if (!Singleton.Database.VerifyNameExists(mailmessage.Recieptent)) { result = 2; } //NOT ENOUGH MONEY else if (this.character.ZENY < req_zeny) { result = 3; } //CHECK ITEM INVENTORY else if (item != null && cpkt.StackCount > item.count) { result = 5; } //CHECK IF OWNER OUTBOX IF FULL else if (Singleton.Database.GetInboxMailCount(this.character.Name) == 20) { result = 6; } //CHECK IF SENDER INBOX IS FULL else if (Singleton.Database.GetInboxMailCount(mailmessage.Recieptent) == 20) { result = 7; } //DATABASE ERROR else if (!Singleton.Database.InsertNewMailItem(this.character, mailmessage)) { result = 1; } //EVERYTHING IS OKAY else { if (cpkt.HasItem > 0) { this.character.ZENY -= req_zeny; CommonFunctions.UpdateZeny(this.character); } //UPDATE ITEM COUNT AS FORM OF A ATTACHMENT if ((cpkt.HasItem & 2) == 2) { item.count -= cpkt.StackCount; if (item.count > 0) { SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Amount = (byte)item.count; spkt.UpdateReason = (byte)ItemUpdateReason.AttachmentReceived; spkt.UpdateType = 4; spkt.Container = 2; spkt.SessionId = this.character.id; spkt.Index = cpkt.Slot; this.Send((byte[])spkt); } else { this.character.container.RemoveAt(cpkt.Slot); SMSG_DELETEITEM spkt = new SMSG_DELETEITEM(); spkt.Container = 2; spkt.Index = cpkt.Slot; spkt.UpdateReason = (byte)ItemUpdateReason.AttachmentReceived; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } } //EVERYTHING OKAY result = 0; } } finally { SMSG_MAILSENDAWNSER spkt = new SMSG_MAILSENDAWNSER(); spkt.Result = result; spkt.SessionId = cpkt.SessionId; this.Send((byte[])spkt); } }
/// <summary> /// Learns a new skill from a skillbook /// </summary> /// <param name="cpkt"></param> private void CM_SKILLS_LEARNFROMSKILLBOOK(CMSG_SKILLLEARN cpkt) { byte result = 1; try { Saga.Factory.Spells.Info spellinfo; Rag2Item item = character.container[cpkt.Index]; if (item != null) { //Helpers predicates Predicate<Skill> FindSkill = delegate(Skill skill) { return skill.Id == item.info.skill; }; Predicate<Skill> FindPreviousSkill = delegate(Skill skill) { return skill.Id == item.info.skill - 1; }; //HELPER VARIABLES uint baseskill = (item.info.skill / 100) * 100 + 1; int newLength = character.container[cpkt.Index].count - 1; List<Skill> learnedSpells = this.character.learnedskills; Singleton.SpellManager.TryGetSpell(item.info.skill, out spellinfo); Skill CurrentSkill = learnedSpells.FindLast(FindSkill); Skill PreviousSkill = learnedSpells.FindLast(FindPreviousSkill); bool IsBaseSkill = item.info.skill == baseskill; //CHECK IF THE CURRENT JOB CAN LEARN THE SPELL if (item.info.JobRequirement[this.character.job - 1] > this.character.jlvl) { result = (byte)Generalerror.ConditionsNotMet; } //CHECK IF WE ALREADY LEARNED THE SPELL else if (CurrentSkill != null) { result = (byte)Generalerror.AlreadyLearntSkill; } //CHECK IF A PREVIOUS SKILL WAS FOUND else if (!IsBaseSkill && PreviousSkill == null) { result = (byte)Generalerror.PreviousSkillNotFound; } //CHECK SKILL EXP else if (PreviousSkill != null && PreviousSkill.Experience < PreviousSkill.info.maximumexperience) { result = (byte)Generalerror.NotEnoughSkillExperience; } else { //ADD A NEW SKILL if (IsBaseSkill) { //Passive skill bool canUse = Singleton.SpellManager.CanUse(this.character, spellinfo); if (spellinfo.skilltype == 2 && canUse) { Singleton.Additions.ApplyAddition(spellinfo.addition, this.character); int ActiveWeaponIndex = (this.character.weapons.ActiveWeaponIndex == 1) ? this.character.weapons.SeconairyWeaponIndex : this.character.weapons.PrimaryWeaponIndex; if (ActiveWeaponIndex < this.character.weapons.UnlockedWeaponSlots) { Weapon weapon = this.character.weapons[ActiveWeaponIndex]; if ((baseskill - 1) == weapon.Info.weapon_skill) { BattleStatus status = character._status; status.MaxWMAttack += (ushort)weapon.Info.max_magic_attack; status.MinWMAttack += (ushort)weapon.Info.min_magic_attack; status.MaxWPAttack += (ushort)weapon.Info.max_short_attack; status.MinWPAttack += (ushort)weapon.Info.min_short_attack; status.MaxWRAttack += (ushort)weapon.Info.max_range_attack; status.MinWRAttack += (ushort)weapon.Info.min_range_attack; status.Updates |= 2; } } } Singleton.Database.InsertNewSkill(this.character, item.info.skill, spellinfo.maximumexperience); CurrentSkill = new Skill(); CurrentSkill.info = spellinfo; CurrentSkill.Id = item.info.skill; CurrentSkill.Experience = spellinfo.maximumexperience; learnedSpells.Add(CurrentSkill); } //UPDATE A OLD SKILL else { //Passive skill if (spellinfo.skilltype == 2) { Saga.Factory.Spells.Info oldSpellinfo; Singleton.SpellManager.TryGetSpell(PreviousSkill.info.skillid, out oldSpellinfo); bool canUseOld = Singleton.SpellManager.CanUse(this.character, oldSpellinfo); bool canUseNew = Singleton.SpellManager.CanUse(this.character, spellinfo); if (canUseOld) { Singleton.Additions.DeapplyAddition(oldSpellinfo.addition, this.character); } if (canUseNew) { Singleton.Additions.ApplyAddition(spellinfo.addition, this.character); } } Singleton.Database.UpgradeSkill(this.character, PreviousSkill.info.skillid, item.info.skill, spellinfo.maximumexperience); PreviousSkill.info = spellinfo; PreviousSkill.Id = item.info.skill; PreviousSkill.Experience = spellinfo.maximumexperience; } SMSG_SKILLADD spkt2 = new SMSG_SKILLADD(); spkt2.Slot = 0; spkt2.SkillId = item.info.skill; spkt2.SessionId = this.character.id; this.Send((byte[])spkt2); if (newLength > 0) { this.character.container[cpkt.Index].count = newLength; SMSG_UPDATEITEM spkt = new SMSG_UPDATEITEM(); spkt.Amount = (byte)newLength; spkt.UpdateReason = 8; spkt.UpdateType = 4; spkt.Container = 2; spkt.SessionId = this.character.id; spkt.Index = cpkt.Index; this.Send((byte[])spkt); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt = new SMSG_DELETEITEM(); spkt.UpdateReason = 8; spkt.Container = 2; spkt.Index = cpkt.Index; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } Common.Internal.CheckWeaponary(this.character); Tasks.LifeCycle.Update(this.character); result = 0; } } } finally { //OUTPUT THE RESULT SMSG_SKILLLEARN spkt = new SMSG_SKILLLEARN(); spkt.Result = result; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } }
/// <summary> /// Occurs when using a item that uses a skill /// </summary> /// <param name="cpkt"></param> private void CM_ITEMTOGGLE(CMSG_ITEMTOGLE cpkt) { lock (this.character.cooldowncollection) { try { Rag2Item item = this.character.container[cpkt.Index]; MapObject target; uint skillid = cpkt.SkillID; byte skilltype = cpkt.SkillType; ItemSkillUsageEventArgs argument = null; bool cancast = Regiontree.TryFind(cpkt.TargetActor, this.character, out target) && ItemSkillUsageEventArgs.Create(item, this.character, target, out argument) && argument.SpellInfo.casttime > -1 && (argument.SpellInfo.casttime == 0 || this.character._lastcastedskill == skillid) && ((long)((uint)Environment.TickCount) - this.character._lastcastedtick) > 0 && (argument.SpellInfo.delay == 0 || !this.character.cooldowncollection.IsCoolDown(skillid)) && (argument.SpellInfo.maximumrange == 0 || argument.SpellInfo.IsInRangeOf((int)(Vector.GetDistance2D(this.character.Position, target.Position)))) && argument.SpellInfo.requiredWeapons[this.character.weapons.GetCurrentWeaponType()] == 1 && this.character.jlvl > argument.SpellInfo.requiredJobs[this.character.job - 1] && argument.SpellInfo.IsTarget(this.character, target) && item.count > 0; if (cancast && argument.Use()) { int delay = (int)(argument.SpellInfo.delay - ((character.stats.Dexterity * 2) + (character.stats.Concentration * 2))); if (delay > 0) this.character.cooldowncollection.Add(skillid, delay); this.character.cooldowncollection.Update(); int newLength = this.character.container[cpkt.Index].count - 1; if (newLength > 0) { this.character.container[cpkt.Index].count = newLength; SMSG_UPDATEITEM spkt2 = new SMSG_UPDATEITEM(); spkt2.Amount = (byte)newLength; spkt2.UpdateReason = 8; spkt2.UpdateType = 4; spkt2.Container = 2; spkt2.SessionId = this.character.id; spkt2.Index = cpkt.Index; this.Send((byte[])spkt2); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 8; spkt3.Container = 2; spkt3.Index = cpkt.Index; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } //Preprocess packet SMSG_ITEMTOGGLE spkt = new SMSG_ITEMTOGGLE(); spkt.Container = cpkt.Container; spkt.SkillMessage = (byte)argument.Result; spkt.Index = cpkt.Index; spkt.SkillID = cpkt.SkillID; spkt.SkillType = cpkt.SkillType; spkt.SourceActor = this.character.id; spkt.TargetActor = cpkt.TargetActor; spkt.Value = argument.Damage; //Send packets in one-mighty blow Regiontree tree = this.character.currentzone.Regiontree; foreach (Character regionObject in tree.SearchActors(this.character, SearchFlags.Characters)) { if (character.client.isloaded == false || !Point.IsInSightRangeByRadius(this.character.Position, regionObject.Position)) continue; spkt.SessionId = target.id; regionObject.client.Send((byte[])spkt); } } } catch (Exception) { Trace.TraceError("Error processing item skill"); } } }