m_berserk.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. /*
  4. ==============================================================================
  5. BERSERK
  6. ==============================================================================
  7. */
  8. #include "g_local.h"
  9. #include "m_berserk.h"
  10. static int sound_pain;
  11. static int sound_die;
  12. static int sound_idle;
  13. static int sound_punch;
  14. static int sound_sight;
  15. static int sound_search;
  16. void berserk_sight (edict_t *self, edict_t *other)
  17. {
  18. gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  19. }
  20. void berserk_search (edict_t *self)
  21. {
  22. gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
  23. }
  24. void berserk_fidget (edict_t *self);
  25. mframe_t berserk_frames_stand [] =
  26. {
  27. ai_stand, 0, berserk_fidget,
  28. ai_stand, 0, NULL,
  29. ai_stand, 0, NULL,
  30. ai_stand, 0, NULL,
  31. ai_stand, 0, NULL
  32. };
  33. mmove_t berserk_move_stand = {FRAME_stand1, FRAME_stand5, berserk_frames_stand, NULL};
  34. void berserk_stand (edict_t *self)
  35. {
  36. self->monsterinfo.currentmove = &berserk_move_stand;
  37. }
  38. mframe_t berserk_frames_stand_fidget [] =
  39. {
  40. ai_stand, 0, NULL,
  41. ai_stand, 0, NULL,
  42. ai_stand, 0, NULL,
  43. ai_stand, 0, NULL,
  44. ai_stand, 0, NULL,
  45. ai_stand, 0, NULL,
  46. ai_stand, 0, NULL,
  47. ai_stand, 0, NULL,
  48. ai_stand, 0, NULL,
  49. ai_stand, 0, NULL,
  50. ai_stand, 0, NULL,
  51. ai_stand, 0, NULL,
  52. ai_stand, 0, NULL,
  53. ai_stand, 0, NULL,
  54. ai_stand, 0, NULL,
  55. ai_stand, 0, NULL,
  56. ai_stand, 0, NULL,
  57. ai_stand, 0, NULL,
  58. ai_stand, 0, NULL,
  59. ai_stand, 0, NULL
  60. };
  61. mmove_t berserk_move_stand_fidget = {FRAME_standb1, FRAME_standb20, berserk_frames_stand_fidget, berserk_stand};
  62. void berserk_fidget (edict_t *self)
  63. {
  64. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  65. return;
  66. if (random() > 0.15)
  67. return;
  68. self->monsterinfo.currentmove = &berserk_move_stand_fidget;
  69. gi.sound (self, CHAN_WEAPON, sound_idle, 1, ATTN_IDLE, 0);
  70. }
  71. mframe_t berserk_frames_walk [] =
  72. {
  73. ai_walk, 9.1, NULL,
  74. ai_walk, 6.3, NULL,
  75. ai_walk, 4.9, NULL,
  76. ai_walk, 6.7, NULL,
  77. ai_walk, 6.0, NULL,
  78. ai_walk, 8.2, NULL,
  79. ai_walk, 7.2, NULL,
  80. ai_walk, 6.1, NULL,
  81. ai_walk, 4.9, NULL,
  82. ai_walk, 4.7, NULL,
  83. ai_walk, 4.7, NULL,
  84. ai_walk, 4.8, NULL
  85. };
  86. mmove_t berserk_move_walk = {FRAME_walkc1, FRAME_walkc11, berserk_frames_walk, NULL};
  87. void berserk_walk (edict_t *self)
  88. {
  89. self->monsterinfo.currentmove = &berserk_move_walk;
  90. }
  91. /*
  92. *****************************
  93. SKIPPED THIS FOR NOW!
  94. *****************************
  95. Running -> Arm raised in air
  96. void() berserk_runb1 =[ $r_att1 , berserk_runb2 ] {ai_run(21);};
  97. void() berserk_runb2 =[ $r_att2 , berserk_runb3 ] {ai_run(11);};
  98. void() berserk_runb3 =[ $r_att3 , berserk_runb4 ] {ai_run(21);};
  99. void() berserk_runb4 =[ $r_att4 , berserk_runb5 ] {ai_run(25);};
  100. void() berserk_runb5 =[ $r_att5 , berserk_runb6 ] {ai_run(18);};
  101. void() berserk_runb6 =[ $r_att6 , berserk_runb7 ] {ai_run(19);};
  102. // running with arm in air : start loop
  103. void() berserk_runb7 =[ $r_att7 , berserk_runb8 ] {ai_run(21);};
  104. void() berserk_runb8 =[ $r_att8 , berserk_runb9 ] {ai_run(11);};
  105. void() berserk_runb9 =[ $r_att9 , berserk_runb10 ] {ai_run(21);};
  106. void() berserk_runb10 =[ $r_att10 , berserk_runb11 ] {ai_run(25);};
  107. void() berserk_runb11 =[ $r_att11 , berserk_runb12 ] {ai_run(18);};
  108. void() berserk_runb12 =[ $r_att12 , berserk_runb7 ] {ai_run(19);};
  109. // running with arm in air : end loop
  110. */
  111. mframe_t berserk_frames_run1 [] =
  112. {
  113. ai_run, 21, NULL,
  114. ai_run, 11, NULL,
  115. ai_run, 21, NULL,
  116. // PMM .. from NULL
  117. ai_run, 25, monster_done_dodge,
  118. ai_run, 18, NULL,
  119. ai_run, 19, NULL
  120. };
  121. mmove_t berserk_move_run1 = {FRAME_run1, FRAME_run6, berserk_frames_run1, NULL};
  122. void berserk_run (edict_t *self)
  123. {
  124. monster_done_dodge (self);
  125. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  126. self->monsterinfo.currentmove = &berserk_move_stand;
  127. else
  128. self->monsterinfo.currentmove = &berserk_move_run1;
  129. }
  130. void berserk_attack_spike (edict_t *self)
  131. {
  132. static vec3_t aim = {MELEE_DISTANCE, 0, -24};
  133. fire_hit (self, aim, (15 + (rand() % 6)), 400); // Faster attack -- upwards and backwards
  134. }
  135. void berserk_swing (edict_t *self)
  136. {
  137. gi.sound (self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
  138. }
  139. mframe_t berserk_frames_attack_spike [] =
  140. {
  141. ai_charge, 0, NULL,
  142. ai_charge, 0, NULL,
  143. ai_charge, 0, berserk_swing,
  144. ai_charge, 0, berserk_attack_spike,
  145. ai_charge, 0, NULL,
  146. ai_charge, 0, NULL,
  147. ai_charge, 0, NULL,
  148. ai_charge, 0, NULL
  149. };
  150. mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_frames_attack_spike, berserk_run};
  151. void berserk_attack_club (edict_t *self)
  152. {
  153. vec3_t aim;
  154. VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
  155. fire_hit (self, aim, (5 + (rand() % 6)), 400); // Slower attack
  156. }
  157. mframe_t berserk_frames_attack_club [] =
  158. {
  159. ai_charge, 0, NULL,
  160. ai_charge, 0, NULL,
  161. ai_charge, 0, NULL,
  162. ai_charge, 0, NULL,
  163. ai_charge, 0, berserk_swing,
  164. ai_charge, 0, NULL,
  165. ai_charge, 0, NULL,
  166. ai_charge, 0, NULL,
  167. ai_charge, 0, berserk_attack_club,
  168. ai_charge, 0, NULL,
  169. ai_charge, 0, NULL,
  170. ai_charge, 0, NULL
  171. };
  172. mmove_t berserk_move_attack_club = {FRAME_att_c9, FRAME_att_c20, berserk_frames_attack_club, berserk_run};
  173. void berserk_strike (edict_t *self)
  174. {
  175. //FIXME play impact sound
  176. }
  177. mframe_t berserk_frames_attack_strike [] =
  178. {
  179. ai_move, 0, NULL,
  180. ai_move, 0, NULL,
  181. ai_move, 0, NULL,
  182. ai_move, 0, berserk_swing,
  183. ai_move, 0, NULL,
  184. ai_move, 0, NULL,
  185. ai_move, 0, NULL,
  186. ai_move, 0, berserk_strike,
  187. ai_move, 0, NULL,
  188. ai_move, 0, NULL,
  189. ai_move, 0, NULL,
  190. ai_move, 0, NULL,
  191. ai_move, 9.7, NULL,
  192. ai_move, 13.6, NULL
  193. };
  194. mmove_t berserk_move_attack_strike = {FRAME_att_c21, FRAME_att_c34, berserk_frames_attack_strike, berserk_run};
  195. void berserk_melee (edict_t *self)
  196. {
  197. monster_done_dodge (self);
  198. if ((rand() % 2) == 0)
  199. self->monsterinfo.currentmove = &berserk_move_attack_spike;
  200. else
  201. self->monsterinfo.currentmove = &berserk_move_attack_club;
  202. }
  203. /*
  204. void() berserk_atke1 =[ $r_attb1, berserk_atke2 ] {ai_run(9);};
  205. void() berserk_atke2 =[ $r_attb2, berserk_atke3 ] {ai_run(6);};
  206. void() berserk_atke3 =[ $r_attb3, berserk_atke4 ] {ai_run(18.4);};
  207. void() berserk_atke4 =[ $r_attb4, berserk_atke5 ] {ai_run(25);};
  208. void() berserk_atke5 =[ $r_attb5, berserk_atke6 ] {ai_run(14);};
  209. void() berserk_atke6 =[ $r_attb6, berserk_atke7 ] {ai_run(20);};
  210. void() berserk_atke7 =[ $r_attb7, berserk_atke8 ] {ai_run(8.5);};
  211. void() berserk_atke8 =[ $r_attb8, berserk_atke9 ] {ai_run(3);};
  212. void() berserk_atke9 =[ $r_attb9, berserk_atke10 ] {ai_run(17.5);};
  213. void() berserk_atke10 =[ $r_attb10, berserk_atke11 ] {ai_run(17);};
  214. void() berserk_atke11 =[ $r_attb11, berserk_atke12 ] {ai_run(9);};
  215. void() berserk_atke12 =[ $r_attb12, berserk_atke13 ] {ai_run(25);};
  216. void() berserk_atke13 =[ $r_attb13, berserk_atke14 ] {ai_run(3.7);};
  217. void() berserk_atke14 =[ $r_attb14, berserk_atke15 ] {ai_run(2.6);};
  218. void() berserk_atke15 =[ $r_attb15, berserk_atke16 ] {ai_run(19);};
  219. void() berserk_atke16 =[ $r_attb16, berserk_atke17 ] {ai_run(25);};
  220. void() berserk_atke17 =[ $r_attb17, berserk_atke18 ] {ai_run(19.6);};
  221. void() berserk_atke18 =[ $r_attb18, berserk_run1 ] {ai_run(7.8);};
  222. */
  223. mframe_t berserk_frames_pain1 [] =
  224. {
  225. ai_move, 0, NULL,
  226. ai_move, 0, NULL,
  227. ai_move, 0, NULL,
  228. ai_move, 0, NULL
  229. };
  230. mmove_t berserk_move_pain1 = {FRAME_painc1, FRAME_painc4, berserk_frames_pain1, berserk_run};
  231. mframe_t berserk_frames_pain2 [] =
  232. {
  233. ai_move, 0, NULL,
  234. ai_move, 0, NULL,
  235. ai_move, 0, NULL,
  236. ai_move, 0, NULL,
  237. ai_move, 0, NULL,
  238. ai_move, 0, NULL,
  239. ai_move, 0, NULL,
  240. ai_move, 0, NULL,
  241. ai_move, 0, NULL,
  242. ai_move, 0, NULL,
  243. ai_move, 0, NULL,
  244. ai_move, 0, NULL,
  245. ai_move, 0, NULL,
  246. ai_move, 0, NULL,
  247. ai_move, 0, NULL,
  248. ai_move, 0, NULL,
  249. ai_move, 0, NULL,
  250. ai_move, 0, NULL,
  251. ai_move, 0, NULL,
  252. ai_move, 0, NULL
  253. };
  254. mmove_t berserk_move_pain2 = {FRAME_painb1, FRAME_painb20, berserk_frames_pain2, berserk_run};
  255. void berserk_pain (edict_t *self, edict_t *other, float kick, int damage)
  256. {
  257. if (self->health < (self->max_health / 2))
  258. self->s.skinnum = 1;
  259. if (level.time < self->pain_debounce_time)
  260. return;
  261. self->pain_debounce_time = level.time + 3;
  262. gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
  263. if (skill->value == 3)
  264. return; // no pain anims in nightmare
  265. monster_done_dodge (self);
  266. if ((damage < 20) || (random() < 0.5))
  267. self->monsterinfo.currentmove = &berserk_move_pain1;
  268. else
  269. self->monsterinfo.currentmove = &berserk_move_pain2;
  270. }
  271. void berserk_dead (edict_t *self)
  272. {
  273. VectorSet (self->mins, -16, -16, -24);
  274. VectorSet (self->maxs, 16, 16, -8);
  275. self->movetype = MOVETYPE_TOSS;
  276. self->svflags |= SVF_DEADMONSTER;
  277. self->nextthink = 0;
  278. gi.linkentity (self);
  279. }
  280. mframe_t berserk_frames_death1 [] =
  281. {
  282. ai_move, 0, NULL,
  283. ai_move, 0, NULL,
  284. ai_move, 0, NULL,
  285. ai_move, 0, NULL,
  286. ai_move, 0, NULL,
  287. ai_move, 0, NULL,
  288. ai_move, 0, NULL,
  289. ai_move, 0, NULL,
  290. ai_move, 0, NULL,
  291. ai_move, 0, NULL,
  292. ai_move, 0, NULL,
  293. ai_move, 0, NULL,
  294. ai_move, 0, NULL
  295. };
  296. mmove_t berserk_move_death1 = {FRAME_death1, FRAME_death13, berserk_frames_death1, berserk_dead};
  297. mframe_t berserk_frames_death2 [] =
  298. {
  299. ai_move, 0, NULL,
  300. ai_move, 0, NULL,
  301. ai_move, 0, NULL,
  302. ai_move, 0, NULL,
  303. ai_move, 0, NULL,
  304. ai_move, 0, NULL,
  305. ai_move, 0, NULL,
  306. ai_move, 0, NULL
  307. };
  308. mmove_t berserk_move_death2 = {FRAME_deathc1, FRAME_deathc8, berserk_frames_death2, berserk_dead};
  309. void berserk_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  310. {
  311. int n;
  312. if (self->health <= self->gib_health)
  313. {
  314. gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  315. for (n= 0; n < 2; n++)
  316. ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  317. for (n= 0; n < 4; n++)
  318. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  319. ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  320. self->deadflag = DEAD_DEAD;
  321. return;
  322. }
  323. if (self->deadflag == DEAD_DEAD)
  324. return;
  325. gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
  326. self->deadflag = DEAD_DEAD;
  327. self->takedamage = DAMAGE_YES;
  328. if (damage >= 50)
  329. self->monsterinfo.currentmove = &berserk_move_death1;
  330. else
  331. self->monsterinfo.currentmove = &berserk_move_death2;
  332. }
  333. //===========
  334. //PGM
  335. void berserk_jump_now (edict_t *self)
  336. {
  337. vec3_t forward,up;
  338. monster_jump_start (self);
  339. AngleVectors (self->s.angles, forward, NULL, up);
  340. VectorMA(self->velocity, 100, forward, self->velocity);
  341. VectorMA(self->velocity, 300, up, self->velocity);
  342. }
  343. void berserk_jump2_now (edict_t *self)
  344. {
  345. vec3_t forward,up;
  346. monster_jump_start (self);
  347. AngleVectors (self->s.angles, forward, NULL, up);
  348. VectorMA(self->velocity, 150, forward, self->velocity);
  349. VectorMA(self->velocity, 400, up, self->velocity);
  350. }
  351. void berserk_jump_wait_land (edict_t *self)
  352. {
  353. if(self->groundentity == NULL)
  354. {
  355. self->monsterinfo.nextframe = self->s.frame;
  356. if(monster_jump_finished (self))
  357. self->monsterinfo.nextframe = self->s.frame + 1;
  358. }
  359. else
  360. self->monsterinfo.nextframe = self->s.frame + 1;
  361. }
  362. mframe_t berserk_frames_jump [] =
  363. {
  364. ai_move, 0, NULL,
  365. ai_move, 0, NULL,
  366. ai_move, 0, NULL,
  367. ai_move, 0, berserk_jump_now,
  368. ai_move, 0, NULL,
  369. ai_move, 0, NULL,
  370. ai_move, 0, berserk_jump_wait_land,
  371. ai_move, 0, NULL,
  372. ai_move, 0, NULL
  373. };
  374. mmove_t berserk_move_jump = { FRAME_jump1, FRAME_jump9, berserk_frames_jump, berserk_run };
  375. mframe_t berserk_frames_jump2 [] =
  376. {
  377. ai_move, -8, NULL,
  378. ai_move, -4, NULL,
  379. ai_move, -4, NULL,
  380. ai_move, 0, berserk_jump_now,
  381. ai_move, 0, NULL,
  382. ai_move, 0, NULL,
  383. ai_move, 0, berserk_jump_wait_land,
  384. ai_move, 0, NULL,
  385. ai_move, 0, NULL
  386. };
  387. mmove_t berserk_move_jump2 = { FRAME_jump1, FRAME_jump9, berserk_frames_jump2, berserk_run };
  388. void berserk_jump (edict_t *self)
  389. {
  390. if(!self->enemy)
  391. return;
  392. monster_done_dodge (self);
  393. if(self->enemy->s.origin[2] > self->s.origin[2])
  394. self->monsterinfo.currentmove = &berserk_move_jump2;
  395. else
  396. self->monsterinfo.currentmove = &berserk_move_jump;
  397. }
  398. qboolean berserk_blocked (edict_t *self, float dist)
  399. {
  400. if(blocked_checkjump (self, dist, 256, 40))
  401. {
  402. berserk_jump(self);
  403. return true;
  404. }
  405. if(blocked_checkplat (self, dist))
  406. return true;
  407. return false;
  408. }
  409. //PGM
  410. //===========
  411. void berserk_sidestep (edict_t *self)
  412. {
  413. // if we're jumping, don't dodge
  414. if ((self->monsterinfo.currentmove == &berserk_move_jump) ||
  415. (self->monsterinfo.currentmove == &berserk_move_jump2))
  416. {
  417. return;
  418. }
  419. // don't check for attack; the eta should suffice for melee monsters
  420. if (self->monsterinfo.currentmove != &berserk_move_run1)
  421. self->monsterinfo.currentmove = &berserk_move_run1;
  422. }
  423. /*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  424. */
  425. void SP_monster_berserk (edict_t *self)
  426. {
  427. if (deathmatch->value)
  428. {
  429. G_FreeEdict (self);
  430. return;
  431. }
  432. // pre-caches
  433. sound_pain = gi.soundindex ("berserk/berpain2.wav");
  434. sound_die = gi.soundindex ("berserk/berdeth2.wav");
  435. sound_idle = gi.soundindex ("berserk/beridle1.wav");
  436. sound_punch = gi.soundindex ("berserk/attack.wav");
  437. sound_search = gi.soundindex ("berserk/bersrch1.wav");
  438. sound_sight = gi.soundindex ("berserk/sight.wav");
  439. self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2");
  440. VectorSet (self->mins, -16, -16, -24);
  441. VectorSet (self->maxs, 16, 16, 32);
  442. self->movetype = MOVETYPE_STEP;
  443. self->solid = SOLID_BBOX;
  444. self->health = 240;
  445. self->gib_health = -60;
  446. self->mass = 250;
  447. self->pain = berserk_pain;
  448. self->die = berserk_die;
  449. self->monsterinfo.stand = berserk_stand;
  450. self->monsterinfo.walk = berserk_walk;
  451. self->monsterinfo.run = berserk_run;
  452. // pmm
  453. // self->monsterinfo.dodge = NULL;
  454. self->monsterinfo.dodge = M_MonsterDodge;
  455. self->monsterinfo.sidestep = berserk_sidestep;
  456. // pmm
  457. self->monsterinfo.attack = NULL;
  458. self->monsterinfo.melee = berserk_melee;
  459. self->monsterinfo.sight = berserk_sight;
  460. self->monsterinfo.search = berserk_search;
  461. self->monsterinfo.blocked = berserk_blocked; //PGM
  462. self->monsterinfo.currentmove = &berserk_move_stand;
  463. self->monsterinfo.scale = MODEL_SCALE;
  464. gi.linkentity (self);
  465. walkmonster_start (self);
  466. }