Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Attempt to hit our target.
- // Calculating damage
- // Damaging target ( OnTakeDamage() / @GetHit )
- // pCharTarg = the target.
- // RETURN:
- // WAR_SWING_INVALID = target is invalid
- // WAR_SWING_EQUIPPING = recoiling weapon / swing made
- // WAR_SWING_READY = can't take my swing right now. but I'm ready to hit
- // WAR_SWING_SWINGING = taking my swing now
- WAR_SWING_TYPE CChar::Fight_Hit( CChar * pCharTarg )
- {
- ADDTOCALLSTACK("CChar::Fight_Hit");
- if ( !pCharTarg || (pCharTarg == this) )
- return WAR_SWING_INVALID;
- DAMAGE_TYPE iTyp = DAMAGE_HIT_BLUNT;
- if ( IsTrigUsed(TRIGGER_HITCHECK) )
- {
- CScriptTriggerArgs pArgs;
- pArgs.m_iN1 = m_atFight.m_Swing_State;
- pArgs.m_iN2 = iTyp;
- TRIGRET_TYPE tRet = OnTrigger(CTRIG_HitCheck, pCharTarg, &pArgs);
- if ( tRet == TRIGRET_RET_TRUE )
- return static_cast<WAR_SWING_TYPE>(pArgs.m_iN1);
- if ( tRet == -1 )
- return WAR_SWING_INVALID;
- m_atFight.m_Swing_State = static_cast<WAR_SWING_TYPE>(pArgs.m_iN1);
- iTyp = static_cast<DAMAGE_TYPE>(pArgs.m_iN2);
- if ( (m_atFight.m_Swing_State == WAR_SWING_SWINGING) && (iTyp & DAMAGE_FIXED) )
- {
- if ( tRet == TRIGRET_RET_DEFAULT )
- return WAR_SWING_EQUIPPING;
- if ( iTyp == DAMAGE_HIT_BLUNT ) // if type did not change in the trigger, default iTyp is set
- {
- CItem *pWeapon = m_uidWeapon.ItemFind();
- if ( pWeapon )
- {
- CVarDefCont *pDamTypeOverride = pWeapon->GetKey("OVERRIDE.DAMAGETYPE", true);
- if ( pDamTypeOverride )
- iTyp = static_cast<DAMAGE_TYPE>(pDamTypeOverride->GetValNum());
- else
- {
- CItemBase *pWeaponDef = pWeapon->Item_GetDef();
- switch ( pWeaponDef->GetType() )
- {
- case IT_WEAPON_SWORD:
- case IT_WEAPON_AXE:
- case IT_WEAPON_THROWING:
- iTyp |= DAMAGE_HIT_SLASH;
- break;
- case IT_WEAPON_FENCE:
- case IT_WEAPON_BOW:
- case IT_WEAPON_XBOW:
- iTyp |= DAMAGE_HIT_PIERCE;
- break;
- default:
- break;
- }
- }
- }
- }
- if ( iTyp & DAMAGE_FIXED )
- iTyp &= ~DAMAGE_FIXED;
- pCharTarg->OnTakeDamage(
- Fight_CalcDamage(m_uidWeapon.ItemFind()),
- this,
- iTyp,
- static_cast<int>(GetDefNum("DAMPHYSICAL")),
- static_cast<int>(GetDefNum("DAMFIRE")),
- static_cast<int>(GetDefNum("DAMCOLD")),
- static_cast<int>(GetDefNum("DAMPOISON")),
- static_cast<int>(GetDefNum("DAMENERGY"))
- );
- return WAR_SWING_EQUIPPING;
- }
- }
- // Very basic check on possibility to hit
- if ( IsStatFlag(STATF_DEAD|STATF_Sleeping|STATF_Freeze|STATF_Stone) || !pCharTarg->Fight_IsAttackable() )
- return WAR_SWING_INVALID;
- if ( pCharTarg->m_pArea && pCharTarg->m_pArea->IsFlag(REGION_FLAG_SAFE) )
- return WAR_SWING_INVALID;
- int iDist = GetTopDist3D(pCharTarg);
- if ( iDist > UO_MAP_VIEW_SIZE )
- return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_INVALID;
- // I am on ship. Should be able to combat only inside the ship to avoid free sea and ground characters hunting
- if ( (m_pArea != pCharTarg->m_pArea) && !IsSetCombatFlags(COMBAT_ALLOWHITFROMSHIP) )
- {
- if ( m_pArea && m_pArea->IsFlag(REGION_FLAG_SHIP) )
- {
- SysMessageDefault(DEFMSG_COMBAT_OUTSIDESHIP);
- return WAR_SWING_INVALID;
- }
- if ( pCharTarg->m_pArea && pCharTarg->m_pArea->IsFlag(REGION_FLAG_SHIP) )
- {
- SysMessageDefault(DEFMSG_COMBAT_INSIDESHIP);
- return WAR_SWING_INVALID;
- }
- }
- // Fix of the bounce back effect with dir update for clients to be able to run in combat easily
- if ( m_pClient && IsSetCombatFlags(COMBAT_FACECOMBAT) )
- {
- DIR_TYPE dirOpponent = GetDir(pCharTarg, m_dirFace);
- if ( (dirOpponent != m_dirFace) && (dirOpponent != GetDirTurn(m_dirFace, -1)) && (dirOpponent != GetDirTurn(m_dirFace, 1)) )
- return WAR_SWING_READY;
- }
- if ( IsSetCombatFlags(COMBAT_PREHIT) && (m_atFight.m_Swing_State == WAR_SWING_READY) )
- {
- INT64 diff = GetKeyNum("LastHit") - g_World.GetCurrentTime().GetTimeRaw();
- if ( diff > 0 )
- {
- SetTimeout(minimum(diff, 50));
- return WAR_SWING_READY;
- }
- }
- CItem *pWeapon = m_uidWeapon.ItemFind();
- CItem *pAmmo = NULL;
- CItemBase *pWeaponDef = NULL;
- CVarDefCont *pType = NULL;
- CVarDefCont *pCont = NULL;
- CVarDefCont *pAnim = NULL;
- CVarDefCont *pColor = NULL;
- CVarDefCont *pRender = NULL;
- if ( pWeapon )
- {
- pType = pWeapon->GetDefKey("AMMOTYPE", true);
- pCont = pWeapon->GetDefKey("AMMOCONT", true);
- pAnim = pWeapon->GetDefKey("AMMOANIM", true);
- pColor = pWeapon->GetDefKey("AMMOANIMHUE", true);
- pRender = pWeapon->GetDefKey("AMMOANIMRENDER", true);
- CVarDefCont *pDamTypeOverride = pWeapon->GetKey("OVERRIDE.DAMAGETYPE", true);
- if ( pDamTypeOverride )
- iTyp = static_cast<DAMAGE_TYPE>(pDamTypeOverride->GetValNum());
- else
- {
- pWeaponDef = pWeapon->Item_GetDef();
- switch ( pWeaponDef->GetType() )
- {
- case IT_WEAPON_SWORD:
- case IT_WEAPON_AXE:
- case IT_WEAPON_THROWING:
- iTyp |= DAMAGE_HIT_SLASH;
- break;
- case IT_WEAPON_FENCE:
- case IT_WEAPON_BOW:
- case IT_WEAPON_XBOW:
- iTyp |= DAMAGE_HIT_PIERCE;
- break;
- default:
- break;
- }
- }
- }
- SKILL_TYPE skill = Skill_GetActive();
- RESOURCE_ID_BASE rid;
- LPCTSTR t_Str;
- if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
- {
- if ( IsStatFlag(STATF_HasShield) ) // this should never happen
- {
- SysMessageDefault(DEFMSG_ITEMUSE_BOW_SHIELD);
- return WAR_SWING_INVALID;
- }
- else if ( !IsSetCombatFlags(COMBAT_ARCHERYCANMOVE) && !IsStatFlag(STATF_ArcherCanMove) )
- {
- // Only start swing 1sec after the char stop moving (TO-DO: add .ini option to customize this delay -> SE:250ms / AOS:500ms / pre-AOS:1000ms)
- if ( m_pClient && -g_World.GetTimeDiff(m_pClient->m_timeLastEventWalk) < TICK_PER_SEC )
- return WAR_SWING_EQUIPPING;
- }
- int iMinDist = pWeapon ? pWeapon->RangeH() : g_Cfg.m_iArcheryMinDist;
- int iMaxDist = pWeapon ? pWeapon->RangeL() : g_Cfg.m_iArcheryMaxDist;
- if ( !iMaxDist || (iMinDist == 0 && iMaxDist == 1) )
- iMaxDist = g_Cfg.m_iArcheryMaxDist;
- if ( !iMinDist )
- iMinDist = g_Cfg.m_iArcheryMinDist;
- if ( iDist < iMinDist )
- {
- SysMessageDefault(DEFMSG_COMBAT_ARCH_TOOCLOSE);
- return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_READY;
- }
- if ( iDist > iMaxDist )
- return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_READY;
- if ( pType )
- {
- t_Str = pType->GetValStr();
- rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
- }
- else
- rid = pWeaponDef->m_ttWeaponBow.m_idAmmo;
- ITEMID_TYPE AmmoID = static_cast<ITEMID_TYPE>(rid.GetResIndex());
- if ( AmmoID )
- {
- if ( pCont )
- {
- CGrayUID uidCont = static_cast<CGrayUID>(static_cast<DWORD>(pCont->GetValNum()));
- CItemContainer *pNewCont = static_cast<CItemContainer *>(uidCont.ItemFind());
- if ( !pNewCont ) //if no UID, check for ITEMID_TYPE
- {
- t_Str = pCont->GetValStr();
- RESOURCE_ID_BASE rContid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
- ITEMID_TYPE ContID = static_cast<ITEMID_TYPE>(rContid.GetResIndex());
- if ( ContID )
- pNewCont = static_cast<CItemContainer *>(ContentFind(rContid));
- }
- pAmmo = (pNewCont) ? pNewCont->ContentFind(rid) : ContentFind(rid);
- }
- else
- pAmmo = ContentFind(rid);
- if ( !pAmmo && m_pPlayer )
- {
- SysMessageDefault(DEFMSG_COMBAT_ARCH_NOAMMO);
- return WAR_SWING_INVALID;
- }
- }
- }
- else
- {
- int iMinDist = pWeapon ? pWeapon->RangeH() : 0;
- int iMaxDist = CalcFightRange(pWeapon);
- if ( iDist < iMinDist || iDist > iMaxDist )
- return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_READY;
- }
- // Start the swing
- if ( m_atFight.m_Swing_State == WAR_SWING_READY )
- {
- if ( !CanSeeLOS(pCharTarg) )
- return WAR_SWING_EQUIPPING;
- ANIM_TYPE anim = GenerateAnimate(ANIM_ATTACK_WEAPON);
- int animDelay = 7; // attack speed is always 7ms and then the char keep waiting the remaining time
- int iSwingDelay = g_Cfg.Calc_CombatAttackSpeed(this, pWeapon) - 1; // swings are started only on the next tick, so substract -1 to compensate that
- if ( IsTrigUsed(TRIGGER_HITTRY) )
- {
- CScriptTriggerArgs Args(iSwingDelay, 0, pWeapon);
- Args.m_VarsLocal.SetNum("Anim", static_cast<int>(anim));
- Args.m_VarsLocal.SetNum("AnimDelay", animDelay);
- if ( OnTrigger(CTRIG_HitTry, pCharTarg, &Args) == TRIGRET_RET_TRUE )
- return WAR_SWING_READY;
- iSwingDelay = static_cast<int>(Args.m_iN1);
- anim = static_cast<ANIM_TYPE>(Args.m_VarsLocal.GetKeyNum("Anim"));
- animDelay = static_cast<int>(Args.m_VarsLocal.GetKeyNum("AnimDelay"));
- if ( iSwingDelay < 0 )
- iSwingDelay = 0;
- if ( animDelay < 0 )
- animDelay = 0;
- }
- m_atFight.m_Swing_State = WAR_SWING_SWINGING;
- m_atFight.m_Swing_Delay = maximum(0, iSwingDelay - animDelay);
- if ( IsSetCombatFlags(COMBAT_PREHIT) )
- {
- SetKeyNum("LastHit", g_World.GetCurrentTime().GetTimeRaw() + iSwingDelay);
- SetTimeout(0);
- }
- else
- SetTimeout(animDelay);
- Reveal();
- if ( !IsSetCombatFlags(COMBAT_NODIRCHANGE) )
- UpdateDir(pCharTarg);
- UpdateAnimate(anim, false, false, static_cast<BYTE>(animDelay / TICK_PER_SEC));
- return WAR_SWING_SWINGING;
- }
- m_atFight.m_Swing_NextAction = CServTime::GetCurrentTime() + m_atFight.m_Swing_Delay;
- if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
- {
- // Post-swing behavior
- ITEMID_TYPE AmmoAnim;
- if ( pAnim )
- {
- t_Str = pAnim->GetValStr();
- rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
- AmmoAnim = static_cast<ITEMID_TYPE>(rid.GetResIndex());
- }
- else
- AmmoAnim = static_cast<ITEMID_TYPE>(pWeaponDef->m_ttWeaponBow.m_idAmmoX.GetResIndex());
- DWORD AmmoHue = 0;
- if ( pColor )
- AmmoHue = static_cast<DWORD>(pColor->GetValNum());
- DWORD AmmoRender = 0;
- if ( pRender )
- AmmoRender = static_cast<DWORD>(pRender->GetValNum());
- pCharTarg->Effect(EFFECT_BOLT, AmmoAnim, this, 18, 1, false, AmmoHue, AmmoRender);
- }
- // We made our swing. so we must recoil.
- m_atFight.m_Swing_State = WAR_SWING_EQUIPPING;
- // We missed
- if ( m_Act_Difficulty < 0 )
- {
- if ( IsTrigUsed(TRIGGER_HITMISS) )
- {
- CScriptTriggerArgs Args(0, 0, pWeapon);
- if ( pAmmo )
- Args.m_VarsLocal.SetNum("Arrow", pAmmo->GetUID());
- if ( OnTrigger(CTRIG_HitMiss, pCharTarg, &Args) == TRIGRET_RET_TRUE )
- return WAR_SWING_EQUIPPING;
- if ( Args.m_VarsLocal.GetKeyNum("ArrowHandled") != 0 ) // if arrow is handled by script, do nothing with it further!
- pAmmo = NULL;
- }
- if ( pAmmo && m_pPlayer && (40 >= Calc_GetRandVal(100)) )
- {
- pAmmo->UnStackSplit(1);
- pAmmo->MoveToDecay(pCharTarg->GetTopPoint(), g_Cfg.m_iDecay_Item);
- }
- SOUND_TYPE iSound = 0;
- if ( pWeapon )
- iSound = static_cast<SOUND_TYPE>(pWeapon->GetDefNum("AMMOSOUNDMISS"));
- if ( !iSound )
- {
- if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
- {
- static const SOUND_TYPE sm_Snd_Miss[] = { 0x233, 0x238 };
- iSound = sm_Snd_Miss[Calc_GetRandVal(COUNTOF(sm_Snd_Miss))];
- }
- else
- {
- static const SOUND_TYPE sm_Snd_Miss[] = { 0x238, 0x239, 0x23a };
- iSound = sm_Snd_Miss[Calc_GetRandVal(COUNTOF(sm_Snd_Miss))];
- }
- }
- if ( IsPriv(PRIV_DETAIL) )
- SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_COMBAT_MISSS), pCharTarg->GetName());
- if ( pCharTarg->IsPriv(PRIV_DETAIL) )
- pCharTarg->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_COMBAT_MISSO), GetName());
- Sound(iSound);
- return WAR_SWING_EQUIPPING;
- }
- // We hit
- if ( !(iTyp & DAMAGE_GOD) )
- {
- // Check if target will block the hit
- // Legacy pre-SE formula
- CItem *pItemHit = NULL;
- int ParryChance = 0;
- if ( pCharTarg->IsStatFlag(STATF_HasShield) ) // parry using shield
- {
- pItemHit = pCharTarg->LayerFind(LAYER_HAND2);
- ParryChance = pCharTarg->Skill_GetBase(SKILL_PARRYING) / 40;
- }
- else if ( pCharTarg->m_uidWeapon.IsItem() ) // parry using weapon
- {
- pItemHit = pCharTarg->m_uidWeapon.ItemFind();
- ParryChance = pCharTarg->Skill_GetBase(SKILL_PARRYING) / 80;
- }
- if ( pCharTarg->Skill_GetBase(SKILL_PARRYING) >= 1000 )
- ParryChance += 5;
- int Dex = pCharTarg->Stat_GetAdjusted(STAT_DEX);
- if ( Dex < 80 )
- ParryChance = ParryChance * (20 + Dex) / 100;
- if ( pCharTarg->Skill_UseQuick(SKILL_PARRYING, ParryChance, true, false) )
- {
- if ( IsPriv(PRIV_DETAIL) )
- SysMessageDefault(DEFMSG_COMBAT_PARRY);
- if ( pItemHit )
- pItemHit->OnTakeDamage(1, this, iTyp);
- //Effect(EFFECT_OBJ, ITEMID_FX_GLOW, this, 10, 16); // moved to scripts (@UseQuick on Parrying skill)
- return WAR_SWING_EQUIPPING;
- }
- }
- // Calculate base damage
- int iDmg = Fight_CalcDamage(pWeapon);
- CScriptTriggerArgs Args(iDmg, iTyp, pWeapon);
- Args.m_VarsLocal.SetNum("ItemDamageChance", 40);
- if ( pAmmo )
- Args.m_VarsLocal.SetNum("Arrow", pAmmo->GetUID());
- if ( IsTrigUsed(TRIGGER_SKILLSUCCESS) )
- {
- if ( Skill_OnCharTrigger(skill, CTRIG_SkillSuccess) == TRIGRET_RET_TRUE )
- {
- Skill_Cleanup();
- return WAR_SWING_EQUIPPING; // ok, so no hit - skill failed. Pah!
- }
- }
- if ( IsTrigUsed(TRIGGER_SUCCESS) )
- {
- if ( Skill_OnTrigger(skill, SKTRIG_SUCCESS) == TRIGRET_RET_TRUE )
- {
- Skill_Cleanup();
- return WAR_SWING_EQUIPPING; // ok, so no hit - skill failed. Pah!
- }
- }
- if ( IsTrigUsed(TRIGGER_HIT) )
- {
- if ( OnTrigger(CTRIG_Hit, pCharTarg, &Args) == TRIGRET_RET_TRUE )
- return WAR_SWING_EQUIPPING;
- if ( Args.m_VarsLocal.GetKeyNum("ArrowHandled") != 0 ) // if arrow is handled by script, do nothing with it further
- pAmmo = NULL;
- iDmg = static_cast<int>(Args.m_iN1);
- iTyp = static_cast<DAMAGE_TYPE>(Args.m_iN2);
- }
- // BAD BAD Healing fix.. Cant think of something else -- Radiant
- if ( pCharTarg->m_Act_SkillCurrent == SKILL_HEALING )
- {
- pCharTarg->SysMessageDefault(DEFMSG_HEALING_INTERRUPT);
- pCharTarg->Skill_Cleanup();
- }
- if ( pAmmo )
- {
- pAmmo->UnStackSplit(1);
- if ( pCharTarg->m_pNPC && (40 >= Calc_GetRandVal(100)) )
- pCharTarg->ItemBounce(pAmmo, false);
- else
- pAmmo->Delete();
- }
- // Hit noise (based on weapon type)
- SoundChar(CRESND_HIT);
- if ( pWeapon )
- {
- // Check if the weapon is poisoned
- if ( !IsSetCombatFlags(COMBAT_NOPOISONHIT) && pWeapon->m_itWeapon.m_poison_skill && pWeapon->m_itWeapon.m_poison_skill > Calc_GetRandVal(100) )
- {
- BYTE iPoisonDeliver = static_cast<BYTE>(Calc_GetRandVal(pWeapon->m_itWeapon.m_poison_skill));
- pCharTarg->SetPoison(10 * iPoisonDeliver, iPoisonDeliver / 5, this);
- pWeapon->m_itWeapon.m_poison_skill -= iPoisonDeliver / 2; // reduce weapon poison charges
- pWeapon->UpdatePropertyFlag(AUTOTOOLTIP_FLAG_POISON);
- }
- // Check if the weapon will be damaged
- int iDamageChance = static_cast<int>(Args.m_VarsLocal.GetKeyNum("ItemDamageChance"));
- if ( iDamageChance > Calc_GetRandVal(100) )
- pWeapon->OnTakeDamage(iDmg, pCharTarg);
- }
- else if ( NPC_IsMonster() )
- {
- // Base poisoning for NPCs
- if ( !IsSetCombatFlags(COMBAT_NOPOISONHIT) && 50 >= Calc_GetRandVal(100) )
- {
- int iPoisoningSkill = Skill_GetBase(SKILL_POISONING);
- if ( iPoisoningSkill )
- pCharTarg->SetPoison(Calc_GetRandVal(iPoisoningSkill), Calc_GetRandVal(iPoisoningSkill / 50), this);
- }
- }
- // Took my swing. Do Damage !
- iDmg = pCharTarg->OnTakeDamage(
- iDmg,
- this,
- iTyp,
- static_cast<int>(GetDefNum("DAMPHYSICAL", true)),
- static_cast<int>(GetDefNum("DAMFIRE", true)),
- static_cast<int>(GetDefNum("DAMCOLD", true)),
- static_cast<int>(GetDefNum("DAMPOISON", true)),
- static_cast<int>(GetDefNum("DAMENERGY", true))
- );
- if ( iDmg > 0 )
- {
- CItem *pCurseWeapon = LayerFind(LAYER_SPELL_Curse_Weapon);
- short iHitLifeLeech = static_cast<short>(GetDefNum("HitLeechLife"));
- if ( pWeapon && pCurseWeapon )
- iHitLifeLeech += pCurseWeapon->m_itSpell.m_spelllevel;
- bool bMakeLeechSound = false;
- if ( iHitLifeLeech )
- {
- iHitLifeLeech = static_cast<short>(Calc_GetRandVal2(0, (iDmg * iHitLifeLeech * 30) / 10000)); // leech 0% ~ 30% of damage value
- UpdateStatVal(STAT_STR, iHitLifeLeech, Stat_GetMax(STAT_STR));
- bMakeLeechSound = true;
- }
- short iHitManaLeech = static_cast<short>(GetDefNum("HitLeechMana"));
- if ( iHitManaLeech )
- {
- iHitManaLeech = static_cast<short>(Calc_GetRandVal2(0, (iDmg * iHitManaLeech * 40) / 10000)); // leech 0% ~ 40% of damage value
- UpdateStatVal(STAT_INT, iHitManaLeech, Stat_GetMax(STAT_INT));
- bMakeLeechSound = true;
- }
- if ( GetDefNum("HitLeechStam") > Calc_GetRandLLVal(100) )
- {
- UpdateStatVal(STAT_DEX, static_cast<short>(iDmg), Stat_GetMax(STAT_DEX)); // leech 100% of damage value
- bMakeLeechSound = true;
- }
- short iManaDrain = 0;
- if ( g_Cfg.m_iFeatureAOS & FEATURE_AOS_UPDATE_B )
- {
- CItem *pPoly = LayerFind(LAYER_SPELL_Polymorph);
- if ( pPoly && pPoly->m_itSpell.m_spell == SPELL_Wraith_Form )
- iManaDrain += 5 + (15 * Skill_GetBase(SKILL_SPIRITSPEAK) / 1000);
- }
- if ( GetDefNum("HitManaDrain") > Calc_GetRandLLVal(100) )
- iManaDrain += IMULDIV(static_cast<short>(iDmg), 20, 100); // leech 20% of damage value
- short iTargMana = pCharTarg->Stat_GetVal(STAT_INT);
- if ( iManaDrain > iTargMana )
- iManaDrain = iTargMana;
- if ( iManaDrain > 0 )
- {
- pCharTarg->UpdateStatVal(STAT_INT, iTargMana - iManaDrain);
- UpdateStatVal(STAT_INT, iManaDrain, Stat_GetMax(STAT_INT));
- bMakeLeechSound = true;
- }
- if ( bMakeLeechSound )
- Sound(0x44d);
- // Make blood effects
- if ( pCharTarg->m_wBloodHue != static_cast<HUE_TYPE>(-1) )
- {
- static const ITEMID_TYPE sm_Blood[] = { ITEMID_BLOOD1, ITEMID_BLOOD2, ITEMID_BLOOD3, ITEMID_BLOOD4, ITEMID_BLOOD5, ITEMID_BLOOD6, ITEMID_BLOOD_SPLAT };
- int iBloodQty = (g_Cfg.m_iFeatureSE & FEATURE_SE_UPDATE) ? Calc_GetRandVal2(4, 5) : Calc_GetRandVal2(1, 2);
- for ( int i = 0; i < iBloodQty; i++ )
- {
- ITEMID_TYPE iBloodID = sm_Blood[Calc_GetRandVal(COUNTOF(sm_Blood))];
- CItem *pBlood = CItem::CreateBase(iBloodID);
- ASSERT(pBlood);
- pBlood->SetHue(pCharTarg->m_wBloodHue);
- pBlood->MoveNear(pCharTarg->GetTopPoint(), 1);
- pBlood->SetDecayTime(5 * TICK_PER_SEC);
- }
- }
- // Check for passive skill gain
- if ( m_pPlayer && !pCharTarg->m_pArea->IsFlag(REGION_FLAG_NO_PVP) )
- {
- Skill_Experience(skill, m_Act_Difficulty);
- Skill_Experience(SKILL_TACTICS, m_Act_Difficulty);
- }
- }
- return WAR_SWING_EQUIPPING;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement