public void WUExceptions() { var wu = new WUUpgrades(); Assert.Throws(typeof(ArgumentOutOfRangeException), () => { wu.ChainCastSkillId = 1; }); Assert.Throws(typeof(ArgumentOutOfRangeException), () => { wu.ChainCastLevel = 10; }); Assert.DoesNotThrow(() => { wu.ChainCastSkillId = 10000; }); Assert.DoesNotThrow(() => { wu.ChainCastLevel = 9; }); }
public void WUModification() { var test1 = "12345603070809"; var test2 = "65432723374859"; var test3 = "100012fffefdfc"; var test4 = "00000504030201"; var wu = new WUUpgrades(test1); Assert.Equal(test1, wu.ToString()); wu.ChainCastSkillId = 65432; wu.ChainCastLevel += 0x1; wu.ManaUse += 0x20; wu.ManaBurn += 0x30; wu.CastingSpeed += 0x40; wu.MagicDamage += 0x50; Assert.Equal(test2, wu.ToString()); Assert.Equal(wu.ChainCastSkillId, 65432); Assert.Equal(wu.ChainCastLevel, 7); Assert.Equal(wu.ManaUse, 0x23); Assert.Equal(wu.ManaBurn, 0x37); Assert.Equal(wu.CastingSpeed, 0x48); Assert.Equal(wu.MagicDamage, 0x59); wu.ChainCastSkillId = 10001; wu.ChainCastLevel = 2; wu.ManaUse = -1; wu.ManaBurn = -2; wu.CastingSpeed = -3; wu.MagicDamage = -4; Assert.Equal(test3, wu.ToString()); Assert.Equal(wu.ChainCastSkillId, 10001); Assert.Equal(wu.ChainCastLevel, 2); Assert.Equal(wu.ManaUse, -1); Assert.Equal(wu.ManaBurn, -2); Assert.Equal(wu.CastingSpeed, -3); Assert.Equal(wu.MagicDamage, -4); wu.ChainCastSkillId = 0; wu.ChainCastLevel = 5; wu.ManaUse = 4; wu.ManaBurn = 3; wu.CastingSpeed = 2; wu.MagicDamage = 1; Assert.Equal(test4, wu.ToString()); Assert.Equal(wu.ChainCastSkillId, 0); Assert.Equal(wu.ChainCastLevel, 5); Assert.Equal(wu.ManaUse, 4); Assert.Equal(wu.ManaBurn, 3); Assert.Equal(wu.CastingSpeed, 2); Assert.Equal(wu.MagicDamage, 1); }
public void WUParsing() { var test = "12345603070809"; var wu = new WUUpgrades(test); Assert.Equal(test, wu.ToString()); Assert.Equal(wu.ChainCastSkillId, 12345); Assert.Equal(wu.ChainCastLevel, 6); Assert.Equal(wu.ManaUse, 3); Assert.Equal(wu.Unknown, 7); Assert.Equal(wu.CastingSpeed, 8); Assert.Equal(wu.MagicDamage, 9); }
public void WUSizeFix() { var test1_1 = "0504030201"; var test1_2 = "00000504030201"; var wu1 = new WUUpgrades(test1_1); Assert.Equal(test1_2, wu1.ToString()); Assert.Equal(wu1.ChainCastSkillId, 0); Assert.Equal(wu1.ChainCastLevel, 5); Assert.Equal(wu1.ManaUse, 4); Assert.Equal(wu1.ManaBurn, 3); Assert.Equal(wu1.CastingSpeed, 2); Assert.Equal(wu1.MagicDamage, 1); }
public void WUParsing() { var test = "12345603070809"; var wu = new WUUpgrades(test); Assert.Equal(test, wu.ToString()); Assert.Equal(wu.ChainCastSkillId, 12345); Assert.Equal(wu.ChainCastLevel, 6); Assert.Equal(wu.ManaUse, 3); Assert.Equal(wu.ManaBurn, 7); Assert.Equal(wu.CastingSpeed, 8); Assert.Equal(wu.MagicDamage, 9); var test2 = "00006504030201"; var wu2 = new WUUpgrades(test2); Assert.Equal(test2, wu2.ToString()); Assert.Equal(wu2.ChainCastSkillId, 6); Assert.Equal(wu2.ChainCastLevel, 5); Assert.Equal(wu2.ManaUse, 4); Assert.Equal(wu2.ManaBurn, 3); Assert.Equal(wu2.CastingSpeed, 2); Assert.Equal(wu2.MagicDamage, 1); }
/// <summary> /// Tries to upgrade item specified in the reply. /// </summary> /// <param name="upgradeReply"></param> /// <returns></returns> /// <remarks> /// Only warn when something goes wrong, because problems can be caused /// by replies unknown to us or an outdated database. /// /// The NPCs don't have replies for failed upgrades, because the client /// disables invalid upgrades, you shouldn't be able to get a fail, /// unless you "hacked", modified client files, or Aura is outdated. /// </remarks> public UpgradeResult Upgrade(string upgradeReply) { var result = new UpgradeResult(); // Example: @upgrade:22518872341757176:broad_sword_balance1 var args = upgradeReply.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (args.Length != 3 || !long.TryParse(args[1], out result.ItemEntityId)) { Log.Warning("NpcScript.Upgrade: Player '{0:X16}' (Account: {1}) sent invalid reply.", this.Player.EntityId, this.Player.Client.Account.Id); return result; } // Get item result.Item = this.Player.Inventory.GetItem(result.ItemEntityId); if (result.Item == null || result.Item.OptionInfo.Upgraded == result.Item.OptionInfo.UpgradeMax) { Log.Warning("NpcScript.Upgrade: Player '{0:X16}' (Account: {1}) tried to upgrade invalid item.", this.Player.EntityId, this.Player.Client.Account.Id); return result; } // Get upgrade and check item and NPCs result.Upgrade = AuraData.ItemUpgradesDb.Find(args[2]); if (result.Upgrade == null) { Log.Warning("NpcScript.Upgrade: Player '{0:X16}' (Account: {1}) tried to apply an unknown upgrade ({2}).", this.Player.EntityId, this.Player.Client.Account.Id, args[2]); return result; } // Check upgrade and item if (!result.Item.Data.HasTag(result.Upgrade.Filter) || result.Item.Proficiency < result.Upgrade.Exp || !Math2.Between(result.Item.OptionInfo.Upgraded, result.Upgrade.UpgradeMin, result.Upgrade.UpgradeMax)) { Log.Warning("NpcScript.Upgrade: Player '{0:X16}' (Account: {1}) tried to apply upgrade to invalid item.", this.Player.EntityId, this.Player.Client.Account.Id); return result; } if (!result.Upgrade.Npcs.Contains(this.NPC.Name.TrimStart('_').ToLower())) { Log.Warning("NpcScript.Upgrade: Player '{0:X16}' (Account: {1}) tried to apply upgrade '{2}' at an invalid NPC ({3}).", this.Player.EntityId, this.Player.Client.Account.Id, result.Upgrade.Ident, this.NPC.Name.TrimStart('_').ToLower()); return result; } // Check for disabled Artisan // TODO: Feature check, once we do have Artisan. if (result.Upgrade.Effects.Any(a => a.Key == "Artisan")) { Send.MsgBox(this.Player, Localization.Get("Artisan upgrades aren't available yet.")); return result; } // Check gold if (this.Gold < result.Upgrade.Gold) return result; // Take gold and exp result.Item.Proficiency -= result.Upgrade.Exp; this.Gold -= result.Upgrade.Gold; // Increase upgrade count result.Item.OptionInfo.Upgraded++; if (ChannelServer.Instance.Conf.World.UnlimitedUpgrades && result.Item.OptionInfo.Upgraded == result.Item.OptionInfo.UpgradeMax) result.Item.OptionInfo.Upgraded = 0; // Upgrade foreach (var effect in result.Upgrade.Effects) { switch (effect.Key) { case "MinAttack": result.Item.OptionInfo.AttackMin = (ushort)Math2.Clamp(1, result.Item.OptionInfo.AttackMax, result.Item.OptionInfo.AttackMin + effect.Value[0]); break; case "MaxAttack": result.Item.OptionInfo.AttackMax = (ushort)Math2.Clamp(1, ushort.MaxValue, result.Item.OptionInfo.AttackMax + effect.Value[0]); if (result.Item.OptionInfo.AttackMax < result.Item.OptionInfo.AttackMin) result.Item.OptionInfo.AttackMin = result.Item.OptionInfo.AttackMax; break; case "MinInjury": result.Item.OptionInfo.InjuryMin = (ushort)Math2.Clamp(0, result.Item.OptionInfo.InjuryMax, result.Item.OptionInfo.InjuryMin + effect.Value[0]); break; case "MaxInjury": result.Item.OptionInfo.InjuryMax = (ushort)Math2.Clamp(0, ushort.MaxValue, result.Item.OptionInfo.InjuryMax + effect.Value[0]); if (result.Item.OptionInfo.InjuryMax < result.Item.OptionInfo.InjuryMin) result.Item.OptionInfo.InjuryMin = result.Item.OptionInfo.InjuryMax; break; case "Balance": result.Item.OptionInfo.Balance = (byte)Math2.Clamp(0, byte.MaxValue, result.Item.OptionInfo.Balance + effect.Value[0]); break; case "Critical": result.Item.OptionInfo.Critical = (sbyte)Math2.Clamp(0, sbyte.MaxValue, result.Item.OptionInfo.Critical + effect.Value[0]); break; case "Defense": result.Item.OptionInfo.Defense = (int)Math2.Clamp(0, int.MaxValue, result.Item.OptionInfo.Defense + (long)effect.Value[0]); break; case "Protection": result.Item.OptionInfo.Protection = (short)Math2.Clamp(0, short.MaxValue, result.Item.OptionInfo.Protection + effect.Value[0]); break; case "AttackRange": result.Item.OptionInfo.EffectiveRange = (short)Math2.Clamp(0, short.MaxValue, result.Item.OptionInfo.EffectiveRange + effect.Value[0]); break; case "MaxDurability": result.Item.OptionInfo.DurabilityMax = (int)Math2.Clamp(1000, int.MaxValue, result.Item.OptionInfo.DurabilityMax + (long)(effect.Value[0] * 1000)); if (result.Item.OptionInfo.DurabilityMax < result.Item.OptionInfo.Durability) result.Item.OptionInfo.Durability = result.Item.OptionInfo.DurabilityMax; break; case "MagicDefense": // MDEF:f:1.000000;MPROT:f:1.000000;MTWR:1:1; var mdef = result.Item.MetaData1.GetFloat("MDEF"); result.Item.MetaData1.SetFloat("MDEF", Math2.Clamp(0, int.MaxValue, mdef + effect.Value[0])); break; case "MagicProtection": // MDEF:f:1.000000;MPROT:f:1.000000;MTWR:1:1; var mprot = result.Item.MetaData1.GetFloat("MPROT"); result.Item.MetaData1.SetFloat("MPROT", Math2.Clamp(0, int.MaxValue, mprot + effect.Value[0])); break; case "ManaUse": // WU:s:00000003000000 var manaUseWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); manaUseWU.ManaUse += (sbyte)effect.Value[0]; result.Item.MetaData1.SetString("WU", manaUseWU.ToString()); break; case "ManaBurn": var manaBurnWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); // Prior to G15S2 players lost all their Mana when // they unequipped a wand. This was removed via // feature, but before that this upgrade allowed // one to reduce the amount of Mana lost. // Afterwards the ManaBurn upgrade was turned into // a ManaUse automatically, but the bonus was halfed, // meaning if a ManaBurn upgrade gave -4% burn, // it gave -2% use after this update. if (!this.IsEnabled("ManaBurnRemove")) manaBurnWU.ManaBurn += (sbyte)effect.Value[0]; else manaBurnWU.ManaUse += (sbyte)(effect.Value[0] / 2); result.Item.MetaData1.SetString("WU", manaBurnWU.ToString()); break; case "ChainCasting": // Chain Casting: +4, Magic Attack: +21 // EHLV:4:5;MTWR:1:1;OWNER:s:username;WU:s:30201400000015; var chainCastWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); chainCastWU.ChainCastSkillId = (ushort)effect.Value[0]; chainCastWU.ChainCastLevel = (byte)effect.Value[1]; result.Item.MetaData1.SetString("WU", chainCastWU.ToString()); break; case "MagicDamage": // Charging Speed: +12%, MA: +16 // EHLV:4:5;MTWR:1:1;OWNER:s:username;WU:s:00000000000c10; var magicDmgWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); magicDmgWU.MagicDamage += (sbyte)effect.Value[0]; result.Item.MetaData1.SetString("WU", magicDmgWU.ToString()); break; case "CastingSpeed": // Charging Speed: +12%, MA: +16 // EHLV:4:5;MTWR:1:1;OWNER:s:username;WU:s:00000000000c10; var castingSpeedWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); castingSpeedWU.CastingSpeed += (sbyte)effect.Value[0]; result.Item.MetaData1.SetString("WU", castingSpeedWU.ToString()); break; case "MusicBuffBonus": // MBB:4:8;MBD:4:10;MTWR:1:2;OTU:1:1;SPTEC:1:1; var musicBuff = result.Item.MetaData1.GetInt("MBB"); result.Item.MetaData1.SetInt("MBB", musicBuff + (int)effect.Value[0]); break; case "MusicBuffDuration": // MBB:4:8;MBD:4:10;MTWR:1:2;OTU:1:1;SPTEC:1:1; var musicBuffDur = result.Item.MetaData1.GetInt("MBD"); result.Item.MetaData1.SetInt("MBD", musicBuffDur + (int)effect.Value[0]); break; case "CollectionBonus": // CTBONUS:2:40;CTSPEED:4:750;MTWR:1:1; var collectionBonusBuff = result.Item.MetaData1.GetShort("CTBONUS"); result.Item.MetaData1.SetShort("CTBONUS", (short)(collectionBonusBuff + effect.Value[0])); break; case "CollectionSpeed": // CTBONUS:2:40;CTSPEED:4:750;MTWR:1:1; var collectionSpeedBuff = result.Item.MetaData1.GetInt("CTSPEED"); result.Item.MetaData1.SetInt("CTSPEED", collectionSpeedBuff + (int)effect.Value[0]); break; case "LancePiercing": // EHLV:4:5;LKUP:8:262244;LP:1:4;LP_E:1:0;OWNER:s:character;SPTRP:1:1; << Piercing Level 4 // LP:1:1;QUAL:4:70; << Piercing Level 1 var lancePiercingBuff = result.Item.MetaData1.GetByte("LP"); result.Item.MetaData1.SetByte("LP", (byte)(lancePiercingBuff + effect.Value[0])); break; case "SplashRadius": // SP_DMG:f:0.250000;SP_RAD:4:70; var splashRadiusBuff = result.Item.MetaData1.GetInt("SP_RAD"); result.Item.MetaData1.SetInt("SP_RAD", splashRadiusBuff + (int)effect.Value[0]); break; case "SplashDamage": // SP_DMG:f:0.250000;SP_RAD:4:70; var splashDamageBuff = result.Item.MetaData1.GetFloat("SP_DMG"); result.Item.MetaData1.SetFloat("SP_DMG", splashDamageBuff + effect.Value[0]); break; case "ImmuneMelee": // IM_MGC:f:0.050000;IM_MLE:f:0.050000;IM_RNG:f:0.050000;MDEF:f:2.000000;MPROT:f:3.000000;OTU:1:1; var immuneMeleeBuff = result.Item.MetaData1.GetFloat("IM_MLE"); result.Item.MetaData1.SetFloat("IM_MLE", immuneMeleeBuff + effect.Value[0]); break; case "ImmuneRanged": // IM_MGC:f:0.050000;IM_MLE:f:0.050000;IM_RNG:f:0.050000;MDEF:f:2.000000;MPROT:f:3.000000;OTU:1:1; var immuneRangedBuff = result.Item.MetaData1.GetFloat("IM_RNG"); result.Item.MetaData1.SetFloat("IM_RNG", immuneRangedBuff + effect.Value[0]); break; case "ImmuneMagic": // IM_MGC:f:0.050000;IM_MLE:f:0.050000;IM_RNG:f:0.050000;MDEF:f:2.000000;MPROT:f:3.000000;OTU:1:1; var immuneMagicBuff = result.Item.MetaData1.GetFloat("IM_MGC"); result.Item.MetaData1.SetFloat("IM_MGC", immuneMagicBuff + effect.Value[0]); break; // TODO: // - MaxBullets // - Artisan default: Log.Unimplemented("Item upgrade '{0}'", effect.Key); break; } } // Personalization if (result.Upgrade.Personalize) { result.Item.OptionInfo.Flags |= ItemFlags.Personalized; result.Item.MetaData1.SetString("OWNER", this.Player.Name); } // Update item Send.ItemUpdate(this.Player, result.Item); // Send result Send.ItemUpgradeResult(this.Player, result.Item, result.Upgrade.Ident); result.Success = true; this.Player.Keywords.Give("ExperienceUpgrade"); return result; }
/// <summary> /// Caches and applies WU upgrades for item. /// </summary> /// <param name="item"></param> private void HandleWUUpgrades(Item item) { // There's probably a better way to save these bonuses, // but I can't think of it right now. var wustr = item.MetaData1.GetString("WU"); if (wustr != null) { var wu = new WUUpgrades(wustr); lock (_wuUpgrades) _wuUpgrades[item.EntityId] = wu; if (wu.MagicDamage != 0) _creature.StatMods.Add(Stat.MagicAttackMod, wu.MagicDamage, StatModSource.Equipment, item.EntityId); } }
/// <summary> /// Tries to upgrade item specified in the reply. /// </summary> /// <param name="upgradeReply"></param> /// <returns></returns> /// <remarks> /// Only warn when something goes wrong because problems can be caused /// by replies unknown to us or an outdated database. /// /// The NPCs don't have replies for failed upgrades, because the client /// disables invalid upgrades, you shouldn't be able to get a fail, /// unless you "hacked", modified client files, or Aura is outdated. /// </remarks> public UpgradeResult Upgrade(string upgradeReply) { var result = new UpgradeResult(); // Example: @upgrade:22518872341757176:broad_sword_balance1 var args = upgradeReply.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (args.Length != 3 || !long.TryParse(args[1], out result.ItemEntityId)) { Log.Warning("NpcScript.Upgrade: Player '{0}' (Account: {1}) sent invalid reply.", this.Player.EntityIdHex, this.Player.Client.Account.Id); return result; } // Get item result.Item = this.Player.Inventory.GetItem(result.ItemEntityId); if (result.Item == null || result.Item.OptionInfo.Upgraded == result.Item.OptionInfo.UpgradeMax) { Log.Warning("NpcScript.Upgrade: Player '{0}' (Account: {1}) tried to upgrade invalid item.", this.Player.EntityIdHex, this.Player.Client.Account.Id); return result; } // Get upgrade and check item and NPCs result.Upgrade = AuraData.ItemUpgradesDb.Find(args[2]); if (result.Upgrade == null) { Log.Warning("NpcScript.Upgrade: Player '{0}' (Account: {1}) tried to apply an unknown upgrade ({2}).", this.Player.EntityIdHex, this.Player.Client.Account.Id, args[2]); return result; } // Check upgrade and item if (!result.Item.Data.HasTag(result.Upgrade.Filter) || result.Item.Proficiency < result.Upgrade.Exp || !Math2.Between(result.Item.OptionInfo.Upgraded, result.Upgrade.UpgradeMin, result.Upgrade.UpgradeMax)) { Log.Warning("NpcScript.Upgrade: Player '{0}' (Account: {1}) tried to apply upgrade to invalid item.", this.Player.EntityIdHex, this.Player.Client.Account.Id); return result; } if (!result.Upgrade.Npcs.Contains(this.NPC.Name.TrimStart('_').ToLower())) { Log.Warning("NpcScript.Upgrade: Player '{0}' (Account: {1}) tried to apply upgrade '{2}' at an invalid NPC ({3}).", this.Player.EntityIdHex, this.Player.Client.Account.Id, result.Upgrade.Ident, this.NPC.Name.TrimStart('_').ToLower()); return result; } // Check gold if (this.Gold < result.Upgrade.Gold) return result; // Take gold and exp result.Item.Proficiency -= result.Upgrade.Exp; this.Gold -= result.Upgrade.Gold; // Increase upgrade count result.Item.OptionInfo.Upgraded++; if (ChannelServer.Instance.Conf.World.UnlimitedUpgrades && result.Item.OptionInfo.Upgraded == result.Item.OptionInfo.UpgradeMax) result.Item.OptionInfo.Upgraded = 0; // Upgrade foreach (var effect in result.Upgrade.Effects) { switch (effect.Key) { case "MinAttack": result.Item.OptionInfo.AttackMin = (ushort)Math2.Clamp(1, result.Item.OptionInfo.AttackMax, result.Item.OptionInfo.AttackMin + effect.Value[0]); break; case "MaxAttack": result.Item.OptionInfo.AttackMax = (ushort)Math2.Clamp(1, ushort.MaxValue, result.Item.OptionInfo.AttackMax + effect.Value[0]); if (result.Item.OptionInfo.AttackMax < result.Item.OptionInfo.AttackMin) result.Item.OptionInfo.AttackMin = result.Item.OptionInfo.AttackMax; break; case "MinInjury": result.Item.OptionInfo.InjuryMin = (ushort)Math2.Clamp(0, result.Item.OptionInfo.InjuryMax, result.Item.OptionInfo.InjuryMin + effect.Value[0]); break; case "MaxInjury": result.Item.OptionInfo.InjuryMax = (ushort)Math2.Clamp(0, ushort.MaxValue, result.Item.OptionInfo.InjuryMax + effect.Value[0]); if (result.Item.OptionInfo.InjuryMax < result.Item.OptionInfo.InjuryMin) result.Item.OptionInfo.InjuryMin = result.Item.OptionInfo.InjuryMax; break; case "Balance": result.Item.OptionInfo.Balance = (byte)Math2.Clamp(0, byte.MaxValue, result.Item.OptionInfo.Balance + effect.Value[0]); break; case "Critical": result.Item.OptionInfo.Critical = (sbyte)Math2.Clamp(0, sbyte.MaxValue, result.Item.OptionInfo.Critical + effect.Value[0]); break; case "Defense": result.Item.OptionInfo.Defense = (int)Math2.Clamp(0, int.MaxValue, result.Item.OptionInfo.Defense + (long)effect.Value[0]); break; case "Protection": result.Item.OptionInfo.Protection = (short)Math2.Clamp(0, short.MaxValue, result.Item.OptionInfo.Protection + effect.Value[0]); break; case "AttackRange": result.Item.OptionInfo.EffectiveRange = (short)Math2.Clamp(0, short.MaxValue, result.Item.OptionInfo.EffectiveRange + effect.Value[0]); break; case "MaxDurability": result.Item.OptionInfo.DurabilityMax = (int)Math2.Clamp(1000, int.MaxValue, result.Item.OptionInfo.DurabilityMax + (long)(effect.Value[0] * 1000)); if (result.Item.OptionInfo.DurabilityMax < result.Item.OptionInfo.Durability) result.Item.OptionInfo.Durability = result.Item.OptionInfo.DurabilityMax; break; case "MagicDefense": // MDEF:f:1.000000;MPROT:f:1.000000;MTWR:1:1; var mdef = result.Item.MetaData1.GetFloat("MDEF"); result.Item.MetaData1.SetFloat("MDEF", Math2.Clamp(0, int.MaxValue, mdef + effect.Value[0])); break; case "MagicProtection": // MDEF:f:1.000000;MPROT:f:1.000000;MTWR:1:1; var mprot = result.Item.MetaData1.GetFloat("MPROT"); result.Item.MetaData1.SetFloat("MPROT", Math2.Clamp(0, int.MaxValue, mprot + effect.Value[0])); break; case "ManaUse": // WU:s:00000003000000 var manaUseWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); manaUseWU.ManaUse += (sbyte)effect.Value[0]; result.Item.MetaData1.SetString("WU", manaUseWU.ToString()); break; case "ChainCast": // Chain Casting: +4, Magic Attack: +21 // EHLV:4:5;MTWR:1:1;OWNER:s:username;WU:s:30201400000015; var chainCastWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); chainCastWU.ChainCastSkillId = (ushort)effect.Value[0]; chainCastWU.ChainCastLevel = (byte)effect.Value[1]; result.Item.MetaData1.SetString("WU", chainCastWU.ToString()); break; case "MagicDamage": // Charging Speed: +12%, MA: +16 // EHLV:4:5;MTWR:1:1;OWNER:s:username;WU:s:00000000000c10; var magicDmgWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); magicDmgWU.MagicDamage += (sbyte)effect.Value[0]; result.Item.MetaData1.SetString("WU", magicDmgWU.ToString()); break; case "CastingSpeed": // Charging Speed: +12%, MA: +16 // EHLV:4:5;MTWR:1:1;OWNER:s:username;WU:s:00000000000c10; var castingSpeedWU = new WUUpgrades(result.Item.MetaData1.GetString("WU")); castingSpeedWU.CastingSpeed += (sbyte)effect.Value[0]; result.Item.MetaData1.SetString("WU", castingSpeedWU.ToString()); break; case "MusicBuffBonus": // MBB:4:8;MBD:4:10;MTWR:1:2;OTU:1:1;SPTEC:1:1; var musicBuff = result.Item.MetaData1.GetInt("MBB"); result.Item.MetaData1.SetInt("MBB", musicBuff + effect.Value[0]); break; case "MusicBuffDuration": // MBB:4:8;MBD:4:10;MTWR:1:2;OTU:1:1;SPTEC:1:1; var musicBuffDur = result.Item.MetaData1.GetInt("MBD"); result.Item.MetaData1.SetInt("MBD", musicBuffDur + effect.Value[0]); break; // TODO: // - CollectionSpeed // - CollectionBonus // - SplashRadius // - ManaBurn // - LancePiercing // - MaxBullets // - Artisan default: Log.Unimplemented("Item upgrade '{0}'", effect.Key); break; } } // Personalization if (result.Upgrade.Personalize) { result.Item.OptionInfo.Flags |= ItemFlags.Personalized; result.Item.MetaData1.SetString("OWNER", this.Player.Name); } // Update item Send.ItemUpdate(this.Player, result.Item); // Send result Send.ItemUpgradeResult(this.Player, result.Item, result.Upgrade.Ident); result.Success = true; return result; }