/// <summary> /// called when spell effect has to be started and applied to targets /// </summary> public override bool StartSpell(GameLiving target) { if (target == null) { return(false); } if (m_maxTick >= 0) { m_maxTick = (Spell.Pulse > 1)?Spell.Pulse:1; m_currentTick = 1; m_currentSource = target; } int ticksToTarget = m_currentSource.GetDistanceTo(target) * 100 / 85; // 85 units per 1/10s int delay = 1 + ticksToTarget / 100; foreach (GamePlayer player in target.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) { player.Out.SendSpellEffectAnimation(m_currentSource, target, m_spell.ClientEffect, (ushort)(delay), false, 1); } BoltOnTargetAction bolt = new BoltOnTargetAction(Caster, target, this); bolt.Start(1 + ticksToTarget); m_currentSource = target; m_currentTick++; return(true); }
/// <summary> /// Begins the callback between this gameliving source and target (commences a bolt flying between them) /// </summary> /// <param name="source"></param> /// <param name="target"></param> public void DealLightning() { int ticksToTarget = currentSource.GetDistanceTo(currentTarget) * 100 / 85; // 85 units per 1/10s int delay = 1 + ticksToTarget / 100; foreach (GamePlayer player in currentTarget.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) { player.Out.SendSpellEffectAnimation(currentSource, currentTarget, m_spell.ClientEffect, (ushort)(delay), false, 1); } BoltAction bolt = new BoltAction(this); bolt.Start(1 + ticksToTarget); }
/// <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); }
private void DamageTarget(GameLiving target) { if (!GameServer.ServerRules.IsAllowedToAttack(_owner, target, true)) { return; } if (!target.IsAlive) { return; } if (_ticktimer.IsAlive) { _ticktimer.Stop(); removeHandlers(); } int dist = target.GetDistanceTo(new Point3D(_traparea.X, _traparea.Y, _traparea.Z)); double mod = 1; if (dist > 0) { mod = 1 - ((double)dist / 350); } int basedamage = (int)(_effectiveness * mod); int resist = (int)(basedamage * target.GetModified(eProperty.Resist_Energy) * -0.01); int damage = basedamage + resist; if (_owner is GamePlayer player) { player.Out.SendMessage($"You hit {target.Name} for {damage}({resist}) points of damage!", eChatType.CT_YouHit, eChatLoc.CL_SystemWindow); } if (target is GamePlayer targetPlayer) { if (targetPlayer.IsStealthed) { targetPlayer.Stealth(false); } } foreach (GamePlayer p in target.GetPlayersInRadius(false, WorldMgr.VISIBILITY_DISTANCE)) { p.Out.SendSpellEffectAnimation(_owner, target, 7026, 0, false, 1); p.Out.SendCombatAnimation(_owner, target, 0, 0, 0, 0, 0x14, target.HealthPercent); } // target.TakeDamage(owner, eDamageType.Energy, damage, 0); AttackData ad = new AttackData { AttackResult = GameLiving.eAttackResult.HitUnstyled, Attacker = _owner, Target = target, DamageType = eDamageType.Energy, Damage = damage }; target.OnAttackedByEnemy(ad); _owner.DealDamage(ad); }
private void DamageTarget(GameLiving target) { if (!GameServer.ServerRules.IsAllowedToAttack(owner, target, true)) return; if (!target.IsAlive) return; if (ticktimer.IsAlive) { ticktimer.Stop(); removeHandlers(); } int dist = target.GetDistanceTo( new Point3D( traparea.X, traparea.Y, traparea.Z ) ); double mod = 1; if (dist > 0) mod = 1 - ((double)dist / 350); int basedamage = (int)(effectiveness * mod); int resist = (int)(basedamage * target.GetModified(eProperty.Resist_Energy) * -0.01); int damage = basedamage + resist; GamePlayer player = owner as GamePlayer; if (player != null) { player.Out.SendMessage("You hit " + target.Name + " for " + damage + "(" + resist + ") points of damage!", eChatType.CT_YouHit, eChatLoc.CL_SystemWindow); } GamePlayer targetPlayer = target as GamePlayer; if (targetPlayer != null) { if (targetPlayer.IsStealthed) targetPlayer.Stealth(false); } foreach (GamePlayer p in target.GetPlayersInRadius(false, WorldMgr.VISIBILITY_DISTANCE)) { p.Out.SendSpellEffectAnimation(owner, target, 7026, 0, false, 1); p.Out.SendCombatAnimation(owner, target, 0, 0, 0, 0, 0x14, target.HealthPercent); } //target.TakeDamage(owner, eDamageType.Energy, damage, 0); AttackData ad = new AttackData(); ad.AttackResult = GameLiving.eAttackResult.HitUnstyled; ad.Attacker = owner; ad.Target = target; ad.DamageType = eDamageType.Energy; ad.Damage = damage; target.OnAttackedByEnemy(ad); owner.DealDamage(ad); }