Advertisement
Guest User

Untitled

a guest
Apr 28th, 2017
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.25 KB | None | 0 0
  1. // Attempt to hit our target.
  2. // Calculating damage
  3. // Damaging target ( OnTakeDamage() / @GetHit )
  4. // pCharTarg = the target.
  5. // RETURN:
  6. // WAR_SWING_INVALID = target is invalid
  7. // WAR_SWING_EQUIPPING = recoiling weapon / swing made
  8. // WAR_SWING_READY = can't take my swing right now. but I'm ready to hit
  9. // WAR_SWING_SWINGING = taking my swing now
  10. WAR_SWING_TYPE CChar::Fight_Hit( CChar * pCharTarg )
  11. {
  12. ADDTOCALLSTACK("CChar::Fight_Hit");
  13.  
  14. if ( !pCharTarg || (pCharTarg == this) )
  15. return WAR_SWING_INVALID;
  16.  
  17. DAMAGE_TYPE iTyp = DAMAGE_HIT_BLUNT;
  18.  
  19. if ( IsTrigUsed(TRIGGER_HITCHECK) )
  20. {
  21. CScriptTriggerArgs pArgs;
  22. pArgs.m_iN1 = m_atFight.m_Swing_State;
  23. pArgs.m_iN2 = iTyp;
  24. TRIGRET_TYPE tRet = OnTrigger(CTRIG_HitCheck, pCharTarg, &pArgs);
  25. if ( tRet == TRIGRET_RET_TRUE )
  26. return static_cast<WAR_SWING_TYPE>(pArgs.m_iN1);
  27. if ( tRet == -1 )
  28. return WAR_SWING_INVALID;
  29.  
  30. m_atFight.m_Swing_State = static_cast<WAR_SWING_TYPE>(pArgs.m_iN1);
  31. iTyp = static_cast<DAMAGE_TYPE>(pArgs.m_iN2);
  32.  
  33. if ( (m_atFight.m_Swing_State == WAR_SWING_SWINGING) && (iTyp & DAMAGE_FIXED) )
  34. {
  35. if ( tRet == TRIGRET_RET_DEFAULT )
  36. return WAR_SWING_EQUIPPING;
  37.  
  38. if ( iTyp == DAMAGE_HIT_BLUNT ) // if type did not change in the trigger, default iTyp is set
  39. {
  40. CItem *pWeapon = m_uidWeapon.ItemFind();
  41. if ( pWeapon )
  42. {
  43. CVarDefCont *pDamTypeOverride = pWeapon->GetKey("OVERRIDE.DAMAGETYPE", true);
  44. if ( pDamTypeOverride )
  45. iTyp = static_cast<DAMAGE_TYPE>(pDamTypeOverride->GetValNum());
  46. else
  47. {
  48. CItemBase *pWeaponDef = pWeapon->Item_GetDef();
  49. switch ( pWeaponDef->GetType() )
  50. {
  51. case IT_WEAPON_SWORD:
  52. case IT_WEAPON_AXE:
  53. case IT_WEAPON_THROWING:
  54. iTyp |= DAMAGE_HIT_SLASH;
  55. break;
  56. case IT_WEAPON_FENCE:
  57. case IT_WEAPON_BOW:
  58. case IT_WEAPON_XBOW:
  59. iTyp |= DAMAGE_HIT_PIERCE;
  60. break;
  61. default:
  62. break;
  63. }
  64. }
  65. }
  66. }
  67. if ( iTyp & DAMAGE_FIXED )
  68. iTyp &= ~DAMAGE_FIXED;
  69.  
  70. pCharTarg->OnTakeDamage(
  71. Fight_CalcDamage(m_uidWeapon.ItemFind()),
  72. this,
  73. iTyp,
  74. static_cast<int>(GetDefNum("DAMPHYSICAL")),
  75. static_cast<int>(GetDefNum("DAMFIRE")),
  76. static_cast<int>(GetDefNum("DAMCOLD")),
  77. static_cast<int>(GetDefNum("DAMPOISON")),
  78. static_cast<int>(GetDefNum("DAMENERGY"))
  79. );
  80.  
  81. return WAR_SWING_EQUIPPING;
  82. }
  83. }
  84.  
  85. // Very basic check on possibility to hit
  86. if ( IsStatFlag(STATF_DEAD|STATF_Sleeping|STATF_Freeze|STATF_Stone) || !pCharTarg->Fight_IsAttackable() )
  87. return WAR_SWING_INVALID;
  88. if ( pCharTarg->m_pArea && pCharTarg->m_pArea->IsFlag(REGION_FLAG_SAFE) )
  89. return WAR_SWING_INVALID;
  90.  
  91. int iDist = GetTopDist3D(pCharTarg);
  92. if ( iDist > UO_MAP_VIEW_SIZE )
  93. return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_INVALID;
  94.  
  95. // I am on ship. Should be able to combat only inside the ship to avoid free sea and ground characters hunting
  96. if ( (m_pArea != pCharTarg->m_pArea) && !IsSetCombatFlags(COMBAT_ALLOWHITFROMSHIP) )
  97. {
  98. if ( m_pArea && m_pArea->IsFlag(REGION_FLAG_SHIP) )
  99. {
  100. SysMessageDefault(DEFMSG_COMBAT_OUTSIDESHIP);
  101. return WAR_SWING_INVALID;
  102. }
  103. if ( pCharTarg->m_pArea && pCharTarg->m_pArea->IsFlag(REGION_FLAG_SHIP) )
  104. {
  105. SysMessageDefault(DEFMSG_COMBAT_INSIDESHIP);
  106. return WAR_SWING_INVALID;
  107. }
  108. }
  109.  
  110. // Fix of the bounce back effect with dir update for clients to be able to run in combat easily
  111. if ( m_pClient && IsSetCombatFlags(COMBAT_FACECOMBAT) )
  112. {
  113. DIR_TYPE dirOpponent = GetDir(pCharTarg, m_dirFace);
  114. if ( (dirOpponent != m_dirFace) && (dirOpponent != GetDirTurn(m_dirFace, -1)) && (dirOpponent != GetDirTurn(m_dirFace, 1)) )
  115. return WAR_SWING_READY;
  116. }
  117.  
  118. if ( IsSetCombatFlags(COMBAT_PREHIT) && (m_atFight.m_Swing_State == WAR_SWING_READY) )
  119. {
  120. INT64 diff = GetKeyNum("LastHit") - g_World.GetCurrentTime().GetTimeRaw();
  121. if ( diff > 0 )
  122. {
  123. SetTimeout(minimum(diff, 50));
  124. return WAR_SWING_READY;
  125. }
  126. }
  127.  
  128. CItem *pWeapon = m_uidWeapon.ItemFind();
  129. CItem *pAmmo = NULL;
  130. CItemBase *pWeaponDef = NULL;
  131. CVarDefCont *pType = NULL;
  132. CVarDefCont *pCont = NULL;
  133. CVarDefCont *pAnim = NULL;
  134. CVarDefCont *pColor = NULL;
  135. CVarDefCont *pRender = NULL;
  136. if ( pWeapon )
  137. {
  138. pType = pWeapon->GetDefKey("AMMOTYPE", true);
  139. pCont = pWeapon->GetDefKey("AMMOCONT", true);
  140. pAnim = pWeapon->GetDefKey("AMMOANIM", true);
  141. pColor = pWeapon->GetDefKey("AMMOANIMHUE", true);
  142. pRender = pWeapon->GetDefKey("AMMOANIMRENDER", true);
  143. CVarDefCont *pDamTypeOverride = pWeapon->GetKey("OVERRIDE.DAMAGETYPE", true);
  144. if ( pDamTypeOverride )
  145. iTyp = static_cast<DAMAGE_TYPE>(pDamTypeOverride->GetValNum());
  146. else
  147. {
  148. pWeaponDef = pWeapon->Item_GetDef();
  149. switch ( pWeaponDef->GetType() )
  150. {
  151. case IT_WEAPON_SWORD:
  152. case IT_WEAPON_AXE:
  153. case IT_WEAPON_THROWING:
  154. iTyp |= DAMAGE_HIT_SLASH;
  155. break;
  156. case IT_WEAPON_FENCE:
  157. case IT_WEAPON_BOW:
  158. case IT_WEAPON_XBOW:
  159. iTyp |= DAMAGE_HIT_PIERCE;
  160. break;
  161. default:
  162. break;
  163. }
  164. }
  165. }
  166.  
  167. SKILL_TYPE skill = Skill_GetActive();
  168. RESOURCE_ID_BASE rid;
  169. LPCTSTR t_Str;
  170.  
  171. if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
  172. {
  173. if ( IsStatFlag(STATF_HasShield) ) // this should never happen
  174. {
  175. SysMessageDefault(DEFMSG_ITEMUSE_BOW_SHIELD);
  176. return WAR_SWING_INVALID;
  177. }
  178. else if ( !IsSetCombatFlags(COMBAT_ARCHERYCANMOVE) && !IsStatFlag(STATF_ArcherCanMove) )
  179. {
  180. // 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)
  181. if ( m_pClient && -g_World.GetTimeDiff(m_pClient->m_timeLastEventWalk) < TICK_PER_SEC )
  182. return WAR_SWING_EQUIPPING;
  183. }
  184.  
  185. int iMinDist = pWeapon ? pWeapon->RangeH() : g_Cfg.m_iArcheryMinDist;
  186. int iMaxDist = pWeapon ? pWeapon->RangeL() : g_Cfg.m_iArcheryMaxDist;
  187. if ( !iMaxDist || (iMinDist == 0 && iMaxDist == 1) )
  188. iMaxDist = g_Cfg.m_iArcheryMaxDist;
  189. if ( !iMinDist )
  190. iMinDist = g_Cfg.m_iArcheryMinDist;
  191.  
  192. if ( iDist < iMinDist )
  193. {
  194. SysMessageDefault(DEFMSG_COMBAT_ARCH_TOOCLOSE);
  195. return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_READY;
  196. }
  197. if ( iDist > iMaxDist )
  198. return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_READY;
  199.  
  200. if ( pType )
  201. {
  202. t_Str = pType->GetValStr();
  203. rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
  204. }
  205. else
  206. rid = pWeaponDef->m_ttWeaponBow.m_idAmmo;
  207.  
  208. ITEMID_TYPE AmmoID = static_cast<ITEMID_TYPE>(rid.GetResIndex());
  209. if ( AmmoID )
  210. {
  211. if ( pCont )
  212. {
  213. CGrayUID uidCont = static_cast<CGrayUID>(static_cast<DWORD>(pCont->GetValNum()));
  214. CItemContainer *pNewCont = static_cast<CItemContainer *>(uidCont.ItemFind());
  215. if ( !pNewCont ) //if no UID, check for ITEMID_TYPE
  216. {
  217. t_Str = pCont->GetValStr();
  218. RESOURCE_ID_BASE rContid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
  219. ITEMID_TYPE ContID = static_cast<ITEMID_TYPE>(rContid.GetResIndex());
  220. if ( ContID )
  221. pNewCont = static_cast<CItemContainer *>(ContentFind(rContid));
  222. }
  223.  
  224. pAmmo = (pNewCont) ? pNewCont->ContentFind(rid) : ContentFind(rid);
  225. }
  226. else
  227. pAmmo = ContentFind(rid);
  228.  
  229. if ( !pAmmo && m_pPlayer )
  230. {
  231. SysMessageDefault(DEFMSG_COMBAT_ARCH_NOAMMO);
  232. return WAR_SWING_INVALID;
  233. }
  234. }
  235. }
  236. else
  237. {
  238. int iMinDist = pWeapon ? pWeapon->RangeH() : 0;
  239. int iMaxDist = CalcFightRange(pWeapon);
  240. if ( iDist < iMinDist || iDist > iMaxDist )
  241. return IsSetCombatFlags(COMBAT_STAYINRANGE) ? WAR_SWING_EQUIPPING : WAR_SWING_READY;
  242. }
  243.  
  244. // Start the swing
  245. if ( m_atFight.m_Swing_State == WAR_SWING_READY )
  246. {
  247. if ( !CanSeeLOS(pCharTarg) )
  248. return WAR_SWING_EQUIPPING;
  249.  
  250. ANIM_TYPE anim = GenerateAnimate(ANIM_ATTACK_WEAPON);
  251. int animDelay = 7; // attack speed is always 7ms and then the char keep waiting the remaining time
  252. int iSwingDelay = g_Cfg.Calc_CombatAttackSpeed(this, pWeapon) - 1; // swings are started only on the next tick, so substract -1 to compensate that
  253.  
  254. if ( IsTrigUsed(TRIGGER_HITTRY) )
  255. {
  256. CScriptTriggerArgs Args(iSwingDelay, 0, pWeapon);
  257. Args.m_VarsLocal.SetNum("Anim", static_cast<int>(anim));
  258. Args.m_VarsLocal.SetNum("AnimDelay", animDelay);
  259. if ( OnTrigger(CTRIG_HitTry, pCharTarg, &Args) == TRIGRET_RET_TRUE )
  260. return WAR_SWING_READY;
  261.  
  262. iSwingDelay = static_cast<int>(Args.m_iN1);
  263. anim = static_cast<ANIM_TYPE>(Args.m_VarsLocal.GetKeyNum("Anim"));
  264. animDelay = static_cast<int>(Args.m_VarsLocal.GetKeyNum("AnimDelay"));
  265. if ( iSwingDelay < 0 )
  266. iSwingDelay = 0;
  267. if ( animDelay < 0 )
  268. animDelay = 0;
  269. }
  270.  
  271. m_atFight.m_Swing_State = WAR_SWING_SWINGING;
  272. m_atFight.m_Swing_Delay = maximum(0, iSwingDelay - animDelay);
  273.  
  274. if ( IsSetCombatFlags(COMBAT_PREHIT) )
  275. {
  276. SetKeyNum("LastHit", g_World.GetCurrentTime().GetTimeRaw() + iSwingDelay);
  277. SetTimeout(0);
  278. }
  279. else
  280. SetTimeout(animDelay);
  281.  
  282. Reveal();
  283. if ( !IsSetCombatFlags(COMBAT_NODIRCHANGE) )
  284. UpdateDir(pCharTarg);
  285. UpdateAnimate(anim, false, false, static_cast<BYTE>(animDelay / TICK_PER_SEC));
  286. return WAR_SWING_SWINGING;
  287. }
  288.  
  289. m_atFight.m_Swing_NextAction = CServTime::GetCurrentTime() + m_atFight.m_Swing_Delay;
  290.  
  291. if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
  292. {
  293. // Post-swing behavior
  294. ITEMID_TYPE AmmoAnim;
  295. if ( pAnim )
  296. {
  297. t_Str = pAnim->GetValStr();
  298. rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
  299. AmmoAnim = static_cast<ITEMID_TYPE>(rid.GetResIndex());
  300. }
  301. else
  302. AmmoAnim = static_cast<ITEMID_TYPE>(pWeaponDef->m_ttWeaponBow.m_idAmmoX.GetResIndex());
  303.  
  304. DWORD AmmoHue = 0;
  305. if ( pColor )
  306. AmmoHue = static_cast<DWORD>(pColor->GetValNum());
  307.  
  308. DWORD AmmoRender = 0;
  309. if ( pRender )
  310. AmmoRender = static_cast<DWORD>(pRender->GetValNum());
  311.  
  312. pCharTarg->Effect(EFFECT_BOLT, AmmoAnim, this, 18, 1, false, AmmoHue, AmmoRender);
  313. }
  314.  
  315. // We made our swing. so we must recoil.
  316. m_atFight.m_Swing_State = WAR_SWING_EQUIPPING;
  317.  
  318. // We missed
  319. if ( m_Act_Difficulty < 0 )
  320. {
  321. if ( IsTrigUsed(TRIGGER_HITMISS) )
  322. {
  323. CScriptTriggerArgs Args(0, 0, pWeapon);
  324. if ( pAmmo )
  325. Args.m_VarsLocal.SetNum("Arrow", pAmmo->GetUID());
  326. if ( OnTrigger(CTRIG_HitMiss, pCharTarg, &Args) == TRIGRET_RET_TRUE )
  327. return WAR_SWING_EQUIPPING;
  328.  
  329. if ( Args.m_VarsLocal.GetKeyNum("ArrowHandled") != 0 ) // if arrow is handled by script, do nothing with it further!
  330. pAmmo = NULL;
  331. }
  332.  
  333. if ( pAmmo && m_pPlayer && (40 >= Calc_GetRandVal(100)) )
  334. {
  335. pAmmo->UnStackSplit(1);
  336. pAmmo->MoveToDecay(pCharTarg->GetTopPoint(), g_Cfg.m_iDecay_Item);
  337. }
  338.  
  339. SOUND_TYPE iSound = 0;
  340. if ( pWeapon )
  341. iSound = static_cast<SOUND_TYPE>(pWeapon->GetDefNum("AMMOSOUNDMISS"));
  342. if ( !iSound )
  343. {
  344. if ( g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
  345. {
  346. static const SOUND_TYPE sm_Snd_Miss[] = { 0x233, 0x238 };
  347. iSound = sm_Snd_Miss[Calc_GetRandVal(COUNTOF(sm_Snd_Miss))];
  348. }
  349. else
  350. {
  351. static const SOUND_TYPE sm_Snd_Miss[] = { 0x238, 0x239, 0x23a };
  352. iSound = sm_Snd_Miss[Calc_GetRandVal(COUNTOF(sm_Snd_Miss))];
  353. }
  354. }
  355.  
  356. if ( IsPriv(PRIV_DETAIL) )
  357. SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_COMBAT_MISSS), pCharTarg->GetName());
  358. if ( pCharTarg->IsPriv(PRIV_DETAIL) )
  359. pCharTarg->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_COMBAT_MISSO), GetName());
  360.  
  361. Sound(iSound);
  362. return WAR_SWING_EQUIPPING;
  363. }
  364.  
  365. // We hit
  366. if ( !(iTyp & DAMAGE_GOD) )
  367. {
  368. // Check if target will block the hit
  369. // Legacy pre-SE formula
  370. CItem *pItemHit = NULL;
  371. int ParryChance = 0;
  372. if ( pCharTarg->IsStatFlag(STATF_HasShield) ) // parry using shield
  373. {
  374. pItemHit = pCharTarg->LayerFind(LAYER_HAND2);
  375. ParryChance = pCharTarg->Skill_GetBase(SKILL_PARRYING) / 40;
  376. }
  377. else if ( pCharTarg->m_uidWeapon.IsItem() ) // parry using weapon
  378. {
  379. pItemHit = pCharTarg->m_uidWeapon.ItemFind();
  380. ParryChance = pCharTarg->Skill_GetBase(SKILL_PARRYING) / 80;
  381. }
  382.  
  383. if ( pCharTarg->Skill_GetBase(SKILL_PARRYING) >= 1000 )
  384. ParryChance += 5;
  385.  
  386. int Dex = pCharTarg->Stat_GetAdjusted(STAT_DEX);
  387. if ( Dex < 80 )
  388. ParryChance = ParryChance * (20 + Dex) / 100;
  389.  
  390. if ( pCharTarg->Skill_UseQuick(SKILL_PARRYING, ParryChance, true, false) )
  391. {
  392. if ( IsPriv(PRIV_DETAIL) )
  393. SysMessageDefault(DEFMSG_COMBAT_PARRY);
  394. if ( pItemHit )
  395. pItemHit->OnTakeDamage(1, this, iTyp);
  396.  
  397. //Effect(EFFECT_OBJ, ITEMID_FX_GLOW, this, 10, 16); // moved to scripts (@UseQuick on Parrying skill)
  398. return WAR_SWING_EQUIPPING;
  399. }
  400. }
  401.  
  402. // Calculate base damage
  403. int iDmg = Fight_CalcDamage(pWeapon);
  404.  
  405. CScriptTriggerArgs Args(iDmg, iTyp, pWeapon);
  406. Args.m_VarsLocal.SetNum("ItemDamageChance", 40);
  407. if ( pAmmo )
  408. Args.m_VarsLocal.SetNum("Arrow", pAmmo->GetUID());
  409.  
  410. if ( IsTrigUsed(TRIGGER_SKILLSUCCESS) )
  411. {
  412. if ( Skill_OnCharTrigger(skill, CTRIG_SkillSuccess) == TRIGRET_RET_TRUE )
  413. {
  414. Skill_Cleanup();
  415. return WAR_SWING_EQUIPPING; // ok, so no hit - skill failed. Pah!
  416. }
  417. }
  418. if ( IsTrigUsed(TRIGGER_SUCCESS) )
  419. {
  420. if ( Skill_OnTrigger(skill, SKTRIG_SUCCESS) == TRIGRET_RET_TRUE )
  421. {
  422. Skill_Cleanup();
  423. return WAR_SWING_EQUIPPING; // ok, so no hit - skill failed. Pah!
  424. }
  425. }
  426.  
  427. if ( IsTrigUsed(TRIGGER_HIT) )
  428. {
  429. if ( OnTrigger(CTRIG_Hit, pCharTarg, &Args) == TRIGRET_RET_TRUE )
  430. return WAR_SWING_EQUIPPING;
  431.  
  432. if ( Args.m_VarsLocal.GetKeyNum("ArrowHandled") != 0 ) // if arrow is handled by script, do nothing with it further
  433. pAmmo = NULL;
  434.  
  435. iDmg = static_cast<int>(Args.m_iN1);
  436. iTyp = static_cast<DAMAGE_TYPE>(Args.m_iN2);
  437. }
  438.  
  439. // BAD BAD Healing fix.. Cant think of something else -- Radiant
  440. if ( pCharTarg->m_Act_SkillCurrent == SKILL_HEALING )
  441. {
  442. pCharTarg->SysMessageDefault(DEFMSG_HEALING_INTERRUPT);
  443. pCharTarg->Skill_Cleanup();
  444. }
  445.  
  446. if ( pAmmo )
  447. {
  448. pAmmo->UnStackSplit(1);
  449. if ( pCharTarg->m_pNPC && (40 >= Calc_GetRandVal(100)) )
  450. pCharTarg->ItemBounce(pAmmo, false);
  451. else
  452. pAmmo->Delete();
  453. }
  454.  
  455. // Hit noise (based on weapon type)
  456. SoundChar(CRESND_HIT);
  457.  
  458. if ( pWeapon )
  459. {
  460. // Check if the weapon is poisoned
  461. if ( !IsSetCombatFlags(COMBAT_NOPOISONHIT) && pWeapon->m_itWeapon.m_poison_skill && pWeapon->m_itWeapon.m_poison_skill > Calc_GetRandVal(100) )
  462. {
  463. BYTE iPoisonDeliver = static_cast<BYTE>(Calc_GetRandVal(pWeapon->m_itWeapon.m_poison_skill));
  464. pCharTarg->SetPoison(10 * iPoisonDeliver, iPoisonDeliver / 5, this);
  465.  
  466. pWeapon->m_itWeapon.m_poison_skill -= iPoisonDeliver / 2; // reduce weapon poison charges
  467. pWeapon->UpdatePropertyFlag(AUTOTOOLTIP_FLAG_POISON);
  468. }
  469.  
  470. // Check if the weapon will be damaged
  471. int iDamageChance = static_cast<int>(Args.m_VarsLocal.GetKeyNum("ItemDamageChance"));
  472. if ( iDamageChance > Calc_GetRandVal(100) )
  473. pWeapon->OnTakeDamage(iDmg, pCharTarg);
  474. }
  475. else if ( NPC_IsMonster() )
  476. {
  477. // Base poisoning for NPCs
  478. if ( !IsSetCombatFlags(COMBAT_NOPOISONHIT) && 50 >= Calc_GetRandVal(100) )
  479. {
  480. int iPoisoningSkill = Skill_GetBase(SKILL_POISONING);
  481. if ( iPoisoningSkill )
  482. pCharTarg->SetPoison(Calc_GetRandVal(iPoisoningSkill), Calc_GetRandVal(iPoisoningSkill / 50), this);
  483. }
  484. }
  485.  
  486. // Took my swing. Do Damage !
  487. iDmg = pCharTarg->OnTakeDamage(
  488. iDmg,
  489. this,
  490. iTyp,
  491. static_cast<int>(GetDefNum("DAMPHYSICAL", true)),
  492. static_cast<int>(GetDefNum("DAMFIRE", true)),
  493. static_cast<int>(GetDefNum("DAMCOLD", true)),
  494. static_cast<int>(GetDefNum("DAMPOISON", true)),
  495. static_cast<int>(GetDefNum("DAMENERGY", true))
  496. );
  497.  
  498. if ( iDmg > 0 )
  499. {
  500. CItem *pCurseWeapon = LayerFind(LAYER_SPELL_Curse_Weapon);
  501. short iHitLifeLeech = static_cast<short>(GetDefNum("HitLeechLife"));
  502. if ( pWeapon && pCurseWeapon )
  503. iHitLifeLeech += pCurseWeapon->m_itSpell.m_spelllevel;
  504.  
  505. bool bMakeLeechSound = false;
  506. if ( iHitLifeLeech )
  507. {
  508. iHitLifeLeech = static_cast<short>(Calc_GetRandVal2(0, (iDmg * iHitLifeLeech * 30) / 10000)); // leech 0% ~ 30% of damage value
  509. UpdateStatVal(STAT_STR, iHitLifeLeech, Stat_GetMax(STAT_STR));
  510. bMakeLeechSound = true;
  511. }
  512.  
  513. short iHitManaLeech = static_cast<short>(GetDefNum("HitLeechMana"));
  514. if ( iHitManaLeech )
  515. {
  516. iHitManaLeech = static_cast<short>(Calc_GetRandVal2(0, (iDmg * iHitManaLeech * 40) / 10000)); // leech 0% ~ 40% of damage value
  517. UpdateStatVal(STAT_INT, iHitManaLeech, Stat_GetMax(STAT_INT));
  518. bMakeLeechSound = true;
  519. }
  520.  
  521. if ( GetDefNum("HitLeechStam") > Calc_GetRandLLVal(100) )
  522. {
  523. UpdateStatVal(STAT_DEX, static_cast<short>(iDmg), Stat_GetMax(STAT_DEX)); // leech 100% of damage value
  524. bMakeLeechSound = true;
  525. }
  526.  
  527. short iManaDrain = 0;
  528. if ( g_Cfg.m_iFeatureAOS & FEATURE_AOS_UPDATE_B )
  529. {
  530. CItem *pPoly = LayerFind(LAYER_SPELL_Polymorph);
  531. if ( pPoly && pPoly->m_itSpell.m_spell == SPELL_Wraith_Form )
  532. iManaDrain += 5 + (15 * Skill_GetBase(SKILL_SPIRITSPEAK) / 1000);
  533. }
  534. if ( GetDefNum("HitManaDrain") > Calc_GetRandLLVal(100) )
  535. iManaDrain += IMULDIV(static_cast<short>(iDmg), 20, 100); // leech 20% of damage value
  536.  
  537. short iTargMana = pCharTarg->Stat_GetVal(STAT_INT);
  538. if ( iManaDrain > iTargMana )
  539. iManaDrain = iTargMana;
  540.  
  541. if ( iManaDrain > 0 )
  542. {
  543. pCharTarg->UpdateStatVal(STAT_INT, iTargMana - iManaDrain);
  544. UpdateStatVal(STAT_INT, iManaDrain, Stat_GetMax(STAT_INT));
  545. bMakeLeechSound = true;
  546. }
  547.  
  548. if ( bMakeLeechSound )
  549. Sound(0x44d);
  550.  
  551. // Make blood effects
  552. if ( pCharTarg->m_wBloodHue != static_cast<HUE_TYPE>(-1) )
  553. {
  554. static const ITEMID_TYPE sm_Blood[] = { ITEMID_BLOOD1, ITEMID_BLOOD2, ITEMID_BLOOD3, ITEMID_BLOOD4, ITEMID_BLOOD5, ITEMID_BLOOD6, ITEMID_BLOOD_SPLAT };
  555. int iBloodQty = (g_Cfg.m_iFeatureSE & FEATURE_SE_UPDATE) ? Calc_GetRandVal2(4, 5) : Calc_GetRandVal2(1, 2);
  556.  
  557. for ( int i = 0; i < iBloodQty; i++ )
  558. {
  559. ITEMID_TYPE iBloodID = sm_Blood[Calc_GetRandVal(COUNTOF(sm_Blood))];
  560. CItem *pBlood = CItem::CreateBase(iBloodID);
  561. ASSERT(pBlood);
  562. pBlood->SetHue(pCharTarg->m_wBloodHue);
  563. pBlood->MoveNear(pCharTarg->GetTopPoint(), 1);
  564. pBlood->SetDecayTime(5 * TICK_PER_SEC);
  565. }
  566. }
  567.  
  568. // Check for passive skill gain
  569. if ( m_pPlayer && !pCharTarg->m_pArea->IsFlag(REGION_FLAG_NO_PVP) )
  570. {
  571. Skill_Experience(skill, m_Act_Difficulty);
  572. Skill_Experience(SKILL_TACTICS, m_Act_Difficulty);
  573. }
  574. }
  575.  
  576. return WAR_SWING_EQUIPPING;
  577. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement