Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

m_gunner.c (14951B)


      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 GUNNER
     24 
     25 ==============================================================================
     26 */
     27 
     28 #include "g_local.h"
     29 #include "m_gunner.h"
     30 
     31 
     32 static int	sound_pain;
     33 static int	sound_pain2;
     34 static int	sound_death;
     35 static int	sound_idle;
     36 static int	sound_open;
     37 static int	sound_search;
     38 static int	sound_sight;
     39 
     40 
     41 void gunner_idlesound (edict_t *self)
     42 {
     43 	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
     44 }
     45 
     46 void gunner_sight (edict_t *self, edict_t *other)
     47 {
     48 	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
     49 }
     50 
     51 void gunner_search (edict_t *self)
     52 {
     53 	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
     54 }
     55 
     56 
     57 qboolean visible (edict_t *self, edict_t *other);
     58 void GunnerGrenade (edict_t *self);
     59 void GunnerFire (edict_t *self);
     60 void gunner_fire_chain(edict_t *self);
     61 void gunner_refire_chain(edict_t *self);
     62 
     63 
     64 void gunner_stand (edict_t *self);
     65 
     66 mframe_t gunner_frames_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, gunner_idlesound,
     76 	ai_stand, 0, NULL,
     77 
     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 	ai_stand, 0, NULL,
     90 	ai_stand, 0, NULL,
     91 	ai_stand, 0, NULL,
     92 	ai_stand, 0, NULL,
     93 	ai_stand, 0, NULL,
     94 	ai_stand, 0, NULL,
     95 	ai_stand, 0, NULL,
     96 	ai_stand, 0, NULL,
     97 	ai_stand, 0, NULL,
     98 	ai_stand, 0, NULL,
     99 
    100 	ai_stand, 0, NULL,
    101 	ai_stand, 0, NULL,
    102 	ai_stand, 0, NULL,
    103 	ai_stand, 0, NULL,
    104 	ai_stand, 0, NULL,
    105 	ai_stand, 0, NULL,
    106 	ai_stand, 0, NULL,
    107 	ai_stand, 0, NULL,
    108 	ai_stand, 0, NULL,
    109 	ai_stand, 0, NULL,
    110 
    111 	ai_stand, 0, NULL,
    112 	ai_stand, 0, NULL,
    113 	ai_stand, 0, NULL,
    114 	ai_stand, 0, NULL,
    115 	ai_stand, 0, NULL,
    116 	ai_stand, 0, NULL,
    117 	ai_stand, 0, NULL,
    118 	ai_stand, 0, NULL,
    119 	ai_stand, 0, NULL,
    120 	ai_stand, 0, NULL
    121 };
    122 mmove_t	gunner_move_fidget = {FRAME_stand31, FRAME_stand70, gunner_frames_fidget, gunner_stand};
    123 
    124 void gunner_fidget (edict_t *self)
    125 {
    126 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
    127 		return;
    128 	if (random() <= 0.05)
    129 		self->monsterinfo.currentmove = &gunner_move_fidget;
    130 }
    131 
    132 mframe_t gunner_frames_stand [] =
    133 {
    134 	ai_stand, 0, NULL,
    135 	ai_stand, 0, NULL,
    136 	ai_stand, 0, NULL,
    137 	ai_stand, 0, NULL,
    138 	ai_stand, 0, NULL,
    139 	ai_stand, 0, NULL,
    140 	ai_stand, 0, NULL,
    141 	ai_stand, 0, NULL,
    142 	ai_stand, 0, NULL,
    143 	ai_stand, 0, gunner_fidget,
    144 
    145 	ai_stand, 0, NULL,
    146 	ai_stand, 0, NULL,
    147 	ai_stand, 0, NULL,
    148 	ai_stand, 0, NULL,
    149 	ai_stand, 0, NULL,
    150 	ai_stand, 0, NULL,
    151 	ai_stand, 0, NULL,
    152 	ai_stand, 0, NULL,
    153 	ai_stand, 0, NULL,
    154 	ai_stand, 0, gunner_fidget,
    155 
    156 	ai_stand, 0, NULL,
    157 	ai_stand, 0, NULL,
    158 	ai_stand, 0, NULL,
    159 	ai_stand, 0, NULL,
    160 	ai_stand, 0, NULL,
    161 	ai_stand, 0, NULL,
    162 	ai_stand, 0, NULL,
    163 	ai_stand, 0, NULL,
    164 	ai_stand, 0, NULL,
    165 	ai_stand, 0, gunner_fidget
    166 };
    167 mmove_t	gunner_move_stand = {FRAME_stand01, FRAME_stand30, gunner_frames_stand, NULL};
    168 
    169 void gunner_stand (edict_t *self)
    170 {
    171 		self->monsterinfo.currentmove = &gunner_move_stand;
    172 }
    173 
    174 
    175 mframe_t gunner_frames_walk [] =
    176 {
    177 	ai_walk, 0, NULL,
    178 	ai_walk, 3, NULL,
    179 	ai_walk, 4, NULL,
    180 	ai_walk, 5, NULL,
    181 	ai_walk, 7, NULL,
    182 	ai_walk, 2, NULL,
    183 	ai_walk, 6, NULL,
    184 	ai_walk, 4, NULL,
    185 	ai_walk, 2, NULL,
    186 	ai_walk, 7, NULL,
    187 	ai_walk, 5, NULL,
    188 	ai_walk, 7, NULL,
    189 	ai_walk, 4, NULL
    190 };
    191 mmove_t gunner_move_walk = {FRAME_walk07, FRAME_walk19, gunner_frames_walk, NULL};
    192 
    193 void gunner_walk (edict_t *self)
    194 {
    195 	self->monsterinfo.currentmove = &gunner_move_walk;
    196 }
    197 
    198 mframe_t gunner_frames_run [] =
    199 {
    200 	ai_run, 26, NULL,
    201 	ai_run, 9,  NULL,
    202 	ai_run, 9,  NULL,
    203 	ai_run, 9,  NULL,
    204 	ai_run, 15, NULL,
    205 	ai_run, 10, NULL,
    206 	ai_run, 13, NULL,
    207 	ai_run, 6,  NULL
    208 };
    209 
    210 mmove_t gunner_move_run = {FRAME_run01, FRAME_run08, gunner_frames_run, NULL};
    211 
    212 void gunner_run (edict_t *self)
    213 {
    214 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
    215 		self->monsterinfo.currentmove = &gunner_move_stand;
    216 	else
    217 		self->monsterinfo.currentmove = &gunner_move_run;
    218 }
    219 
    220 mframe_t gunner_frames_runandshoot [] =
    221 {
    222 	ai_run, 32, NULL,
    223 	ai_run, 15, NULL,
    224 	ai_run, 10, NULL,
    225 	ai_run, 18, NULL,
    226 	ai_run, 8,  NULL,
    227 	ai_run, 20, NULL
    228 };
    229 
    230 mmove_t gunner_move_runandshoot = {FRAME_runs01, FRAME_runs06, gunner_frames_runandshoot, NULL};
    231 
    232 void gunner_runandshoot (edict_t *self)
    233 {
    234 	self->monsterinfo.currentmove = &gunner_move_runandshoot;
    235 }
    236 
    237 mframe_t gunner_frames_pain3 [] =
    238 {
    239 	ai_move, -3, NULL,
    240 	ai_move, 1,	 NULL,
    241 	ai_move, 1,	 NULL,
    242 	ai_move, 0,	 NULL,
    243 	ai_move, 1,	 NULL
    244 };
    245 mmove_t gunner_move_pain3 = {FRAME_pain301, FRAME_pain305, gunner_frames_pain3, gunner_run};
    246 
    247 mframe_t gunner_frames_pain2 [] =
    248 {
    249 	ai_move, -2, NULL,
    250 	ai_move, 11, NULL,
    251 	ai_move, 6,	 NULL,
    252 	ai_move, 2,	 NULL,
    253 	ai_move, -1, NULL,
    254 	ai_move, -7, NULL,
    255 	ai_move, -2, NULL,
    256 	ai_move, -7, NULL
    257 };
    258 mmove_t gunner_move_pain2 = {FRAME_pain201, FRAME_pain208, gunner_frames_pain2, gunner_run};
    259 
    260 mframe_t gunner_frames_pain1 [] =
    261 {
    262 	ai_move, 2,	 NULL,
    263 	ai_move, 0,	 NULL,
    264 	ai_move, -5, NULL,
    265 	ai_move, 3,	 NULL,
    266 	ai_move, -1, NULL,
    267 	ai_move, 0,	 NULL,
    268 	ai_move, 0,	 NULL,
    269 	ai_move, 0,	 NULL,
    270 	ai_move, 0,	 NULL,
    271 	ai_move, 1,	 NULL,
    272 	ai_move, 1,	 NULL,
    273 	ai_move, 2,	 NULL,
    274 	ai_move, 1,	 NULL,
    275 	ai_move, 0,	 NULL,
    276 	ai_move, -2, NULL,
    277 	ai_move, -2, NULL,
    278 	ai_move, 0,	 NULL,
    279 	ai_move, 0,	 NULL
    280 };
    281 mmove_t gunner_move_pain1 = {FRAME_pain101, FRAME_pain118, gunner_frames_pain1, gunner_run};
    282 
    283 void gunner_pain (edict_t *self, edict_t *other, float kick, int damage)
    284 {
    285 	if (self->health < (self->max_health / 2))
    286 		self->s.skinnum = 1;
    287 
    288 	if (level.time < self->pain_debounce_time)
    289 		return;
    290 
    291 	self->pain_debounce_time = level.time + 3;
    292 
    293 	if (rand()&1)
    294 		gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
    295 	else
    296 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
    297 
    298 	if (skill->value == 3)
    299 		return;		// no pain anims in nightmare
    300 
    301 	if (damage <= 10)
    302 		self->monsterinfo.currentmove = &gunner_move_pain3;
    303 	else if (damage <= 25)
    304 		self->monsterinfo.currentmove = &gunner_move_pain2;
    305 	else
    306 		self->monsterinfo.currentmove = &gunner_move_pain1;
    307 }
    308 
    309 void gunner_dead (edict_t *self)
    310 {
    311 	VectorSet (self->mins, -16, -16, -24);
    312 	VectorSet (self->maxs, 16, 16, -8);
    313 	self->movetype = MOVETYPE_TOSS;
    314 	self->svflags |= SVF_DEADMONSTER;
    315 	self->nextthink = 0;
    316 	gi.linkentity (self);
    317 }
    318 
    319 mframe_t gunner_frames_death [] =
    320 {
    321 	ai_move, 0,	 NULL,
    322 	ai_move, 0,	 NULL,
    323 	ai_move, 0,	 NULL,
    324 	ai_move, -7, NULL,
    325 	ai_move, -3, NULL,
    326 	ai_move, -5, NULL,
    327 	ai_move, 8,	 NULL,
    328 	ai_move, 6,	 NULL,
    329 	ai_move, 0,	 NULL,
    330 	ai_move, 0,	 NULL,
    331 	ai_move, 0,	 NULL
    332 };
    333 mmove_t gunner_move_death = {FRAME_death01, FRAME_death11, gunner_frames_death, gunner_dead};
    334 
    335 void gunner_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
    336 {
    337 	int		n;
    338 
    339 // check for gib
    340 	if (self->health <= self->gib_health)
    341 	{
    342 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
    343 		for (n= 0; n < 2; n++)
    344 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
    345 		for (n= 0; n < 4; n++)
    346 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
    347 		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
    348 		self->deadflag = DEAD_DEAD;
    349 		return;
    350 	}
    351 
    352 	if (self->deadflag == DEAD_DEAD)
    353 		return;
    354 
    355 // regular death
    356 	gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
    357 	self->deadflag = DEAD_DEAD;
    358 	self->takedamage = DAMAGE_YES;
    359 	self->monsterinfo.currentmove = &gunner_move_death;
    360 }
    361 
    362 
    363 void gunner_duck_down (edict_t *self)
    364 {
    365 	if (self->monsterinfo.aiflags & AI_DUCKED)
    366 		return;
    367 	self->monsterinfo.aiflags |= AI_DUCKED;
    368 	if (skill->value >= 2)
    369 	{
    370 		if (random() > 0.5)
    371 			GunnerGrenade (self);
    372 	}
    373 
    374 	self->maxs[2] -= 32;
    375 	self->takedamage = DAMAGE_YES;
    376 	self->monsterinfo.pausetime = level.time + 1;
    377 	gi.linkentity (self);
    378 }
    379 
    380 void gunner_duck_hold (edict_t *self)
    381 {
    382 	if (level.time >= self->monsterinfo.pausetime)
    383 		self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
    384 	else
    385 		self->monsterinfo.aiflags |= AI_HOLD_FRAME;
    386 }
    387 
    388 void gunner_duck_up (edict_t *self)
    389 {
    390 	self->monsterinfo.aiflags &= ~AI_DUCKED;
    391 	self->maxs[2] += 32;
    392 	self->takedamage = DAMAGE_AIM;
    393 	gi.linkentity (self);
    394 }
    395 
    396 mframe_t gunner_frames_duck [] =
    397 {
    398 	ai_move, 1,  gunner_duck_down,
    399 	ai_move, 1,  NULL,
    400 	ai_move, 1,  gunner_duck_hold,
    401 	ai_move, 0,  NULL,
    402 	ai_move, -1, NULL,
    403 	ai_move, -1, NULL,
    404 	ai_move, 0,  gunner_duck_up,
    405 	ai_move, -1, NULL
    406 };
    407 mmove_t	gunner_move_duck = {FRAME_duck01, FRAME_duck08, gunner_frames_duck, gunner_run};
    408 
    409 void gunner_dodge (edict_t *self, edict_t *attacker, float eta)
    410 {
    411 	if (random() > 0.25)
    412 		return;
    413 
    414 	if (!self->enemy)
    415 		self->enemy = attacker;
    416 
    417 	self->monsterinfo.currentmove = &gunner_move_duck;
    418 }
    419 
    420 
    421 void gunner_opengun (edict_t *self)
    422 {
    423 	gi.sound (self, CHAN_VOICE, sound_open, 1, ATTN_IDLE, 0);
    424 }
    425 
    426 void GunnerFire (edict_t *self)
    427 {
    428 	vec3_t	start;
    429 	vec3_t	forward, right;
    430 	vec3_t	target;
    431 	vec3_t	aim;
    432 	int		flash_number;
    433 
    434 	flash_number = MZ2_GUNNER_MACHINEGUN_1 + (self->s.frame - FRAME_attak216);
    435 
    436 	AngleVectors (self->s.angles, forward, right, NULL);
    437 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
    438 
    439 	// project enemy back a bit and target there
    440 	VectorCopy (self->enemy->s.origin, target);
    441 	VectorMA (target, -0.2, self->enemy->velocity, target);
    442 	target[2] += self->enemy->viewheight;
    443 
    444 	VectorSubtract (target, start, aim);
    445 	VectorNormalize (aim);
    446 	monster_fire_bullet (self, start, aim, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
    447 }
    448 
    449 void GunnerGrenade (edict_t *self)
    450 {
    451 	vec3_t	start;
    452 	vec3_t	forward, right;
    453 	vec3_t	aim;
    454 	int		flash_number;
    455 
    456 	if (self->s.frame == FRAME_attak105)
    457 		flash_number = MZ2_GUNNER_GRENADE_1;
    458 	else if (self->s.frame == FRAME_attak108)
    459 		flash_number = MZ2_GUNNER_GRENADE_2;
    460 	else if (self->s.frame == FRAME_attak111)
    461 		flash_number = MZ2_GUNNER_GRENADE_3;
    462 	else // (self->s.frame == FRAME_attak114)
    463 		flash_number = MZ2_GUNNER_GRENADE_4;
    464 
    465 	AngleVectors (self->s.angles, forward, right, NULL);
    466 	G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
    467 
    468 	//FIXME : do a spread -225 -75 75 225 degrees around forward
    469 	VectorCopy (forward, aim);
    470 
    471 	monster_fire_grenade (self, start, aim, 50, 600, flash_number);
    472 }
    473 
    474 mframe_t gunner_frames_attack_chain [] =
    475 {
    476 	/*
    477 	ai_charge, 0, NULL,
    478 	ai_charge, 0, NULL,
    479 	ai_charge, 0, NULL,
    480 	ai_charge, 0, NULL,
    481 	ai_charge, 0, NULL,
    482 	ai_charge, 0, NULL,
    483 	ai_charge, 0, NULL,
    484 	ai_charge, 0, NULL,
    485 	*/
    486 	ai_charge, 0, gunner_opengun,
    487 	ai_charge, 0, NULL,
    488 	ai_charge, 0, NULL,
    489 	ai_charge, 0, NULL,
    490 	ai_charge, 0, NULL,
    491 	ai_charge, 0, NULL,
    492 	ai_charge, 0, NULL
    493 };
    494 mmove_t gunner_move_attack_chain = {FRAME_attak209, FRAME_attak215, gunner_frames_attack_chain, gunner_fire_chain};
    495 
    496 mframe_t gunner_frames_fire_chain [] =
    497 {
    498 	ai_charge,   0, GunnerFire,
    499 	ai_charge,   0, GunnerFire,
    500 	ai_charge,   0, GunnerFire,
    501 	ai_charge,   0, GunnerFire,
    502 	ai_charge,   0, GunnerFire,
    503 	ai_charge,   0, GunnerFire,
    504 	ai_charge,   0, GunnerFire,
    505 	ai_charge,   0, GunnerFire
    506 };
    507 mmove_t gunner_move_fire_chain = {FRAME_attak216, FRAME_attak223, gunner_frames_fire_chain, gunner_refire_chain};
    508 
    509 mframe_t gunner_frames_endfire_chain [] =
    510 {
    511 	ai_charge, 0, NULL,
    512 	ai_charge, 0, NULL,
    513 	ai_charge, 0, NULL,
    514 	ai_charge, 0, NULL,
    515 	ai_charge, 0, NULL,
    516 	ai_charge, 0, NULL,
    517 	ai_charge, 0, NULL
    518 };
    519 mmove_t gunner_move_endfire_chain = {FRAME_attak224, FRAME_attak230, gunner_frames_endfire_chain, gunner_run};
    520 
    521 mframe_t gunner_frames_attack_grenade [] =
    522 {
    523 	ai_charge, 0, NULL,
    524 	ai_charge, 0, NULL,
    525 	ai_charge, 0, NULL,
    526 	ai_charge, 0, NULL,
    527 	ai_charge, 0, GunnerGrenade,
    528 	ai_charge, 0, NULL,
    529 	ai_charge, 0, NULL,
    530 	ai_charge, 0, GunnerGrenade,
    531 	ai_charge, 0, NULL,
    532 	ai_charge, 0, NULL,
    533 	ai_charge, 0, GunnerGrenade,
    534 	ai_charge, 0, NULL,
    535 	ai_charge, 0, NULL,
    536 	ai_charge, 0, GunnerGrenade,
    537 	ai_charge, 0, NULL,
    538 	ai_charge, 0, NULL,
    539 	ai_charge, 0, NULL,
    540 	ai_charge, 0, NULL,
    541 	ai_charge, 0, NULL,
    542 	ai_charge, 0, NULL,
    543 	ai_charge, 0, NULL
    544 };
    545 mmove_t gunner_move_attack_grenade = {FRAME_attak101, FRAME_attak121, gunner_frames_attack_grenade, gunner_run};
    546 
    547 void gunner_attack(edict_t *self)
    548 {
    549 	if (range (self, self->enemy) == RANGE_MELEE)
    550 	{
    551 		self->monsterinfo.currentmove = &gunner_move_attack_chain;
    552 	}
    553 	else
    554 	{
    555 		if (random() <= 0.5)
    556 			self->monsterinfo.currentmove = &gunner_move_attack_grenade;
    557 		else
    558 			self->monsterinfo.currentmove = &gunner_move_attack_chain;
    559 	}
    560 }
    561 
    562 void gunner_fire_chain(edict_t *self)
    563 {
    564 	self->monsterinfo.currentmove = &gunner_move_fire_chain;
    565 }
    566 
    567 void gunner_refire_chain(edict_t *self)
    568 {
    569 	if (self->enemy->health > 0)
    570 		if ( visible (self, self->enemy) )
    571 			if (random() <= 0.5)
    572 			{
    573 				self->monsterinfo.currentmove = &gunner_move_fire_chain;
    574 				return;
    575 			}
    576 	self->monsterinfo.currentmove = &gunner_move_endfire_chain;
    577 }
    578 
    579 /*QUAKED monster_gunner (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
    580 */
    581 void SP_monster_gunner (edict_t *self)
    582 {
    583 	if (deathmatch->value)
    584 	{
    585 		G_FreeEdict (self);
    586 		return;
    587 	}
    588 
    589 	sound_death = gi.soundindex ("gunner/death1.wav");	
    590 	sound_pain = gi.soundindex ("gunner/gunpain2.wav");	
    591 	sound_pain2 = gi.soundindex ("gunner/gunpain1.wav");	
    592 	sound_idle = gi.soundindex ("gunner/gunidle1.wav");	
    593 	sound_open = gi.soundindex ("gunner/gunatck1.wav");	
    594 	sound_search = gi.soundindex ("gunner/gunsrch1.wav");	
    595 	sound_sight = gi.soundindex ("gunner/sight1.wav");	
    596 
    597 	gi.soundindex ("gunner/gunatck2.wav");
    598 	gi.soundindex ("gunner/gunatck3.wav");
    599 
    600 	self->movetype = MOVETYPE_STEP;
    601 	self->solid = SOLID_BBOX;
    602 	self->s.modelindex = gi.modelindex ("models/monsters/gunner/tris.md2");
    603 	VectorSet (self->mins, -16, -16, -24);
    604 	VectorSet (self->maxs, 16, 16, 32);
    605 
    606 	self->health = 175;
    607 	self->gib_health = -70;
    608 	self->mass = 200;
    609 
    610 	self->pain = gunner_pain;
    611 	self->die = gunner_die;
    612 
    613 	self->monsterinfo.stand = gunner_stand;
    614 	self->monsterinfo.walk = gunner_walk;
    615 	self->monsterinfo.run = gunner_run;
    616 	self->monsterinfo.dodge = gunner_dodge;
    617 	self->monsterinfo.attack = gunner_attack;
    618 	self->monsterinfo.melee = NULL;
    619 	self->monsterinfo.sight = gunner_sight;
    620 	self->monsterinfo.search = gunner_search;
    621 
    622 	gi.linkentity (self);
    623 
    624 	self->monsterinfo.currentmove = &gunner_move_stand;	
    625 	self->monsterinfo.scale = MODEL_SCALE;
    626 
    627 	walkmonster_start (self);
    628 }