public override int CalcValue(GameLiving living, eProperty property) { // hardcap at 25% int percent = Math.Min(25, living.BaseBuffBonusCategory[(int)property] - living.DebuffCategory[(int)property] + living.ItemBonus[(int)property]); // Add RA bonus percent += living.AbilityBonus[(int)property]; // Relic bonus calculated before RA bonuses if (living is GamePlayer || living is GamePet) { percent += (int)(100 * RelicMgr.GetRelicBonusModifier(living.Realm, eRelicType.Magic)); } return(percent); }
public void OnCommand(GameClient client, string[] args) { if (args.Length != 3 || (args[1] != "magic" && args[1] != "strength")) { DisplaySyntax(client); return; } DBRelic relic = new DBRelic(); relic.Heading = client.Player.Heading; relic.OriginalRealm = int.Parse(args[2]); relic.Realm = 0; relic.Region = client.Player.CurrentRegionID; relic.relicType = (args[1] == "strength") ? 0 : 1; relic.X = client.Player.X; relic.Y = client.Player.Y; relic.Z = client.Player.Z; relic.RelicID = Util.Random(100); GameServer.Database.AddObject(relic); RelicMgr.Init(); }
protected override void OnTick() { GameLiving target = m_arrowTarget; GameLiving caster = (GameLiving)m_actionSource; if (target == null || !target.IsAlive || target.ObjectState != GameObject.eObjectState.Active || target.CurrentRegionID != caster.CurrentRegionID) { return; } int missrate = 100 - m_handler.CalculateToHitChance(target); // add defence bonus from last executed style if any AttackData targetAD = (AttackData)target.TempProperties.getProperty <object>(GameLiving.LAST_ATTACK_DATA, null); if (targetAD != null && targetAD.AttackResult == GameLiving.eAttackResult.HitStyle && targetAD.Style != null) { missrate += targetAD.Style.BonusToDefense; } // half of the damage is magical // subtract any spelldamage bonus and re-calculate after half damage is calculated AttackData ad = m_handler.CalculateDamageToTarget(target, 0.5 - (caster.GetModified(eProperty.SpellDamage) * 0.01)); // check for bladeturn miss if (ad.AttackResult == GameLiving.eAttackResult.Missed) { return; } if (Util.Chance(missrate)) { ad.AttackResult = GameLiving.eAttackResult.Missed; m_handler.MessageToCaster("You miss!", eChatType.CT_YouHit); m_handler.MessageToLiving(target, caster.GetName(0, false) + " missed!", eChatType.CT_Missed); target.OnAttackedByEnemy(ad); target.StartInterruptTimer(target.SpellInterruptDuration, ad.AttackType, caster); if (target is GameNPC) { IOldAggressiveBrain aggroBrain = ((GameNPC)target).Brain as IOldAggressiveBrain; if (aggroBrain != null) { aggroBrain.AddToAggroList(caster, 1); } } return; } ad.Damage = (int)((double)ad.Damage * (1.0 + caster.GetModified(eProperty.SpellDamage) * 0.01)); bool arrowBlock = false; if (target is GamePlayer && !target.IsStunned && !target.IsMezzed && !target.IsSitting && m_handler.Spell.LifeDrainReturn != (int)Archery.eShotType.Critical) { GamePlayer player = (GamePlayer)target; InventoryItem lefthand = player.Inventory.GetItem(eInventorySlot.LeftHandWeapon); if (lefthand != null && (player.AttackWeapon == null || player.AttackWeapon.Item_Type == Slot.RIGHTHAND || player.AttackWeapon.Item_Type == Slot.LEFTHAND)) { if (target.IsObjectInFront(caster, 180) && lefthand.Object_Type == (int)eObjectType.Shield) { // TODO: shield size vs number of attackers not calculated double shield = 0.5 * player.GetModifiedSpecLevel(Specs.Shields); double blockchance = ((player.Dexterity * 2) - 100) / 40.0 + shield + (0 * 3) + 5; blockchance += 30; blockchance -= target.GetConLevel(caster) * 5; if (blockchance >= 100) { blockchance = 99; } if (blockchance <= 0) { blockchance = 1; } if (target.IsEngaging) { EngageEffect engage = target.EffectList.GetOfType <EngageEffect>(); if (engage != null && target.AttackState && engage.EngageTarget == caster) { // Engage raised block change to 85% if attacker is engageTarget and player is in attackstate // You cannot engage a mob that was attacked within the last X seconds... if (engage.EngageTarget.LastAttackedByEnemyTick > engage.EngageTarget.CurrentRegion.Time - EngageAbilityHandler.ENGAGE_ATTACK_DELAY_TICK) { if (engage.Owner is GamePlayer) { (engage.Owner as GamePlayer).Out.SendMessage(engage.EngageTarget.GetName(0, true) + " has been attacked recently and you are unable to engage.", eChatType.CT_System, eChatLoc.CL_SystemWindow); } } // Check if player has enough endurance left to engage else if (engage.Owner.Endurance < EngageAbilityHandler.ENGAGE_DURATION_LOST) { engage.Cancel(false); // if player ran out of endurance cancel engage effect } else { engage.Owner.Endurance -= EngageAbilityHandler.ENGAGE_DURATION_LOST; if (engage.Owner is GamePlayer) { (engage.Owner as GamePlayer).Out.SendMessage("You concentrate on blocking the blow!", eChatType.CT_Skill, eChatLoc.CL_SystemWindow); } if (blockchance < 85) { blockchance = 85; } } } } if (blockchance >= Util.Random(1, 100)) { arrowBlock = true; m_handler.MessageToLiving(player, "You block " + caster.GetName(0, false) + "'s arrow!", eChatType.CT_System); if (m_handler.Spell.Target.ToLower() != "area") { m_handler.MessageToCaster(player.GetName(0, true) + " blocks your arrow!", eChatType.CT_System); m_handler.DamageTarget(ad, false, 0x02); } } } } } if (arrowBlock == false) { // now calculate the magical part of arrow damage (similar to bolt calculation). Part 1 Physical, Part 2 Magical double damage = m_handler.Spell.Damage / 2; // another half is physical damage if (target is GamePlayer) { ad.ArmorHitLocation = ((GamePlayer)target).CalculateArmorHitLocation(ad); } InventoryItem armor = null; if (target.Inventory != null) { armor = target.Inventory.GetItem((eInventorySlot)ad.ArmorHitLocation); } double ws = (caster.Level * 8 * (1.0 + (caster.GetModified(eProperty.Dexterity) - 50) / 200.0)); damage *= ((ws + 90.68) / (target.GetArmorAF(ad.ArmorHitLocation) + 20 * 4.67)); damage *= 1.0 - Math.Min(0.85, ad.Target.GetArmorAbsorb(ad.ArmorHitLocation)); ad.Modifier = (int)(damage * (ad.Target.GetResist(ad.DamageType) + SkillBase.GetArmorResist(armor, ad.DamageType)) / -100.0); damage += ad.Modifier; double effectiveness = caster.Effectiveness; effectiveness += (caster.GetModified(eProperty.SpellDamage) * 0.01); damage = damage * effectiveness; damage *= (1.0 + RelicMgr.GetRelicBonusModifier(caster.Realm, eRelicType.Magic)); if (damage < 0) { damage = 0; } ad.Damage += (int)damage; if (caster.AttackWeapon != null) { // Quality ad.Damage -= (int)(ad.Damage * (100 - caster.AttackWeapon.Quality) * .01); // Condition ad.Damage = (int)((double)ad.Damage * Math.Min(1.0, (double)caster.AttackWeapon.Condition / (double)caster.AttackWeapon.MaxCondition)); // Patch Note: http://support.darkageofcamelot.com/kb/article.php?id=931 // - The Damage Per Second (DPS) of your bow will have an effect on your damage for archery shots. If the effective DPS // of your equipped bow is less than that of your max DPS for the level of archery shot you are using, the damage of your // shot will be reduced. Max DPS for a particular level can be found by using this equation: (.3 * level) + 1.2 int spellRequiredDPS = 12 + 3 * m_handler.Spell.Level; if (caster.AttackWeapon.DPS_AF < spellRequiredDPS) { double percentReduction = (double)caster.AttackWeapon.DPS_AF / (double)spellRequiredDPS; ad.Damage = (int)(ad.Damage * percentReduction); } } if (ad.Damage < 0) { ad.Damage = 0; } ad.UncappedDamage = ad.Damage; ad.Damage = (int)Math.Min(ad.Damage, m_handler.DamageCap(effectiveness)); if (ad.CriticalDamage > 0) { if (m_handler.Spell.Target.ToLower() == "area") { ad.CriticalDamage = 0; } else { int critMax = (target is GamePlayer) ? ad.Damage / 2 : ad.Damage; ad.CriticalDamage = Util.Random(critMax / 10, critMax); } } target.ModifyAttack(ad); m_handler.SendDamageMessages(ad); m_handler.DamageTarget(ad, false, 0x14); target.StartInterruptTimer(target.SpellInterruptDuration, ad.AttackType, caster); } if (m_handler.Spell.SubSpellID != 0) { Spell subspell = SkillBase.GetSpellByID(m_handler.Spell.SubSpellID); if (subspell != null) { subspell.Level = m_handler.Spell.Level; ISpellHandler spellhandler = ScriptMgr.CreateSpellHandler(m_handler.Caster, subspell, SkillBase.GetSpellLine(GlobalSpellsLines.Combat_Styles_Effect)); if (spellhandler != null) { spellhandler.StartSpell(target); } } } if (arrowBlock == false && m_handler.Caster.AttackWeapon != null && GlobalConstants.IsBowWeapon((eObjectType)m_handler.Caster.AttackWeapon.Object_Type)) { if (ad.AttackResult == GameLiving.eAttackResult.HitUnstyled || ad.AttackResult == GameLiving.eAttackResult.HitStyle) { caster.CheckWeaponMagicalEffect(ad, m_handler.Caster.AttackWeapon); } } }
public override void SendWarmapUpdate(ICollection <IGameKeep> list) { if (m_gameClient.Player == null) { return; } using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.WarMapClaimedKeeps))) { int KeepCount = 0; int TowerCount = 0; foreach (AbstractGameKeep keep in list) { // New Agramon tower are counted as keep if (keep is GameKeep || (keep.KeepID & 0xFF) > 150) { KeepCount++; } else { TowerCount++; } } pak.WriteShort(0x0F00); pak.WriteByte((byte)KeepCount); pak.WriteByte((byte)TowerCount); byte albStr = 0; byte hibStr = 0; byte midStr = 0; byte albMagic = 0; byte hibMagic = 0; byte midMagic = 0; foreach (GameRelic relic in RelicMgr.getNFRelics()) { switch (relic.OriginalRealm) { case eRealm.Albion: if (relic.RelicType == eRelicType.Strength) { albStr = (byte)relic.Realm; } if (relic.RelicType == eRelicType.Magic) { albMagic = (byte)relic.Realm; } break; case eRealm.Hibernia: if (relic.RelicType == eRelicType.Strength) { hibStr = (byte)relic.Realm; } if (relic.RelicType == eRelicType.Magic) { hibMagic = (byte)relic.Realm; } break; case eRealm.Midgard: if (relic.RelicType == eRelicType.Strength) { midStr = (byte)relic.Realm; } if (relic.RelicType == eRelicType.Magic) { midMagic = (byte)relic.Realm; } break; } } pak.WriteByte(albStr); pak.WriteByte(midStr); pak.WriteByte(hibStr); pak.WriteByte(albMagic); pak.WriteByte(midMagic); pak.WriteByte(hibMagic); foreach (AbstractGameKeep keep in list) { int keepId = keep.KeepID; if (ServerProperties.Properties.USE_NEW_KEEPS == 1 || ServerProperties.Properties.USE_NEW_KEEPS == 2) { keepId -= 12; if ((keep.KeepID > 74 && keep.KeepID < 114) || (keep.KeepID > 330 && keep.KeepID < 370) || (keep.KeepID > 586 && keep.KeepID < 626) || (keep.KeepID > 842 && keep.KeepID < 882) || (keep.KeepID > 1098 && keep.KeepID < 1138)) { keepId += 5; } } int id = keepId & 0xFF; int tower = keep.KeepID >> 8; int map = (id / 25) - 1; int index = id - (map * 25 + 25); // Special Agramon zone if ((keep.KeepID & 0xFF) > 150) { index = keep.KeepID - 151; } int flag = (byte)keep.Realm; // 3 bits Guild guild = keep.Guild; string name = ""; // map is now 0 indexed pak.WriteByte((byte)(((map - 1) << 6) | (index << 3) | tower)); if (guild != null) { flag |= (byte)eRealmWarmapKeepFlags.Claimed; name = guild.Name; } //Teleport if (m_gameClient.Account.PrivLevel > (int)ePrivLevel.Player) { flag |= (byte)eRealmWarmapKeepFlags.Teleportable; } else { if (GameServer.KeepManager.FrontierRegionsList.Contains(m_gameClient.Player.CurrentRegionID) && m_gameClient.Player.Realm == keep.Realm) { GameKeep theKeep = keep as GameKeep; if (theKeep != null) { if (theKeep.OwnsAllTowers && !theKeep.InCombat) { flag |= (byte)eRealmWarmapKeepFlags.Teleportable; } } } } if (keep.InCombat) { flag |= (byte)eRealmWarmapKeepFlags.UnderSiege; } pak.WriteByte((byte)flag); pak.WritePascalString(name); } SendTCP(pak); } }
/// <summary> /// Called on every timer tick /// </summary> protected override void OnTick() { GameLiving target = m_boltTarget; GameLiving caster = (GameLiving)m_actionSource; if (target == null) { return; } if (target.CurrentRegionID != caster.CurrentRegionID) { return; } if (target.ObjectState != GameObject.eObjectState.Active) { return; } if (!target.IsAlive) { return; } // Related to PvP hitchance // http://www.camelotherald.com/news/news_article.php?storyid=2444 // No information on bolt hitchance against npc's // Bolts are treated as physical attacks for the purpose of ABS only // Based on this I am normalizing the miss rate for npc's to be that of a standard spell int missrate = 0; if (caster is GamePlayer && target is GamePlayer) { if (target.InCombat) { foreach (GameLiving attacker in target.Attackers) { if (attacker != caster && target.GetDistanceTo(attacker) <= 200) { // each attacker within 200 units adds a 20% chance to miss missrate += 20; } } } } if (target is GameNPC || caster is GameNPC) { missrate += (int)(ServerProperties.Properties.PVE_SPELL_CONHITPERCENT * caster.GetConLevel(target)); } // add defence bonus from last executed style if any AttackData targetAD = (AttackData)target.TempProperties.getProperty <object>(GameLiving.LAST_ATTACK_DATA, null); if (targetAD != null && targetAD.AttackResult == GameLiving.eAttackResult.HitStyle && targetAD.Style != null) { missrate += targetAD.Style.BonusToDefense; } AttackData ad = m_handler.CalculateDamageToTarget(target, 0.5 - (caster.GetModified(eProperty.SpellDamage) * 0.01)); if (Util.Chance(missrate)) { ad.AttackResult = GameLiving.eAttackResult.Missed; m_handler.MessageToCaster("You miss!", eChatType.CT_YouHit); m_handler.MessageToLiving(target, caster.GetName(0, false) + " missed!", eChatType.CT_Missed); target.OnAttackedByEnemy(ad); target.StartInterruptTimer(target.SpellInterruptDuration, ad.AttackType, caster); if (target is GameNPC) { IOldAggressiveBrain aggroBrain = ((GameNPC)target).Brain as IOldAggressiveBrain; if (aggroBrain != null) { aggroBrain.AddToAggroList(caster, 1); } } return; } ad.Damage = (int)((double)ad.Damage * (1.0 + caster.GetModified(eProperty.SpellDamage) * 0.01)); // Block bool blocked = false; if (target is GamePlayer) { // mobs left out yet GamePlayer player = (GamePlayer)target; InventoryItem lefthand = player.Inventory.GetItem(eInventorySlot.LeftHandWeapon); if (lefthand != null && (player.AttackWeapon == null || player.AttackWeapon.Item_Type == Slot.RIGHTHAND || player.AttackWeapon.Item_Type == Slot.LEFTHAND)) { if (target.IsObjectInFront(caster, 180) && lefthand.Object_Type == (int)eObjectType.Shield) { double shield = 0.5 * player.GetModifiedSpecLevel(Specs.Shields); double blockchance = ((player.Dexterity * 2) - 100) / 40.0 + shield + 5; // Removed 30% increased chance to block, can find no clear evidence this is correct - tolakram blockchance -= target.GetConLevel(caster) * 5; if (blockchance >= 100) { blockchance = 99; } if (blockchance <= 0) { blockchance = 1; } if (target.IsEngaging) { EngageEffect engage = target.EffectList.GetOfType <EngageEffect>(); if (engage != null && target.AttackState && engage.EngageTarget == caster) { // Engage raised block change to 85% if attacker is engageTarget and player is in attackstate // You cannot engage a mob that was attacked within the last X seconds... if (engage.EngageTarget.LastAttackedByEnemyTick > engage.EngageTarget.CurrentRegion.Time - EngageAbilityHandler.ENGAGE_ATTACK_DELAY_TICK) { if (engage.Owner is GamePlayer) { (engage.Owner as GamePlayer).Out.SendMessage(engage.EngageTarget.GetName(0, true) + " has been attacked recently and you are unable to engage.", eChatType.CT_System, eChatLoc.CL_SystemWindow); } } // Check if player has enough endurance left to engage else if (engage.Owner.Endurance < EngageAbilityHandler.ENGAGE_DURATION_LOST) { engage.Cancel(false); // if player ran out of endurance cancel engage effect } else { engage.Owner.Endurance -= EngageAbilityHandler.ENGAGE_DURATION_LOST; if (engage.Owner is GamePlayer) { (engage.Owner as GamePlayer).Out.SendMessage("You concentrate on blocking the blow!", eChatType.CT_Skill, eChatLoc.CL_SystemWindow); } if (blockchance < 85) { blockchance = 85; } } } } if (blockchance >= Util.Random(1, 100)) { m_handler.MessageToLiving(player, "You partially block " + caster.GetName(0, false) + "'s spell!", eChatType.CT_Missed); m_handler.MessageToCaster(player.GetName(0, true) + " blocks!", eChatType.CT_YouHit); blocked = true; } } } } double effectiveness = 1.0 + (caster.GetModified(eProperty.SpellDamage) * 0.01); // simplified melee damage calculation if (blocked == false) { // TODO: armor resists to damage type double damage = m_handler.Spell.Damage / 2; // another half is physical damage if (target is GamePlayer) { ad.ArmorHitLocation = ((GamePlayer)target).CalculateArmorHitLocation(ad); } InventoryItem armor = null; if (target.Inventory != null) { armor = target.Inventory.GetItem((eInventorySlot)ad.ArmorHitLocation); } double ws = (caster.Level * 8 * (1.0 + (caster.GetModified(eProperty.Dexterity) - 50) / 200.0)); damage *= ((ws + 90.68) / (target.GetArmorAF(ad.ArmorHitLocation) + 20 * 4.67)); damage *= 1.0 - Math.Min(0.85, ad.Target.GetArmorAbsorb(ad.ArmorHitLocation)); ad.Modifier = (int)(damage * (ad.Target.GetResist(ad.DamageType) + SkillBase.GetArmorResist(armor, ad.DamageType)) / -100.0); damage += ad.Modifier; damage = damage * effectiveness; damage *= (1.0 + RelicMgr.GetRelicBonusModifier(caster.Realm, eRelicType.Magic)); if (damage < 0) { damage = 0; } ad.Damage += (int)damage; } if (m_handler is SiegeArrow == false) { ad.UncappedDamage = ad.Damage; ad.Damage = (int)Math.Min(ad.Damage, m_handler.DamageCap(effectiveness)); } ad.Damage = (int)(ad.Damage * caster.Effectiveness); if (blocked == false && ad.CriticalDamage > 0) { int critMax = (target is GamePlayer) ? ad.Damage / 2 : ad.Damage; ad.CriticalDamage = Util.Random(critMax / 10, critMax); } m_handler.SendDamageMessages(ad); m_handler.DamageTarget(ad, false, (blocked ? 0x02 : 0x14)); target.StartInterruptTimer(target.SpellInterruptDuration, ad.AttackType, caster); }
public override void SendWarmapBonuses() { if (m_gameClient.Player == null) { return; } int AlbTowers = 0; int MidTowers = 0; int HibTowers = 0; int AlbKeeps = 0; int MidKeeps = 0; int HibKeeps = 0; int OwnerDFTowers = 0; eRealm OwnerDF = eRealm.None; foreach (AbstractGameKeep keep in GameServer.KeepManager.GetFrontierKeeps()) { switch ((eRealm)keep.Realm) { case eRealm.Albion: if (keep is GameKeep) { AlbKeeps++; } else { AlbTowers++; } break; case eRealm.Midgard: if (keep is GameKeep) { MidKeeps++; } else { MidTowers++; } break; case eRealm.Hibernia: if (keep is GameKeep) { HibKeeps++; } else { HibTowers++; } break; default: break; } } if (AlbTowers > MidTowers && AlbTowers > HibTowers) { OwnerDF = eRealm.Albion; OwnerDFTowers = AlbTowers; } else if (MidTowers > AlbTowers && MidTowers > HibTowers) { OwnerDF = eRealm.Midgard; OwnerDFTowers = MidTowers; } else if (HibTowers > AlbTowers && HibTowers > MidTowers) { OwnerDF = eRealm.Hibernia; OwnerDFTowers = HibTowers; } using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.WarmapBonuses))) { int RealmKeeps = 0; int RealmTowers = 0; switch ((eRealm)m_gameClient.Player.Realm) { case eRealm.Albion: RealmKeeps = AlbKeeps; RealmTowers = AlbTowers; break; case eRealm.Midgard: RealmKeeps = MidKeeps; RealmTowers = MidTowers; break; case eRealm.Hibernia: RealmKeeps = HibKeeps; RealmTowers = HibTowers; break; default: break; } pak.WriteByte((byte)RealmKeeps); pak.WriteByte((byte)(((byte)RelicMgr.GetRelicCount(m_gameClient.Player.Realm, eRelicType.Magic)) << 4 | (byte)RelicMgr.GetRelicCount(m_gameClient.Player.Realm, eRelicType.Strength))); pak.WriteByte((byte)OwnerDF); pak.WriteByte((byte)RealmTowers); pak.WriteByte((byte)OwnerDFTowers); SendTCP(pak); } }
/* Relic status * * Albion Relics: * Strength: OwnerRealm * Power: OwnerRealm * * Midgard Relics: * Strength: OwnerRealm * Power: OwnerRealm * * Hibernia Relics: * Strength: OwnerRealm * Power: OwnerRealm * * Use '/realm' for Realm Info. */ public void OnCommand(GameClient client, string[] args) { if (IsSpammingCommand(client.Player, "relic")) { return; } string albStr = "", albPwr = "", midStr = "", midPwr = "", hibStr = "", hibPwr = ""; var relicInfo = new List <string>(); #region Reformat Relics '[Type]: [OwnerRealm]' foreach (GameRelic relic in RelicMgr.getNFRelics()) { switch (relic.OriginalRealm) { case eRealm.Albion: { if (relic.RelicType == eRelicType.Strength) { albStr = LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Strength") + ": " + GlobalConstants.RealmToName(relic.Realm); } if (relic.RelicType == eRelicType.Magic) { albPwr = LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Power") + ": " + GlobalConstants.RealmToName(relic.Realm); } break; } case eRealm.Midgard: { if (relic.RelicType == eRelicType.Strength) { midStr = LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Strength") + ": " + GlobalConstants.RealmToName(relic.Realm); } if (relic.RelicType == eRelicType.Magic) { midPwr = LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Power") + ": " + GlobalConstants.RealmToName(relic.Realm); } break; } case eRealm.Hibernia: { if (relic.RelicType == eRelicType.Strength) { hibStr = LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Strength") + ": " + GlobalConstants.RealmToName(relic.Realm); } if (relic.RelicType == eRelicType.Magic) { hibPwr = LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Power") + ": " + GlobalConstants.RealmToName(relic.Realm); } break; } } } #endregion relicInfo.Add(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.AlbRelics") + ":"); relicInfo.Add(albStr); relicInfo.Add(albPwr); relicInfo.Add(""); relicInfo.Add(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.MidRelics") + ":"); relicInfo.Add(midStr); relicInfo.Add(midPwr); relicInfo.Add(""); relicInfo.Add(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.HibRelics") + ":"); relicInfo.Add(hibStr); relicInfo.Add(hibPwr); relicInfo.Add(""); relicInfo.Add(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.UseRealmCommand")); client.Out.SendCustomTextWindow(LanguageMgr.GetTranslation(client.Account.Language, "Scripts.Players.Relic.Title"), relicInfo); }