m_berserk.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. /*
  16. ==============================================================================
  17. BERSERK
  18. ==============================================================================
  19. */
  20. #include "g_local.h"
  21. #include "m_berserk.h"
  22. static int sound_pain;
  23. static int sound_die;
  24. static int sound_idle;
  25. static int sound_punch;
  26. static int sound_sight;
  27. static int sound_search;
  28. void berserk_sight (edict_t *self, edict_t *other)
  29. {
  30. gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  31. }
  32. void berserk_search (edict_t *self)
  33. {
  34. gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
  35. }
  36. void berserk_fidget (edict_t *self);
  37. mframe_t berserk_frames_stand [] =
  38. {
  39. ai_stand, 0, berserk_fidget,
  40. ai_stand, 0, NULL,
  41. ai_stand, 0, NULL,
  42. ai_stand, 0, NULL,
  43. ai_stand, 0, NULL
  44. };
  45. mmove_t berserk_move_stand = {FRAME_stand1, FRAME_stand5, berserk_frames_stand, NULL};
  46. void berserk_stand (edict_t *self)
  47. {
  48. self->monsterinfo.currentmove = &berserk_move_stand;
  49. }
  50. mframe_t berserk_frames_stand_fidget [] =
  51. {
  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. ai_stand, 0, NULL,
  61. ai_stand, 0, NULL,
  62. ai_stand, 0, NULL,
  63. ai_stand, 0, NULL,
  64. ai_stand, 0, NULL,
  65. ai_stand, 0, NULL,
  66. ai_stand, 0, NULL,
  67. ai_stand, 0, NULL,
  68. ai_stand, 0, NULL,
  69. ai_stand, 0, NULL,
  70. ai_stand, 0, NULL,
  71. ai_stand, 0, NULL
  72. };
  73. mmove_t berserk_move_stand_fidget = {FRAME_standb1, FRAME_standb20, berserk_frames_stand_fidget, berserk_stand};
  74. void berserk_fidget (edict_t *self)
  75. {
  76. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  77. return;
  78. if (random() > 0.15)
  79. return;
  80. self->monsterinfo.currentmove = &berserk_move_stand_fidget;
  81. gi.sound (self, CHAN_WEAPON, sound_idle, 1, ATTN_IDLE, 0);
  82. }
  83. mframe_t berserk_frames_walk [] =
  84. {
  85. ai_walk, 9.1, NULL,
  86. ai_walk, 6.3, NULL,
  87. ai_walk, 4.9, NULL,
  88. ai_walk, 6.7, NULL,
  89. ai_walk, 6.0, NULL,
  90. ai_walk, 8.2, NULL,
  91. ai_walk, 7.2, NULL,
  92. ai_walk, 6.1, NULL,
  93. ai_walk, 4.9, NULL,
  94. ai_walk, 4.7, NULL,
  95. ai_walk, 4.7, NULL,
  96. ai_walk, 4.8, NULL
  97. };
  98. mmove_t berserk_move_walk = {FRAME_walkc1, FRAME_walkc11, berserk_frames_walk, NULL};
  99. void berserk_walk (edict_t *self)
  100. {
  101. self->monsterinfo.currentmove = &berserk_move_walk;
  102. }
  103. /*
  104. *****************************
  105. SKIPPED THIS FOR NOW!
  106. *****************************
  107. Running -> Arm raised in air
  108. void() berserk_runb1 =[ $r_att1 , berserk_runb2 ] {ai_run(21);};
  109. void() berserk_runb2 =[ $r_att2 , berserk_runb3 ] {ai_run(11);};
  110. void() berserk_runb3 =[ $r_att3 , berserk_runb4 ] {ai_run(21);};
  111. void() berserk_runb4 =[ $r_att4 , berserk_runb5 ] {ai_run(25);};
  112. void() berserk_runb5 =[ $r_att5 , berserk_runb6 ] {ai_run(18);};
  113. void() berserk_runb6 =[ $r_att6 , berserk_runb7 ] {ai_run(19);};
  114. // running with arm in air : start loop
  115. void() berserk_runb7 =[ $r_att7 , berserk_runb8 ] {ai_run(21);};
  116. void() berserk_runb8 =[ $r_att8 , berserk_runb9 ] {ai_run(11);};
  117. void() berserk_runb9 =[ $r_att9 , berserk_runb10 ] {ai_run(21);};
  118. void() berserk_runb10 =[ $r_att10 , berserk_runb11 ] {ai_run(25);};
  119. void() berserk_runb11 =[ $r_att11 , berserk_runb12 ] {ai_run(18);};
  120. void() berserk_runb12 =[ $r_att12 , berserk_runb7 ] {ai_run(19);};
  121. // running with arm in air : end loop
  122. */
  123. mframe_t berserk_frames_run1 [] =
  124. {
  125. ai_run, 21, NULL,
  126. ai_run, 11, NULL,
  127. ai_run, 21, NULL,
  128. ai_run, 25, NULL,
  129. ai_run, 18, NULL,
  130. ai_run, 19, NULL
  131. };
  132. mmove_t berserk_move_run1 = {FRAME_run1, FRAME_run6, berserk_frames_run1, NULL};
  133. void berserk_run (edict_t *self)
  134. {
  135. if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  136. self->monsterinfo.currentmove = &berserk_move_stand;
  137. else
  138. self->monsterinfo.currentmove = &berserk_move_run1;
  139. }
  140. void berserk_attack_spike (edict_t *self)
  141. {
  142. static vec3_t aim = {MELEE_DISTANCE, 0, -24};
  143. fire_hit (self, aim, (15 + (rand() % 6)), 400); // Faster attack -- upwards and backwards
  144. }
  145. void berserk_swing (edict_t *self)
  146. {
  147. gi.sound (self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
  148. }
  149. mframe_t berserk_frames_attack_spike [] =
  150. {
  151. ai_charge, 0, NULL,
  152. ai_charge, 0, NULL,
  153. ai_charge, 0, berserk_swing,
  154. ai_charge, 0, berserk_attack_spike,
  155. ai_charge, 0, NULL,
  156. ai_charge, 0, NULL,
  157. ai_charge, 0, NULL,
  158. ai_charge, 0, NULL
  159. };
  160. mmove_t berserk_move_attack_spike = {FRAME_att_c1, FRAME_att_c8, berserk_frames_attack_spike, berserk_run};
  161. void berserk_attack_club (edict_t *self)
  162. {
  163. vec3_t aim;
  164. VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
  165. fire_hit (self, aim, (5 + (rand() % 6)), 400); // Slower attack
  166. }
  167. mframe_t berserk_frames_attack_club [] =
  168. {
  169. ai_charge, 0, NULL,
  170. ai_charge, 0, NULL,
  171. ai_charge, 0, NULL,
  172. ai_charge, 0, NULL,
  173. ai_charge, 0, berserk_swing,
  174. ai_charge, 0, NULL,
  175. ai_charge, 0, NULL,
  176. ai_charge, 0, NULL,
  177. ai_charge, 0, berserk_attack_club,
  178. ai_charge, 0, NULL,
  179. ai_charge, 0, NULL,
  180. ai_charge, 0, NULL
  181. };
  182. mmove_t berserk_move_attack_club = {FRAME_att_c9, FRAME_att_c20, berserk_frames_attack_club, berserk_run};
  183. void berserk_strike (edict_t *self)
  184. {
  185. //FIXME play impact sound
  186. }
  187. mframe_t berserk_frames_attack_strike [] =
  188. {
  189. ai_move, 0, NULL,
  190. ai_move, 0, NULL,
  191. ai_move, 0, NULL,
  192. ai_move, 0, berserk_swing,
  193. ai_move, 0, NULL,
  194. ai_move, 0, NULL,
  195. ai_move, 0, NULL,
  196. ai_move, 0, berserk_strike,
  197. ai_move, 0, NULL,
  198. ai_move, 0, NULL,
  199. ai_move, 0, NULL,
  200. ai_move, 0, NULL,
  201. ai_move, 9.7, NULL,
  202. ai_move, 13.6, NULL
  203. };
  204. mmove_t berserk_move_attack_strike = {FRAME_att_c21, FRAME_att_c34, berserk_frames_attack_strike, berserk_run};
  205. void berserk_melee (edict_t *self)
  206. {
  207. if ((rand() % 2) == 0)
  208. self->monsterinfo.currentmove = &berserk_move_attack_spike;
  209. else
  210. self->monsterinfo.currentmove = &berserk_move_attack_club;
  211. }
  212. /*
  213. void() berserk_atke1 =[ $r_attb1, berserk_atke2 ] {ai_run(9);};
  214. void() berserk_atke2 =[ $r_attb2, berserk_atke3 ] {ai_run(6);};
  215. void() berserk_atke3 =[ $r_attb3, berserk_atke4 ] {ai_run(18.4);};
  216. void() berserk_atke4 =[ $r_attb4, berserk_atke5 ] {ai_run(25);};
  217. void() berserk_atke5 =[ $r_attb5, berserk_atke6 ] {ai_run(14);};
  218. void() berserk_atke6 =[ $r_attb6, berserk_atke7 ] {ai_run(20);};
  219. void() berserk_atke7 =[ $r_attb7, berserk_atke8 ] {ai_run(8.5);};
  220. void() berserk_atke8 =[ $r_attb8, berserk_atke9 ] {ai_run(3);};
  221. void() berserk_atke9 =[ $r_attb9, berserk_atke10 ] {ai_run(17.5);};
  222. void() berserk_atke10 =[ $r_attb10, berserk_atke11 ] {ai_run(17);};
  223. void() berserk_atke11 =[ $r_attb11, berserk_atke12 ] {ai_run(9);};
  224. void() berserk_atke12 =[ $r_attb12, berserk_atke13 ] {ai_run(25);};
  225. void() berserk_atke13 =[ $r_attb13, berserk_atke14 ] {ai_run(3.7);};
  226. void() berserk_atke14 =[ $r_attb14, berserk_atke15 ] {ai_run(2.6);};
  227. void() berserk_atke15 =[ $r_attb15, berserk_atke16 ] {ai_run(19);};
  228. void() berserk_atke16 =[ $r_attb16, berserk_atke17 ] {ai_run(25);};
  229. void() berserk_atke17 =[ $r_attb17, berserk_atke18 ] {ai_run(19.6);};
  230. void() berserk_atke18 =[ $r_attb18, berserk_run1 ] {ai_run(7.8);};
  231. */
  232. mframe_t berserk_frames_pain1 [] =
  233. {
  234. ai_move, 0, NULL,
  235. ai_move, 0, NULL,
  236. ai_move, 0, NULL,
  237. ai_move, 0, NULL
  238. };
  239. mmove_t berserk_move_pain1 = {FRAME_painc1, FRAME_painc4, berserk_frames_pain1, berserk_run};
  240. mframe_t berserk_frames_pain2 [] =
  241. {
  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. ai_move, 0, NULL,
  254. ai_move, 0, NULL,
  255. ai_move, 0, NULL,
  256. ai_move, 0, NULL,
  257. ai_move, 0, NULL,
  258. ai_move, 0, NULL,
  259. ai_move, 0, NULL,
  260. ai_move, 0, NULL,
  261. ai_move, 0, NULL
  262. };
  263. mmove_t berserk_move_pain2 = {FRAME_painb1, FRAME_painb20, berserk_frames_pain2, berserk_run};
  264. void berserk_pain (edict_t *self, edict_t *other, float kick, int damage)
  265. {
  266. if (self->health < (self->max_health / 2))
  267. self->s.skinnum = 1;
  268. if (level.time < self->pain_debounce_time)
  269. return;
  270. self->pain_debounce_time = level.time + 3;
  271. gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
  272. if (skill->value == 3)
  273. return; // no pain anims in nightmare
  274. if ((damage < 20) || (random() < 0.5))
  275. self->monsterinfo.currentmove = &berserk_move_pain1;
  276. else
  277. self->monsterinfo.currentmove = &berserk_move_pain2;
  278. }
  279. void berserk_dead (edict_t *self)
  280. {
  281. VectorSet (self->mins, -16, -16, -24);
  282. VectorSet (self->maxs, 16, 16, -8);
  283. self->movetype = MOVETYPE_TOSS;
  284. self->svflags |= SVF_DEADMONSTER;
  285. self->nextthink = 0;
  286. gi.linkentity (self);
  287. }
  288. mframe_t berserk_frames_death1 [] =
  289. {
  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. 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_death1 = {FRAME_death1, FRAME_death13, berserk_frames_death1, berserk_dead};
  305. mframe_t berserk_frames_death2 [] =
  306. {
  307. ai_move, 0, NULL,
  308. ai_move, 0, NULL,
  309. ai_move, 0, NULL,
  310. ai_move, 0, NULL,
  311. ai_move, 0, NULL,
  312. ai_move, 0, NULL,
  313. ai_move, 0, NULL,
  314. ai_move, 0, NULL
  315. };
  316. mmove_t berserk_move_death2 = {FRAME_deathc1, FRAME_deathc8, berserk_frames_death2, berserk_dead};
  317. void berserk_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  318. {
  319. int n;
  320. if (self->health <= self->gib_health)
  321. {
  322. gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  323. for (n= 0; n < 2; n++)
  324. ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  325. for (n= 0; n < 4; n++)
  326. ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  327. ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  328. self->deadflag = DEAD_DEAD;
  329. return;
  330. }
  331. if (self->deadflag == DEAD_DEAD)
  332. return;
  333. gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
  334. self->deadflag = DEAD_DEAD;
  335. self->takedamage = DAMAGE_YES;
  336. if (damage >= 50)
  337. self->monsterinfo.currentmove = &berserk_move_death1;
  338. else
  339. self->monsterinfo.currentmove = &berserk_move_death2;
  340. }
  341. /*QUAKED monster_berserk (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  342. */
  343. void SP_monster_berserk (edict_t *self)
  344. {
  345. if (deathmatch->value)
  346. {
  347. G_FreeEdict (self);
  348. return;
  349. }
  350. // pre-caches
  351. sound_pain = gi.soundindex ("berserk/berpain2.wav");
  352. sound_die = gi.soundindex ("berserk/berdeth2.wav");
  353. sound_idle = gi.soundindex ("berserk/beridle1.wav");
  354. sound_punch = gi.soundindex ("berserk/attack.wav");
  355. sound_search = gi.soundindex ("berserk/bersrch1.wav");
  356. sound_sight = gi.soundindex ("berserk/sight.wav");
  357. self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2");
  358. VectorSet (self->mins, -16, -16, -24);
  359. VectorSet (self->maxs, 16, 16, 32);
  360. self->movetype = MOVETYPE_STEP;
  361. self->solid = SOLID_BBOX;
  362. self->health = 240;
  363. self->gib_health = -60;
  364. self->mass = 250;
  365. self->pain = berserk_pain;
  366. self->die = berserk_die;
  367. self->monsterinfo.stand = berserk_stand;
  368. self->monsterinfo.walk = berserk_walk;
  369. self->monsterinfo.run = berserk_run;
  370. self->monsterinfo.dodge = NULL;
  371. self->monsterinfo.attack = NULL;
  372. self->monsterinfo.melee = berserk_melee;
  373. self->monsterinfo.sight = berserk_sight;
  374. self->monsterinfo.search = berserk_search;
  375. self->monsterinfo.currentmove = &berserk_move_stand;
  376. self->monsterinfo.scale = MODEL_SCALE;
  377. gi.linkentity (self);
  378. walkmonster_start (self);
  379. }