public static bool GiveItem(Character character, uint item, byte count) { Rag2Item iventoryitem; if (Singleton.Item.TryGetItemWithCount(item, count, out iventoryitem)) { int index = character.container.Add(iventoryitem); if (index > -1) { character.container[index] = iventoryitem; SMSG_ADDITEM spkt = new SMSG_ADDITEM(); spkt.Container = 2; spkt.UpdateReason = 0; spkt.SetItem(iventoryitem, index); spkt.SessionId = character.id; character.client.Send((byte[])spkt); QuestBase.UserObtainedItem(item, character); return true; } } return false; }
/// <title>Saga.AddStep</title> /// <code> /// Saga.AddStep(cid, QuestID, StepId, State); /// </code> /// <description> /// Adds a step to the quest. This can only be done during initialisation. /// 0 = Hidden, 1 = Visible, 2 = Completed /// </description> /// <example> ///function QUEST_START(cid) /// -- Initialize all quest steps /// -- Initialize all starting navigation points /// /// Saga.AddStep(cid, QuestID, 101, 1); /// Saga.AddStep(cid, QuestID, 102, 0); /// Saga.AddStep(cid, QuestID, 103, 0); /// Saga.InsertQuest(cid, QuestID, 1); /// /// return 0; ///end /// </example> public static bool NpcGiveItem(uint CID, uint ItemId, byte ItemCount) { Character value; if (LifeCycle.TryGetById(CID, out value)) { Rag2Item item; if (Singleton.Item.TryGetItemWithCount(ItemId, ItemCount, out item)) { int index = value.container.Add(item); if (index > -1) { SMSG_ADDITEM spkt = new SMSG_ADDITEM(); spkt.Container = 2; spkt.SessionId = value.id; spkt.UpdateReason = (byte)ItemUpdateReason.ReceiveFromNpc; spkt.SetItem(item, index); value.client.Send((byte[])spkt); return true; } } } return false; }
/// <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 function occurs when you want to buy a item. /// </summary> /// <param name="cpkt"></param> private void CM_NPCINTERACTION_SHOPBUY(CMSG_NPCSHOPBUY cpkt) { BaseNPC npc = this.character.Target as BaseNPC; BaseShopCollection list = this.character.Tag as BaseShopCollection; if (npc != null && list != null) { //OBTAIN THE REQUIRED ITEMS FROM THE MERCHANT BaseShopCollection.ShopPair pair = list.list[cpkt.Index]; if (pair == null) return; Rag2Item item = pair.item; if (item == null) return; //REQUIRED DEPENDECIES int req_slots = 1; uint req_money = item.info.price * cpkt.Amount; //CHECK IF PLAYER HAS ENOUGH MONEY if (this.character.ZENY < req_money) { Common.Errors.GeneralErrorMessage(this.character, 2); return; } //CHECK MERCHANTS MONEY else if (this.character.container.Count + req_slots > this.character.container.Capacity) { Common.Errors.GeneralErrorMessage(this.character, 1); return; } else { //UPDATE ZENY this.character.ZENY -= req_money; npc.Zeny += req_money; CommonFunctions.UpdateZeny(this.character); CommonFunctions.UpdateShopZeny(this.character); //AMOUNT USED IN DECREMENT CALCULATIONS int amount = (int)cpkt.Amount; int index = this.character.container.FindFirstFreeIndex(); if (index > -1) { Rag2Item invItem = item.Clone(amount); this.character.container[index] = invItem; SMSG_ADDITEM spkt = new SMSG_ADDITEM(); spkt.Container = 2; spkt.UpdateReason = 2; spkt.SetItem(invItem, index); 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); } } //If the item has a limited stock if (pair.NoStock == false) { item.count -= (int)cpkt.Amount; list.Open(this.character, npc); } } } }
/// <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> /// Occurs when retrieving item attachement from the id. /// </summary> /// <param name="cpkt"></param> private void CM_RETRIEVEITEMATTACHMENT(CMSG_GETITEMATTACHMENT cpkt) { byte result = 0; try { Rag2Item item = Singleton.Database.GetItemAttachment(cpkt.MailId); //No attachment if (item == null) { result = 1; } //Not the same item type else if (item.info.item != cpkt.ItemId) { result = 1; } //Not enough space else if (this.character.container.Count == this.character.container.Capacity) { result = 1; } //Update the database else if (Singleton.Database.UpdateItemAttachment(cpkt.MailId, null) == false) { result = 1; } //Everything is okay else { int index = this.character.container.Add(item); SMSG_ADDITEM spkt = new SMSG_ADDITEM(); spkt.Container = 2; spkt.UpdateReason = (byte)ItemUpdateReason.AttachmentSent; spkt.SessionId = this.character.id; spkt.SetItem(item, index); this.Send((byte[])spkt); } } finally { SMSG_MAILITEMAWNSER spkt = new SMSG_MAILITEMAWNSER(); spkt.SessionId = cpkt.SessionId; spkt.Result = result; this.Send((byte[])spkt); } }