Clone of PhatAC @ https://github.com/floaterxk/PhatAC

Monster.cpp 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. #include "StdAfx.h"
  2. #include "PhysicsObj.h"
  3. #include "Monster.h"
  4. #include "World.h"
  5. #include "Item.h"
  6. #include "GameMode.h"
  7. #include "Lifestone.h"
  8. #include "ChatMsgs.h"
  9. CBaseMonster::CBaseMonster()
  10. {
  11. m_ItemType = TYPE_CREATURE;
  12. }
  13. CBaseMonster::~CBaseMonster()
  14. {
  15. }
  16. void CBaseMonster::Precache(void)
  17. {
  18. CalculateSpeed();
  19. }
  20. void CBaseMonster::PostSpawn()
  21. {
  22. if (!IsPlayer())
  23. {
  24. EmitEffect(88, 1.0f);
  25. }
  26. }
  27. void CBaseMonster::CalculateSpeed(void)
  28. {
  29. DWORD dwRunSkill;
  30. ATTRIBUTE *quick = GetAttributeData(eQuickness);
  31. SKILL *run = GetSkillData(eRun);
  32. dwRunSkill = quick->data.base + quick->data.raises;
  33. dwRunSkill += run->data.bonus + run->data.raises;
  34. m_fSpeedMod = Calc_AnimSpeed(dwRunSkill, GetBurdenPercent()) * m_fScale;
  35. }
  36. void CBaseMonster::MonsterThink(void)
  37. {
  38. Animation_Think();
  39. Movement_Think();
  40. }
  41. float CBaseMonster::GetBurdenPercent(void)
  42. {
  43. //should base this off our total burden and strength
  44. return 0.0f;
  45. }
  46. // returns the new number of raises, or zero if unchanged.
  47. DWORD CBaseMonster::GiveAttributeXP(eAttribute index, DWORD dwXP)
  48. {
  49. ATTRIBUTE* pAttrib = GetAttributeData(index);
  50. if (!pAttrib)
  51. return 0;
  52. //if ( WillOF( pAttrib->data.exp, dwXP ) )
  53. // return 0;
  54. DWORD dwMaxXP = GetAttributeMaxXP();
  55. DWORD dwOldAttribXP = pAttrib->data.exp;
  56. DWORD dwNewAttribXP = dwOldAttribXP + dwXP;
  57. if (dwNewAttribXP > dwMaxXP)
  58. dwNewAttribXP = dwMaxXP;
  59. DWORD dwOldRaises = pAttrib->data.raises;
  60. DWORD dwNewRaises = GetAttributeLevel(dwNewAttribXP);
  61. pAttrib->data.exp = dwNewAttribXP;
  62. pAttrib->data.raises = dwNewRaises;
  63. if (index == eEndurance)
  64. {
  65. DWORD dwTotalValue = GetAttributeMax(pAttrib, 0.0f);
  66. DWORD dwMaxHealth = dwTotalValue / 2;
  67. if (dwTotalValue % 2) dwMaxHealth++;
  68. DWORD dwMaxStamina = dwTotalValue;
  69. //GetVitalData( eHealth )->data.base = dwMaxHealth;
  70. //GetVitalData( eStamina )->data.base = dwMaxStamina;
  71. }
  72. else if (index == eQuickness)
  73. CalculateSpeed();
  74. else if (index == eSelf)
  75. {
  76. DWORD dwTotalValue = GetAttributeMax(pAttrib, 0.0f);
  77. DWORD dwMaxMana = dwTotalValue;
  78. //GetVitalData( eMana )->data.base = dwMaxMana;
  79. }
  80. return (dwOldRaises != dwNewRaises) ? dwNewRaises : 0;
  81. }
  82. DWORD CBaseMonster::GiveVitalXP(eVital index, DWORD dwXP)
  83. {
  84. VITAL* pVital = GetVitalData(index);
  85. if (!pVital)
  86. return 0;
  87. //if ( WillOF( pVital->data.exp, dwXP ) )
  88. // return 0;
  89. DWORD dwMaxXP = GetVitalMaxXP();
  90. DWORD dwOldVitalXP = pVital->data.exp;
  91. DWORD dwNewVitalXP = dwOldVitalXP + dwXP;
  92. if (dwNewVitalXP > dwMaxXP)
  93. dwNewVitalXP = dwMaxXP;
  94. DWORD dwOldRaises = pVital->data.raises;
  95. DWORD dwNewRaises = GetVitalLevel(dwNewVitalXP);
  96. pVital->data.exp = dwNewVitalXP;
  97. pVital->data.raises = dwNewRaises;
  98. return (dwOldRaises != dwNewRaises) ? dwNewRaises : 0;
  99. }
  100. DWORD CBaseMonster::GiveSkillXP(eSkill index, DWORD dwXP)
  101. {
  102. SKILL* pSkill = GetSkillData(index);
  103. if (!pSkill)
  104. return 0;
  105. //if ( WillOF( pSkill->data.exp, dwXP ) )
  106. // return 0;
  107. DWORD dwMaxXP;
  108. switch (pSkill->data.training)
  109. {
  110. default:
  111. case eUnusable:
  112. case eUntrained:
  113. return 0;
  114. case eTrained:
  115. dwMaxXP = GetTrainedMaxXP();
  116. break;
  117. case eSpecialized:
  118. dwMaxXP = GetSpecializedMaxXP();
  119. break;
  120. }
  121. DWORD dwOldSkillXP = pSkill->data.exp;
  122. DWORD dwNewSkillXP = dwOldSkillXP + dwXP;
  123. if (dwNewSkillXP > dwMaxXP)
  124. dwNewSkillXP = dwMaxXP;
  125. DWORD dwOldRaises = pSkill->data.raises;
  126. DWORD dwNewRaises;
  127. switch (pSkill->data.training)
  128. {
  129. case eTrained:
  130. dwNewRaises = GetTrainedLevel(dwNewSkillXP);
  131. break;
  132. case eSpecialized:
  133. dwNewRaises = GetSpecializedLevel(dwNewSkillXP);
  134. break;
  135. }
  136. pSkill->data.exp = dwNewSkillXP;
  137. pSkill->data.raises = (WORD) dwNewRaises;
  138. if (index == eRun)
  139. CalculateSpeed();
  140. return (dwOldRaises != dwNewRaises) ? dwNewRaises : 0;
  141. }
  142. SKILL* CBaseMonster::GetSkillData(eSkill index)
  143. {
  144. if (index < 0x1 || index > 0x27)
  145. return NULL;
  146. return &m_skills[index - 1];
  147. }
  148. ATTRIBUTE* CBaseMonster::GetAttributeData(eAttribute index)
  149. {
  150. if (index < 1 || index > 6)
  151. return NULL;
  152. return &m_attributes[index - 1];
  153. }
  154. VITAL* CBaseMonster::GetVitalData(eVital index)
  155. {
  156. if (index < 1 || index > 6)
  157. return NULL;
  158. return &m_vitals[index - 1];
  159. }
  160. void CBaseMonster::Animation_Complete(animation_t *data)
  161. {
  162. switch (data->dwAction)
  163. {
  164. case ANIM_SPELLCAST:
  165. {
  166. DWORD dwSpellID = data->dwActionData[0];
  167. DWORD dwTarget = data->dwTarget;
  168. LaunchSpell(dwSpellID, dwTarget);
  169. break;
  170. }
  171. case ANIM_LSRECALL:
  172. {
  173. if (m_bLifestoneBound)
  174. {
  175. Movement_Teleport(m_LifestonePlacement.origin, m_LifestonePlacement.angles);
  176. }
  177. break;
  178. }
  179. case ANIM_MPRECALL:
  180. {
  181. Movement_Teleport(loc_t(0x016C01BC, 49.11f, -31.22f, 0.005f), heading_t(0.7009f, 0, 0, -0.7132f));
  182. break;
  183. }
  184. case ANIM_BINDLIFESTONE:
  185. {
  186. if (IsPlayer())
  187. {
  188. CBasePlayer *pPlayer = (CBasePlayer *)this;
  189. DWORD dwLifestone = data->dwActionData[0];
  190. CPhysicsObj *pLifestone = g_pWorld->FindWithinPVS(this, dwLifestone);
  191. if (pLifestone)
  192. {
  193. if (pLifestone->DistanceTo(this) <= LIFESTONE_MAX_BIND_DISTANCE)
  194. {
  195. pPlayer->SendNetMessage(ServerText("You have attuned your spirit to this Lifestone. You will resurrect here after you die.", 7), PRIVATE_MSG, FALSE, TRUE);
  196. m_LifestonePlacement.origin = m_Origin;
  197. m_LifestonePlacement.angles = m_Angles;
  198. m_bLifestoneBound = true;
  199. }
  200. else
  201. {
  202. pPlayer->SendNetMessage(ServerText("You are too far away for that!", 7), PRIVATE_MSG, FALSE, TRUE);
  203. }
  204. }
  205. }
  206. break;
  207. }
  208. default:
  209. break;
  210. }
  211. CPhysicsObj::Animation_Complete(data);
  212. }
  213. void CBaseMonster::LaunchSpell(DWORD dwSpellID, DWORD dwTarget)
  214. {
  215. switch (dwSpellID)
  216. {
  217. case 2366: //Bovine Intervention
  218. {
  219. if ((GetLandcell() & 0xFFFF) < 0x100)
  220. {
  221. for (int i = 0; i < 30; i++)
  222. {
  223. CBaseMonster *pCow = new CBaseMonster();
  224. pCow->m_dwGUID = g_pWorld->GenerateGUID(eDynamicGUID);
  225. pCow->m_dwModel = 0x02000006;
  226. pCow->m_fScale = 1.0f;
  227. pCow->m_strName = "Cow";
  228. pCow->m_Origin.landcell = m_Origin.landcell;
  229. pCow->m_Origin.x = m_Origin.x + RandomFloat(-20.0f, 20.0f);
  230. pCow->m_Origin.y = m_Origin.y + RandomFloat(-20.0f, 20.0f);
  231. pCow->m_Origin.z = m_Origin.z + RandomFloat(40.0f, 80.0f);
  232. pCow->m_Angles.w = RandomFloat(-1.0f, 1.0f);
  233. pCow->m_Angles.z = RandomFloat(-1.0f, 1.0f);
  234. g_pWorld->CreateEntity(pCow);
  235. pCow->SetDescription("Mooooo!");
  236. }
  237. }
  238. else {
  239. if (IsPlayer())
  240. ((CBasePlayer *)this)->SendText("Cows don't live indoors, silly!", 1);
  241. }
  242. break;
  243. }
  244. }
  245. }
  246. void CBaseMonster::Attack(DWORD dwTarget, DWORD dwHeight, float flPower)
  247. {
  248. CPhysicsObj *pTarget = g_pWorld->FindWithinPVS(this, dwTarget);
  249. if (!pTarget || !pTarget->IsAttackable())
  250. {
  251. return;
  252. }
  253. float dist = DistanceTo(pTarget);
  254. if (dist >= 5)
  255. {
  256. return;
  257. }
  258. if (g_pWorld->GetGameMode())
  259. {
  260. g_pWorld->GetGameMode()->OnTargetAttacked(pTarget, this);
  261. }
  262. WORD wAttackAnim;
  263. switch (dwHeight)
  264. {
  265. case 0x01: wAttackAnim = 0x62; break;
  266. case 0x02: wAttackAnim = 0x63; break;
  267. case 0x03: wAttackAnim = 0x64; break;
  268. default: return;
  269. }
  270. if (flPower >= 0.25f)
  271. wAttackAnim += 3;
  272. if (flPower >= 0.75f)
  273. wAttackAnim += 3;
  274. if (flPower < 0 || flPower > 1)
  275. return;
  276. float flTime = 0.5f + (flPower * 0.5f);
  277. float fSpeed = 1.5f;
  278. Animation_Attack(dwTarget, wAttackAnim, fSpeed, Container_GetWeaponID());
  279. }
  280. CBaelZharon::CBaelZharon()
  281. {
  282. m_dwModel = 0x0200099E;
  283. m_fScale = 1.8f;
  284. m_strName = "Bael'Zharon";
  285. m_miBaseModel.dwBasePalette = 0x1071;
  286. m_miBaseModel.lPalettes.push_back(PaletteRpl(0x1072, 0x00, 0x00));
  287. // SetThink(&CBaelZharon::CrazyThink);
  288. }
  289. BOOL CBaelZharon::CrazyThink()
  290. {
  291. // SpeakLocal(csprintf("Today's lucky numbers are %u %u %u", RandomLong(0, 9), RandomLong(0, 9), RandomLong(0, 9)));
  292. m_fNextThink = g_pGlobals->Time() + 20.0f + RandomFloat(0, 40);
  293. return TRUE;
  294. }
  295. CTargetDrudge::CTargetDrudge()
  296. {
  297. m_dwModel = 0x02000034;
  298. m_fScale = 0.95f;
  299. m_strName = "Oak Target Drudge";
  300. m_dwAnimationSet = 0x0900008A;
  301. m_dwEffectSet = 0x3400006B;
  302. m_dwSoundSet = 0x20000051;
  303. m_miBaseModel.SetBasePalette(0x01B9);
  304. m_miBaseModel.ReplacePalette(0x08B4, 0x00, 0x00);
  305. m_miBaseModel.ReplaceTexture(0x00, 0x0036, 0x0D33);
  306. m_miBaseModel.ReplaceTexture(0x01, 0x0031, 0x0D33);
  307. m_miBaseModel.ReplaceTexture(0x02, 0x0030, 0x0D33);
  308. m_miBaseModel.ReplaceTexture(0x03, 0x0030, 0x0D33);
  309. m_miBaseModel.ReplaceTexture(0x04, 0x0D33, 0x0D33);
  310. m_miBaseModel.ReplaceTexture(0x05, 0x0030, 0x0D33);
  311. m_miBaseModel.ReplaceTexture(0x06, 0x0030, 0x0D33);
  312. m_miBaseModel.ReplaceTexture(0x07, 0x0D33, 0x0D33);
  313. m_miBaseModel.ReplaceTexture(0x08, 0x0030, 0x0D33);
  314. m_miBaseModel.ReplaceTexture(0x09, 0x0030, 0x0D33);
  315. m_miBaseModel.ReplaceTexture(0x0A, 0x0035, 0x0D33);
  316. m_miBaseModel.ReplaceTexture(0x0B, 0x0030, 0x0D33);
  317. m_miBaseModel.ReplaceTexture(0x0C, 0x0030, 0x0D33);
  318. m_miBaseModel.ReplaceTexture(0x0D, 0x0035, 0x0D33);
  319. m_miBaseModel.ReplaceTexture(0x0E, 0x0D33, 0x0D33);
  320. m_miBaseModel.ReplaceTexture(0x0E, 0x0EE8, 0x0EE8);
  321. m_miBaseModel.ReplaceTexture(0x0F, 0x0035, 0x0D33);
  322. m_miBaseModel.ReplaceTexture(0x10, 0x0035, 0x0D33);
  323. m_miBaseModel.ReplaceModel(0x00, 0x005D);
  324. m_miBaseModel.ReplaceModel(0x01, 0x005E);
  325. m_miBaseModel.ReplaceModel(0x02, 0x006E);
  326. m_miBaseModel.ReplaceModel(0x03, 0x0064);
  327. m_miBaseModel.ReplaceModel(0x04, 0x18D9);
  328. m_miBaseModel.ReplaceModel(0x05, 0x006F);
  329. m_miBaseModel.ReplaceModel(0x06, 0x0316);
  330. m_miBaseModel.ReplaceModel(0x07, 0x18D9);
  331. m_miBaseModel.ReplaceModel(0x08, 0x006D);
  332. m_miBaseModel.ReplaceModel(0x09, 0x006B);
  333. m_miBaseModel.ReplaceModel(0x0A, 0x005F);
  334. m_miBaseModel.ReplaceModel(0x0B, 0x006C);
  335. m_miBaseModel.ReplaceModel(0x0C, 0x0068);
  336. m_miBaseModel.ReplaceModel(0x0D, 0x0060);
  337. m_miBaseModel.ReplaceModel(0x0E, 0x18D7);
  338. m_miBaseModel.ReplaceModel(0x0F, 0x0067);
  339. m_miBaseModel.ReplaceModel(0x10, 0x0060);
  340. }