m_berserk.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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. ai_run, 25, NULL,
  117. ai_run, 18, NULL,
  118. ai_run, 19, NULL
  119. };
  120. mmove_t berserk_move_run1 = {FRAME_run1, FRAME_run6, berserk_frames_run1, NULL};
  121. void berserk_run (edict_t *self)
  122. {
  123. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  124. self->monsterinfo.currentmove = &berserk_move_stand;
  125. else
  126. self->monsterinfo.currentmove = &berserk_move_run1;
  127. }
  128. void berserk_attack_spike (edict_t *self)
  129. {
  130. static vec3_t aim = {MELEE_DISTANCE, 0, -24};
  131. fire_hit (self, aim, (15 + (rand() % 6)), 400); // Faster attack -- upwards and backwards
  132. }
  133. void berserk_swing (edict_t *self)
  134. {
  135. gi.sound (self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
  136. }
  137. mframe_t berserk_frames_attack_spike [] =
  138. {
  139. ai_charge, 0, NULL,
  140. ai_charge, 0, NULL,
  141. ai_charge, 0, berserk_swing,
  142. ai_charge, 0, berserk_attack_spike,
  143. ai_charge, 0, NULL,
  144. ai_charge, 0, NULL,
  145. ai_charge, 0, NULL,
  146. ai_charge, 0, NULL
  147. };
  148. mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_frames_attack_spike, berserk_run};
  149. void berserk_attack_club (edict_t *self)
  150. {
  151. vec3_t aim;
  152. VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
  153. fire_hit (self, aim, (5 + (rand() % 6)), 400); // Slower attack
  154. }
  155. mframe_t berserk_frames_attack_club [] =
  156. {
  157. ai_charge, 0, NULL,
  158. ai_charge, 0, NULL,
  159. ai_charge, 0, NULL,
  160. ai_charge, 0, NULL,
  161. ai_charge, 0, berserk_swing,
  162. ai_charge, 0, NULL,
  163. ai_charge, 0, NULL,
  164. ai_charge, 0, NULL,
  165. ai_charge, 0, berserk_attack_club,
  166. ai_charge, 0, NULL,
  167. ai_charge, 0, NULL,
  168. ai_charge, 0, NULL
  169. };
  170. mmove_t berserk_move_attack_club = {FRAME_att_c9, FRAME_att_c20, berserk_frames_attack_club, berserk_run};
  171. void berserk_strike (edict_t *self)
  172. {
  173. //FIXME play impact sound
  174. }
  175. mframe_t berserk_frames_attack_strike [] =
  176. {
  177. ai_move, 0, NULL,
  178. ai_move, 0, NULL,
  179. ai_move, 0, NULL,
  180. ai_move, 0, berserk_swing,
  181. ai_move, 0, NULL,
  182. ai_move, 0, NULL,
  183. ai_move, 0, NULL,
  184. ai_move, 0, berserk_strike,
  185. ai_move, 0, NULL,
  186. ai_move, 0, NULL,
  187. ai_move, 0, NULL,
  188. ai_move, 0, NULL,
  189. ai_move, 9.7, NULL,
  190. ai_move, 13.6, NULL
  191. };
  192. mmove_t berserk_move_attack_strike = {FRAME_att_c21, FRAME_att_c34, berserk_frames_attack_strike, berserk_run};
  193. void berserk_melee (edict_t *self)
  194. {
  195. if ((rand() % 2) == 0)
  196. self->monsterinfo.currentmove = &berserk_move_attack_spike;
  197. else
  198. self->monsterinfo.currentmove = &berserk_move_attack_club;
  199. }
  200. /*
  201. void() berserk_atke1 =[ $r_attb1, berserk_atke2 ] {ai_run(9);};
  202. void() berserk_atke2 =[ $r_attb2, berserk_atke3 ] {ai_run(6);};
  203. void() berserk_atke3 =[ $r_attb3, berserk_atke4 ] {ai_run(18.4);};
  204. void() berserk_atke4 =[ $r_attb4, berserk_atke5 ] {ai_run(25);};
  205. void() berserk_atke5 =[ $r_attb5, berserk_atke6 ] {ai_run(14);};
  206. void() berserk_atke6 =[ $r_attb6, berserk_atke7 ] {ai_run(20);};
  207. void() berserk_atke7 =[ $r_attb7, berserk_atke8 ] {ai_run(8.5);};
  208. void() berserk_atke8 =[ $r_attb8, berserk_atke9 ] {ai_run(3);};
  209. void() berserk_atke9 =[ $r_attb9, berserk_atke10 ] {ai_run(17.5);};
  210. void() berserk_atke10 =[ $r_attb10, berserk_atke11 ] {ai_run(17);};
  211. void() berserk_atke11 =[ $r_attb11, berserk_atke12 ] {ai_run(9);};
  212. void() berserk_atke12 =[ $r_attb12, berserk_atke13 ] {ai_run(25);};
  213. void() berserk_atke13 =[ $r_attb13, berserk_atke14 ] {ai_run(3.7);};
  214. void() berserk_atke14 =[ $r_attb14, berserk_atke15 ] {ai_run(2.6);};
  215. void() berserk_atke15 =[ $r_attb15, berserk_atke16 ] {ai_run(19);};
  216. void() berserk_atke16 =[ $r_attb16, berserk_atke17 ] {ai_run(25);};
  217. void() berserk_atke17 =[ $r_attb17, berserk_atke18 ] {ai_run(19.6);};
  218. void() berserk_atke18 =[ $r_attb18, berserk_run1 ] {ai_run(7.8);};
  219. */
  220. mframe_t berserk_frames_pain1 [] =
  221. {
  222. ai_move, 0, NULL,
  223. ai_move, 0, NULL,
  224. ai_move, 0, NULL,
  225. ai_move, 0, NULL
  226. };
  227. mmove_t berserk_move_pain1 = {FRAME_painc1, FRAME_painc4, berserk_frames_pain1, berserk_run};
  228. mframe_t berserk_frames_pain2 [] =
  229. {
  230. ai_move, 0, NULL,
  231. ai_move, 0, NULL,
  232. ai_move, 0, NULL,
  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. };
  251. mmove_t berserk_move_pain2 = {FRAME_painb1, FRAME_painb20, berserk_frames_pain2, berserk_run};
  252. void berserk_pain (edict_t *self, edict_t *other, float kick, int damage)
  253. {
  254. if (self->health < (self->max_health / 2))
  255. self->s.skinnum = 1;
  256. if (level.time < self->pain_debounce_time)
  257. return;
  258. self->pain_debounce_time = level.time + 3;
  259. gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
  260. if (skill->value == 3)
  261. return; // no pain anims in nightmare
  262. if ((damage < 20) || (random() < 0.5))
  263. self->monsterinfo.currentmove = &berserk_move_pain1;
  264. else
  265. self->monsterinfo.currentmove = &berserk_move_pain2;
  266. }
  267. void berserk_dead (edict_t *self)
  268. {
  269. VectorSet (self->mins, -16, -16, -24);
  270. VectorSet (self->maxs, 16, 16, -8);
  271. self->movetype = MOVETYPE_TOSS;
  272. self->svflags |= SVF_DEADMONSTER;
  273. self->nextthink = 0;
  274. gi.linkentity (self);
  275. }
  276. mframe_t berserk_frames_death1 [] =
  277. {
  278. ai_move, 0, NULL,
  279. ai_move, 0, NULL,
  280. ai_move, 0, NULL,
  281. ai_move, 0, NULL,
  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. };
  292. mmove_t berserk_move_death1 = {FRAME_death1, FRAME_death13, berserk_frames_death1, berserk_dead};
  293. mframe_t berserk_frames_death2 [] =
  294. {
  295. ai_move, 0, NULL,
  296. ai_move, 0, NULL,
  297. ai_move, 0, NULL,
  298. ai_move, 0, NULL,
  299. ai_move, 0, NULL,
  300. ai_move, 0, NULL,
  301. ai_move, 0, NULL,
  302. ai_move, 0, NULL
  303. };
  304. mmove_t berserk_move_death2 = {FRAME_deathc1, FRAME_deathc8, berserk_frames_death2, berserk_dead};
  305. void berserk_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  306. {
  307. int n;
  308. if (self->health <= self->gib_health)
  309. {
  310. gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  311. for (n= 0; n < 2; n++)
  312. ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  313. for (n= 0; n < 4; n++)
  314. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  315. ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  316. self->deadflag = DEAD_DEAD;
  317. return;
  318. }
  319. if (self->deadflag == DEAD_DEAD)
  320. return;
  321. gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
  322. self->deadflag = DEAD_DEAD;
  323. self->takedamage = DAMAGE_YES;
  324. if (damage >= 50)
  325. self->monsterinfo.currentmove = &berserk_move_death1;
  326. else
  327. self->monsterinfo.currentmove = &berserk_move_death2;
  328. }
  329. /*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  330. */
  331. void SP_monster_berserk (edict_t *self)
  332. {
  333. if (deathmatch->value)
  334. {
  335. G_FreeEdict (self);
  336. return;
  337. }
  338. // pre-caches
  339. sound_pain = gi.soundindex ("berserk/berpain2.wav");
  340. sound_die = gi.soundindex ("berserk/berdeth2.wav");
  341. sound_idle = gi.soundindex ("berserk/beridle1.wav");
  342. sound_punch = gi.soundindex ("berserk/attack.wav");
  343. sound_search = gi.soundindex ("berserk/bersrch1.wav");
  344. sound_sight = gi.soundindex ("berserk/sight.wav");
  345. self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2");
  346. VectorSet (self->mins, -16, -16, -24);
  347. VectorSet (self->maxs, 16, 16, 32);
  348. self->movetype = MOVETYPE_STEP;
  349. self->solid = SOLID_BBOX;
  350. self->health = 240;
  351. self->gib_health = -60;
  352. self->mass = 250;
  353. self->pain = berserk_pain;
  354. self->die = berserk_die;
  355. self->monsterinfo.stand = berserk_stand;
  356. self->monsterinfo.walk = berserk_walk;
  357. self->monsterinfo.run = berserk_run;
  358. self->monsterinfo.dodge = NULL;
  359. self->monsterinfo.attack = NULL;
  360. self->monsterinfo.melee = berserk_melee;
  361. self->monsterinfo.sight = berserk_sight;
  362. self->monsterinfo.search = berserk_search;
  363. self->monsterinfo.currentmove = &berserk_move_stand;
  364. self->monsterinfo.scale = MODEL_SCALE;
  365. gi.linkentity (self);
  366. walkmonster_start (self);
  367. }