/// <summary> /// Occurs when you switch between weapons (primary -> secondary) /// </summary> private void CM_WEAPONSWITCH(CMSG_WEAPONSWITCH cpkt) { //Helper variables byte prev_weapontype = 0; byte next_weapontype = 0; //Deapplies the currrent stats lock (this.character._status) { int WeaponIndex = (this.character.weapons.ActiveWeaponIndex == 1) ? this.character.weapons.SeconairyWeaponIndex : this.character.weapons.PrimaryWeaponIndex; if (WeaponIndex < this.character.weapons.UnlockedWeaponSlots) { Weapon CurrentWeapon = this.character.weapons[WeaponIndex]; prev_weapontype = CurrentWeapon._weapontype; if (CurrentWeapon != null && CurrentWeapon._active == 1) { //Deapplies the weapon stats this.character._status.MaxWMAttack -= (ushort)CurrentWeapon.Info.max_magic_attack; this.character._status.MinWMAttack -= (ushort)CurrentWeapon.Info.min_magic_attack; this.character._status.MaxWPAttack -= (ushort)CurrentWeapon.Info.max_short_attack; this.character._status.MinWPAttack -= (ushort)CurrentWeapon.Info.min_short_attack; this.character._status.MaxWRAttack -= (ushort)CurrentWeapon.Info.max_range_attack; this.character._status.MinWRAttack -= (ushort)CurrentWeapon.Info.min_range_attack; this.character._status.Updates |= 2; //Deapplies the fusion stone if (CurrentWeapon._fusion > 0) Common.Skills.DeleteStaticAddition(this.character, CurrentWeapon._fusion); //Deapplies alterstone additions for (int i = 0; i < 8; i++) { uint addition = CurrentWeapon.Slots[i]; if (addition > 0) { Singleton.Additions.DeapplyAddition(addition, character); } } } } } //Toggles the weapons index this.character.weapons.ActiveWeaponIndex ^= 1; int ShieldIndex = (this.character.weapons.ActiveWeaponIndex == 1) ? 15 : 14; Rag2Item shield = this.character.Equipment[ShieldIndex]; lock (this.character._status) { int NewWeaponIndex = (this.character.weapons.ActiveWeaponIndex == 1) ? this.character.weapons.SeconairyWeaponIndex : this.character.weapons.PrimaryWeaponIndex; if (NewWeaponIndex < this.character.weapons.UnlockedWeaponSlots) { //Apples the battle stats Weapon CurrentWeapon = this.character.weapons[NewWeaponIndex]; next_weapontype = CurrentWeapon._weapontype; if (CurrentWeapon != null && CurrentWeapon._active == 1) { this.character._status.MaxWMAttack += (ushort)CurrentWeapon.Info.max_magic_attack; this.character._status.MinWMAttack += (ushort)CurrentWeapon.Info.min_magic_attack; this.character._status.MaxWPAttack += (ushort)CurrentWeapon.Info.max_short_attack; this.character._status.MinWPAttack += (ushort)CurrentWeapon.Info.min_short_attack; this.character._status.MaxWRAttack += (ushort)CurrentWeapon.Info.max_range_attack; this.character._status.MinWRAttack += (ushort)CurrentWeapon.Info.min_range_attack; this.character._status.Updates |= 2; } //Reapplies the fusion stone if (CurrentWeapon._fusion > 0) Common.Skills.CreateAddition(this.character, CurrentWeapon._fusion); //Reapplies alterstone additions for (int i = 0; i < 8; i++) { uint addition = CurrentWeapon.Slots[i]; if (addition > 0) { Singleton.Additions.DeapplyAddition(addition, character); } } } if (prev_weapontype != next_weapontype) { foreach (Skill skill in this.character.learnedskills) { //If it's a pasive skill if (skill.info.skilltype == 2) { bool PreviousAble = skill.info.requiredWeapons[prev_weapontype] == 1; bool NextAble = skill.info.requiredWeapons[next_weapontype] == 1; if (PreviousAble == false && NextAble == true) { Singleton.Additions.ApplyAddition(skill.info.addition, this.character); this.character._status.Updates |= 2; } else if (NextAble == false && PreviousAble == true) { Singleton.Additions.DeapplyAddition(skill.info.addition, this.character); this.character._status.Updates |= 2; } } } } } //Switch the weapons Point oldPos = this.character.Position; Regiontree tree = this.character.currentzone.Regiontree; foreach (Character regionObject in tree.SearchActors(this.character, SearchFlags.Characters)) { if (regionObject.id == this.character.id) { SMSG_WEAPONSWITCH spkt = new SMSG_WEAPONSWITCH(); spkt.slotid = cpkt.slotid; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } else if (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); SMSG_CHANGEEQUIPMENT spkt2 = new SMSG_CHANGEEQUIPMENT(); spkt2.ActorID = this.character.id; spkt2.Slot = (byte)ShieldIndex; spkt2.ItemID = (shield != null) ? shield.info.item : 0; spkt2.Dye = shield.dyecolor; spkt2.SessionId = regionObject.id; regionObject.client.Send((byte[])spkt2); } } //Does the switch Tasks.LifeCycle.Update(this.character); }
/// <summary> /// This function is sent when you use an dying item /// </summary> /// <param name="cpkt"></param> private void CM_USEDYEITEM(CMSG_USEDYEITEM cpkt) { Rag2Item dyeitem = null; Rag2Item item = null; byte result = 0; try { //Get the dyeitem dyeitem = this.character.container[cpkt.Index]; //Get the equipment item switch (cpkt.Container) { case 1: item = this.character.Equipment[cpkt.Slot]; break; case 2: item = this.character.container[cpkt.Slot]; break; case 3: item = this.character.STORAGE[cpkt.Slot]; break; } //Check if equipment is found if (item == null) { result = (byte)Generalerror.InventoryItemNotFound; } //Check if the dye is found else if (dyeitem == null) { result = (byte)Generalerror.InventoryItemNotFound; } //Everything is okay else { //Set the dye color switch (dyeitem.info.skill) { case 0: item.dyecolor = 0; break; //Nothing case 1: item.dyecolor = (byte)Saga.Utils.Generator.Random(2, 2); break; //red case 2: item.dyecolor = (byte)Saga.Utils.Generator.Random(10, 10); break; //Yellow case 3: item.dyecolor = (byte)Saga.Utils.Generator.Random(17, 17); break; //Green case 4: item.dyecolor = (byte)Saga.Utils.Generator.Random(21, 21); break; //Blue case 5: item.dyecolor = (byte)Saga.Utils.Generator.Random(34, 34); break; //Purple } //The appearance has changed bool IsEquipment = cpkt.Container == 1; Regiontree tree = this.character.currentzone.Regiontree; foreach (Character target in tree.SearchActors(this.character, SearchFlags.Characters)) { if (!Point.IsInSightRangeByRadius(this.character.Position, target.Position)) continue; if (target.id == this.character.id) { //Adjust the item SMSG_ITEMADJUST spkt2 = new SMSG_ITEMADJUST(); spkt2.Container = cpkt.Container; spkt2.Slot = cpkt.Slot; spkt2.Value = item.dyecolor; spkt2.Function = 6; spkt2.SessionId = this.character.id; this.Send((byte[])spkt2); } else if (IsEquipment) { SMSG_CHANGEEQUIPMENT spkt = new SMSG_CHANGEEQUIPMENT(); spkt.ActorID = this.character.id; spkt.ItemID = (item != null) ? item.info.item : 0; spkt.Dye = (item != null) ? (byte)item.dyecolor : (byte)0; spkt.Slot = cpkt.Slot; spkt.SessionId = target.id; target.client.Send((byte[])spkt); } } //Remove item if (dyeitem.count - 1 > 0) { dyeitem.count -= 1; SMSG_ITEMADJUST spkt3 = new SMSG_ITEMADJUST(); spkt3.Container = 2; spkt3.Slot = cpkt.Index; spkt3.Value = (byte)dyeitem.count; spkt3.Function = 4; spkt3.SessionId = this.character.id; this.Send((byte[])spkt3); } else { this.character.container.RemoveAt(cpkt.Index); SMSG_DELETEITEM spkt3 = new SMSG_DELETEITEM(); spkt3.UpdateReason = 0; spkt3.Index = cpkt.Index; spkt3.SessionId = this.character.id; spkt3.Container = 2; this.Send((byte[])spkt3); } } } finally { SMSG_USEDYEITEM spkt = new SMSG_USEDYEITEM(); if (dyeitem != null) spkt.ItemId = dyeitem.info.item; spkt.Equipment = cpkt.Slot; spkt.Container = cpkt.Container; spkt.Result = result; spkt.SessionId = this.character.id; this.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> /// Requests to change the job. /// </summary> /// <param name="cpkt"></param> private void CM_CHARACTER_JOBCHANGE(CMSG_CHANGEJOB cpkt) { JobChangeCollection collection = this.character.Tag as JobChangeCollection; if (collection == null || !collection.IsJobAvailable(cpkt.Job)) { //Job change failed SMSG_JOBCHANGED spkt = new SMSG_JOBCHANGED(); spkt.Job = this.character.job; spkt.Result = 1; spkt.SessionId = this.character.id; spkt.SourceActor = this.character.id; this.Send((byte[])spkt); return; } else if (collection.GetJobTrasferFee(cpkt.Job) > this.character.ZENY) { //Not enough money Common.Errors.GeneralErrorMessage(this.character, (uint)Generalerror.NotEnoughMoney); SMSG_JOBCHANGED spkt = new SMSG_JOBCHANGED(); spkt.Job = this.character.job; spkt.Result = 1; spkt.SessionId = this.character.id; spkt.SourceActor = this.character.id; this.Send((byte[])spkt); return; } else { this.character.ZENY -= collection.GetJobTrasferFee(cpkt.Job); CommonFunctions.UpdateZeny(this.character); } //Helper variables List<int> EnabledEquipment = new List<int>(); List<int> DisabledEquipment = new List<int>(); bool ChangeWeapon = cpkt.ChangeWeapon == 1; bool IsActiveWeapon = this.character.weapons.IsActiveSlot(cpkt.WeaponSlot); Weapon selectedWeapon = this.character.weapons[cpkt.WeaponSlot]; #region Update Character Information lock (this.character) { //Change the job and joblevel int hpbefore = Singleton.CharacterConfiguration.CalculateMaximumHP(this.character); int spbefore = Singleton.CharacterConfiguration.CalculateMaximumSP(this.character); this.character.CharacterJobLevel[this.character.job] = this.character.jlvl; this.character.jlvl = this.character.CharacterJobLevel[cpkt.Job]; this.character.job = cpkt.Job; this.character.Jexp = Singleton.experience.FindRequiredJexp(this.character.jlvl); int hpafter = Singleton.CharacterConfiguration.CalculateMaximumHP(this.character); int spafter = Singleton.CharacterConfiguration.CalculateMaximumSP(this.character); this.character._status.CurrentHp += (ushort)(hpbefore - hpafter); this.character._status.CurrentSp += (ushort)(spbefore - spafter); this.character._status.Updates |= 1; } #endregion Update Character Information #region Refresh Weapon //Deapply current weapon info if (ChangeWeapon && IsActiveWeapon && selectedWeapon != null) { BattleStatus status = this.character._status; status.MaxWMAttack -= (ushort)selectedWeapon.Info.max_magic_attack; status.MinWMAttack -= (ushort)selectedWeapon.Info.min_magic_attack; status.MaxWPAttack -= (ushort)selectedWeapon.Info.max_short_attack; status.MinWPAttack -= (ushort)selectedWeapon.Info.min_short_attack; status.MaxWRAttack -= (ushort)selectedWeapon.Info.max_range_attack; status.MinWRAttack -= (ushort)selectedWeapon.Info.min_range_attack; status.Updates |= 2; //Reapplies alterstone additions for (int i = 0; i < 8; i++) { uint addition = selectedWeapon.Slots[i]; if (addition > 0) { Singleton.Additions.DeapplyAddition(addition, character); } } } #endregion Refresh Weapon #region Refresh Weapon if (ChangeWeapon && selectedWeapon != null) { Singleton.Weapons.ChangeWeapon(cpkt.Job, cpkt.PostFix, selectedWeapon); SMSG_WEAPONCHANGE spkt = new SMSG_WEAPONCHANGE(); spkt.Auge = selectedWeapon._augeskill; spkt.SessionId = this.character.id; spkt.Suffix = cpkt.PostFix; spkt.Index = cpkt.WeaponSlot; spkt.WeaponType = (byte)selectedWeapon._type; this.Send((byte[])spkt); } #endregion Refresh Weapon #region Refresh Skills { //Remove all skills foreach (Skill skill in this.character.learnedskills) { //Remove the skill SMSG_SKILLREMOVE spkt = new SMSG_SKILLREMOVE(); spkt.Unknown = skill.info.skilltype; spkt.SessionId = this.character.id; spkt.SkillId = skill.info.skillid; this.Send((byte[])spkt); //Save only experience if it's maxed-out. Singleton.Database.UpdateSkill(this.character, skill.Id, (skill.Experience == skill.info.maximumexperience) ? skill.info.maximumexperience : 0); //Deapply passive skills bool canUse = Singleton.SpellManager.CanUse(this.character, skill.info); if (skill.info.skilltype == 2 && canUse) Singleton.Additions.DeapplyAddition(skill.info.addition, character); } //Remove all learned skills in an instant this.character.learnedskills.Clear(); Singleton.Database.LoadSkills(this.character); //Retrieve job speciafic skills foreach (Skill skill in this.character.learnedskills) { //Add the skill SMSG_SKILLADD spkt = new SMSG_SKILLADD(); spkt.SessionId = this.character.id; spkt.SkillId = skill.info.skillid; spkt.Slot = 0; this.Send((byte[])spkt); //Deapply passive skills bool canUse = Singleton.SpellManager.CanUse(this.character, skill.info); if (skill.info.skilltype == 2 && canUse) Singleton.Additions.ApplyAddition(skill.info.addition, character); } } #endregion Refresh Skills #region Refresh Weapon //Apply current weapon info if (ChangeWeapon && IsActiveWeapon && selectedWeapon != null) { //Apply status BattleStatus status = this.character._status; status.MaxWMAttack += (ushort)selectedWeapon.Info.max_magic_attack; status.MinWMAttack += (ushort)selectedWeapon.Info.min_magic_attack; status.MaxWPAttack += (ushort)selectedWeapon.Info.max_short_attack; status.MinWPAttack += (ushort)selectedWeapon.Info.min_short_attack; status.MaxWRAttack += (ushort)selectedWeapon.Info.max_range_attack; status.MinWRAttack += (ushort)selectedWeapon.Info.min_range_attack; status.Updates |= 2; //Reapplies alterstone additions for (int i = 0; i < 8; i++) { uint addition = selectedWeapon.Slots[i]; if (addition > 0) { Singleton.Additions.ApplyAddition(addition, character); } } } #endregion Refresh Weapon #region Refresh Equipment { //Disable equipment for (int i = 0; i < 16; i++) { //Verify if item exists Rag2Item item = this.character.Equipment[i]; if (item == null || item.info == null) continue; //Verify if the item changed states bool Active = item.active == 1; bool NewActive = this.character.jlvl >= item.info.JobRequirement[cpkt.Job - 1]; if (Active == NewActive) continue; item.active = (byte)((NewActive == true) ? 1 : 0); //Adjust the item SMSG_ITEMADJUST spkt = new SMSG_ITEMADJUST(); spkt.Container = 1; spkt.Function = 5; spkt.Slot = (byte)i; spkt.SessionId = this.character.id; spkt.Value = item.active; this.Send((byte[])spkt); //Deapply additions if (NewActive) { EnabledEquipment.Add(i); Singleton.Additions.ApplyAddition(item.info.option_id, character); } else { DisabledEquipment.Add(i); Singleton.Additions.DeapplyAddition(item.info.option_id, character); } } //Update other stats //Common.Internal.CheckWeaponary(this.character); //CommonFunctions.UpdateCharacterInfo(this.character, 0); //CommonFunctions.SendBattleStatus(this.character); } #endregion Refresh Equipment #region Refresh Appereance { Regiontree tree = this.character.currentzone.Regiontree; foreach (Character regionObject in tree.SearchActors(SearchFlags.Characters)) { SMSG_JOBCHANGED spkt = new SMSG_JOBCHANGED(); spkt.SessionId = regionObject.id; spkt.SourceActor = this.character.id; spkt.Job = cpkt.Job; regionObject.client.Send((byte[])spkt); if (regionObject.id != this.character.id) { if (IsActiveWeapon) { uint auge = (character.FindRequiredRootSkill(selectedWeapon.Info.weapon_skill)) ? selectedWeapon._augeskill : 0; SMSG_SHOWWEAPON spkt2 = new SMSG_SHOWWEAPON(); spkt2.ActorID = this.character.id; spkt2.AugeID = auge; spkt2.SessionId = regionObject.id; regionObject.client.Send((byte[])spkt2); } foreach (byte i in EnabledEquipment) { Rag2Item item = this.character.Equipment[i]; SMSG_CHANGEEQUIPMENT spkt2 = new SMSG_CHANGEEQUIPMENT(); spkt2.SessionId = regionObject.id; spkt2.ActorID = this.character.id; spkt2.Slot = i; spkt2.ItemID = item.info.item; spkt2.Dye = item.dyecolor; regionObject.client.Send((byte[])spkt2); } foreach (byte i in DisabledEquipment) { SMSG_CHANGEEQUIPMENT spkt2 = new SMSG_CHANGEEQUIPMENT(); spkt2.SessionId = regionObject.id; spkt2.ActorID = this.character.id; spkt2.Slot = i; spkt2.ItemID = 0; spkt2.Dye = 0; regionObject.client.Send((byte[])spkt2); } } } } #endregion Refresh Appereance #region Refresh Party { //Process party members SMSG_PARTYMEMBERJOB spkt = new SMSG_PARTYMEMBERJOB(); spkt.Job = cpkt.Job; spkt.SessionId = this.character.id; spkt.ActorId = this.character.id; spkt.Index = 1; SMSG_PARTYMEMBERJLVL spkt2 = new SMSG_PARTYMEMBERJLVL(); spkt2.Jvl = this.character.jlvl; spkt2.ActorId = this.character.id; spkt2.Index = 1; if (this.character.sessionParty != null) { foreach (Character target in this.character.sessionParty.GetCharacters()) { //Send over Job change spkt.SessionId = target.id; target.client.Send((byte[])spkt); //Send over jlvl change spkt2.SessionId = target.id; target.client.Send((byte[])spkt2); } } } #endregion Refresh Party #region Refresh LifeCycle Tasks.LifeCycle.Update(this.character); #endregion Refresh LifeCycle }