Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

m_berserk.c (11972B)


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