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