Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

m_gladiator.c (9866B)


      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 GLADIATOR
     24 
     25 ==============================================================================
     26 */
     27 
     28 #include "g_local.h"
     29 #include "m_gladiator.h"
     30 
     31 
     32 static int	sound_pain1;
     33 static int	sound_pain2;
     34 static int	sound_die;
     35 static int	sound_gun;
     36 static int	sound_cleaver_swing;
     37 static int	sound_cleaver_hit;
     38 static int	sound_cleaver_miss;
     39 static int	sound_idle;
     40 static int	sound_search;
     41 static int	sound_sight;
     42 
     43 
     44 void gladiator_idle (edict_t *self)
     45 {
     46 	gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
     47 }
     48 
     49 void gladiator_sight (edict_t *self, edict_t *other)
     50 {
     51 	gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
     52 }
     53 
     54 void gladiator_search (edict_t *self)
     55 {
     56 	gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
     57 }
     58 
     59 void gladiator_cleaver_swing (edict_t *self)
     60 {
     61 	gi.sound (self, CHAN_WEAPON, sound_cleaver_swing, 1, ATTN_NORM, 0);
     62 }
     63 
     64 mframe_t gladiator_frames_stand [] =
     65 {
     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 };
     74 mmove_t gladiator_move_stand = {FRAME_stand1, FRAME_stand7, gladiator_frames_stand, NULL};
     75 
     76 void gladiator_stand (edict_t *self)
     77 {
     78 	self->monsterinfo.currentmove = &gladiator_move_stand;
     79 }
     80 
     81 
     82 mframe_t gladiator_frames_walk [] =
     83 {
     84 	ai_walk, 15, NULL,
     85 	ai_walk, 7,  NULL,
     86 	ai_walk, 6,  NULL,
     87 	ai_walk, 5,  NULL,
     88 	ai_walk, 2,  NULL,
     89 	ai_walk, 0,  NULL,
     90 	ai_walk, 2,  NULL,
     91 	ai_walk, 8,  NULL,
     92 	ai_walk, 12, NULL,
     93 	ai_walk, 8,  NULL,
     94 	ai_walk, 5,  NULL,
     95 	ai_walk, 5,  NULL,
     96 	ai_walk, 2,  NULL,
     97 	ai_walk, 2,  NULL,
     98 	ai_walk, 1,  NULL,
     99 	ai_walk, 8,  NULL
    100 };
    101 mmove_t gladiator_move_walk = {FRAME_walk1, FRAME_walk16, gladiator_frames_walk, NULL};
    102 
    103 void gladiator_walk (edict_t *self)
    104 {
    105 	self->monsterinfo.currentmove = &gladiator_move_walk;
    106 }
    107 
    108 
    109 mframe_t gladiator_frames_run [] =
    110 {
    111 	ai_run, 23,	NULL,
    112 	ai_run, 14,	NULL,
    113 	ai_run, 14,	NULL,
    114 	ai_run, 21,	NULL,
    115 	ai_run, 12,	NULL,
    116 	ai_run, 13,	NULL
    117 };
    118 mmove_t gladiator_move_run = {FRAME_run1, FRAME_run6, gladiator_frames_run, NULL};
    119 
    120 void gladiator_run (edict_t *self)
    121 {
    122 	if (self->monsterinfo.aiflags & AI_STAND_GROUND)
    123 		self->monsterinfo.currentmove = &gladiator_move_stand;
    124 	else
    125 		self->monsterinfo.currentmove = &gladiator_move_run;
    126 }
    127 
    128 
    129 void GaldiatorMelee (edict_t *self)
    130 {
    131 	vec3_t	aim;
    132 
    133 	VectorSet (aim, MELEE_DISTANCE, self->mins[0], -4);
    134 	if (fire_hit (self, aim, (20 + (rand() %5)), 300))
    135 		gi.sound (self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0);
    136 	else
    137 		gi.sound (self, CHAN_AUTO, sound_cleaver_miss, 1, ATTN_NORM, 0);
    138 }
    139 
    140 mframe_t gladiator_frames_attack_melee [] =
    141 {
    142 	ai_charge, 0, NULL,
    143 	ai_charge, 0, NULL,
    144 	ai_charge, 0, NULL,
    145 	ai_charge, 0, NULL,
    146 	ai_charge, 0, gladiator_cleaver_swing,
    147 	ai_charge, 0, NULL,
    148 	ai_charge, 0, GaldiatorMelee,
    149 	ai_charge, 0, NULL,
    150 	ai_charge, 0, NULL,
    151 	ai_charge, 0, NULL,
    152 	ai_charge, 0, gladiator_cleaver_swing,
    153 	ai_charge, 0, NULL,
    154 	ai_charge, 0, NULL,
    155 	ai_charge, 0, GaldiatorMelee,
    156 	ai_charge, 0, NULL,
    157 	ai_charge, 0, NULL,
    158 	ai_charge, 0, NULL
    159 };
    160 mmove_t gladiator_move_attack_melee = {FRAME_melee1, FRAME_melee17, gladiator_frames_attack_melee, gladiator_run};
    161 
    162 void gladiator_melee(edict_t *self)
    163 {
    164 	self->monsterinfo.currentmove = &gladiator_move_attack_melee;
    165 }
    166 
    167 
    168 void GladiatorGun (edict_t *self)
    169 {
    170 	vec3_t	start;
    171 	vec3_t	dir;
    172 	vec3_t	forward, right;
    173 
    174 	AngleVectors (self->s.angles, forward, right, NULL);
    175 	G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_GLADIATOR_RAILGUN_1], forward, right, start);
    176 
    177 	// calc direction to where we targted
    178 	VectorSubtract (self->pos1, start, dir);
    179 	VectorNormalize (dir);
    180 
    181 	monster_fire_railgun (self, start, dir, 50, 100, MZ2_GLADIATOR_RAILGUN_1);
    182 }
    183 
    184 mframe_t gladiator_frames_attack_gun [] =
    185 {
    186 	ai_charge, 0, NULL,
    187 	ai_charge, 0, NULL,
    188 	ai_charge, 0, NULL,
    189 	ai_charge, 0, GladiatorGun,
    190 	ai_charge, 0, NULL,
    191 	ai_charge, 0, NULL,
    192 	ai_charge, 0, NULL,
    193 	ai_charge, 0, NULL,
    194 	ai_charge, 0, NULL
    195 };
    196 mmove_t gladiator_move_attack_gun = {FRAME_attack1, FRAME_attack9, gladiator_frames_attack_gun, gladiator_run};
    197 
    198 void gladiator_attack(edict_t *self)
    199 {
    200 	float	range;
    201 	vec3_t	v;
    202 
    203 	// a small safe zone
    204 	VectorSubtract (self->s.origin, self->enemy->s.origin, v);
    205 	range = VectorLength(v);
    206 	if (range <= (MELEE_DISTANCE + 32))
    207 		return;
    208 
    209 	// charge up the railgun
    210 	gi.sound (self, CHAN_WEAPON, sound_gun, 1, ATTN_NORM, 0);
    211 	VectorCopy (self->enemy->s.origin, self->pos1);	//save for aiming the shot
    212 	self->pos1[2] += self->enemy->viewheight;
    213 	self->monsterinfo.currentmove = &gladiator_move_attack_gun;
    214 }
    215 
    216 
    217 mframe_t gladiator_frames_pain [] =
    218 {
    219 	ai_move, 0, NULL,
    220 	ai_move, 0, NULL,
    221 	ai_move, 0, NULL,
    222 	ai_move, 0, NULL,
    223 	ai_move, 0, NULL,
    224 	ai_move, 0, NULL
    225 };
    226 mmove_t gladiator_move_pain = {FRAME_pain1, FRAME_pain6, gladiator_frames_pain, gladiator_run};
    227 
    228 mframe_t gladiator_frames_pain_air [] =
    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 };
    238 mmove_t gladiator_move_pain_air = {FRAME_painup1, FRAME_painup7, gladiator_frames_pain_air, gladiator_run};
    239 
    240 void gladiator_pain (edict_t *self, edict_t *other, float kick, int damage)
    241 {
    242 
    243 	if (self->health < (self->max_health / 2))
    244 		self->s.skinnum = 1;
    245 
    246 	if (level.time < self->pain_debounce_time)
    247 	{
    248 		if ((self->velocity[2] > 100) && (self->monsterinfo.currentmove == &gladiator_move_pain))
    249 			self->monsterinfo.currentmove = &gladiator_move_pain_air;
    250 		return;
    251 	}
    252 
    253 	self->pain_debounce_time = level.time + 3;
    254 
    255 	if (random() < 0.5)
    256 		gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
    257 	else
    258 		gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
    259 
    260 	if (skill->value == 3)
    261 		return;		// no pain anims in nightmare
    262 
    263 	if (self->velocity[2] > 100)
    264 		self->monsterinfo.currentmove = &gladiator_move_pain_air;
    265 	else
    266 		self->monsterinfo.currentmove = &gladiator_move_pain;
    267 	
    268 }
    269 
    270 
    271 void gladiator_dead (edict_t *self)
    272 {
    273 	VectorSet (self->mins, -16, -16, -24);
    274 	VectorSet (self->maxs, 16, 16, -8);
    275 	self->movetype = MOVETYPE_TOSS;
    276 	self->svflags |= SVF_DEADMONSTER;
    277 	self->nextthink = 0;
    278 	gi.linkentity (self);
    279 }
    280 
    281 mframe_t gladiator_frames_death [] =
    282 {
    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 	ai_move, 0, NULL,
    302 	ai_move, 0, NULL,
    303 	ai_move, 0, NULL,
    304 	ai_move, 0, NULL
    305 };
    306 mmove_t gladiator_move_death = {FRAME_death1, FRAME_death22, gladiator_frames_death, gladiator_dead};
    307 
    308 void gladiator_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
    309 {
    310 	int		n;
    311 
    312 // check for gib
    313 	if (self->health <= self->gib_health)
    314 	{
    315 		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
    316 		for (n= 0; n < 2; n++)
    317 			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
    318 		for (n= 0; n < 4; n++)
    319 			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
    320 		ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
    321 		self->deadflag = DEAD_DEAD;
    322 		return;
    323 	}
    324 
    325 	if (self->deadflag == DEAD_DEAD)
    326 		return;
    327 
    328 // regular death
    329 	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
    330 	self->deadflag = DEAD_DEAD;
    331 	self->takedamage = DAMAGE_YES;
    332 
    333 	self->monsterinfo.currentmove = &gladiator_move_death;
    334 }
    335 
    336 
    337 /*QUAKED monster_gladiator (1 .5 0) (-32 -32 -24) (32 32 64) Ambush Trigger_Spawn Sight
    338 */
    339 void SP_monster_gladiator (edict_t *self)
    340 {
    341 	if (deathmatch->value)
    342 	{
    343 		G_FreeEdict (self);
    344 		return;
    345 	}
    346 
    347 
    348 	sound_pain1 = gi.soundindex ("gladiator/pain.wav");	
    349 	sound_pain2 = gi.soundindex ("gladiator/gldpain2.wav");	
    350 	sound_die = gi.soundindex ("gladiator/glddeth2.wav");	
    351 	sound_gun = gi.soundindex ("gladiator/railgun.wav");
    352 	sound_cleaver_swing = gi.soundindex ("gladiator/melee1.wav");
    353 	sound_cleaver_hit = gi.soundindex ("gladiator/melee2.wav");
    354 	sound_cleaver_miss = gi.soundindex ("gladiator/melee3.wav");
    355 	sound_idle = gi.soundindex ("gladiator/gldidle1.wav");
    356 	sound_search = gi.soundindex ("gladiator/gldsrch1.wav");
    357 	sound_sight = gi.soundindex ("gladiator/sight.wav");
    358 
    359 	self->movetype = MOVETYPE_STEP;
    360 	self->solid = SOLID_BBOX;
    361 	self->s.modelindex = gi.modelindex ("models/monsters/gladiatr/tris.md2");
    362 	VectorSet (self->mins, -32, -32, -24);
    363 	VectorSet (self->maxs, 32, 32, 64);
    364 
    365 	self->health = 400;
    366 	self->gib_health = -175;
    367 	self->mass = 400;
    368 
    369 	self->pain = gladiator_pain;
    370 	self->die = gladiator_die;
    371 
    372 	self->monsterinfo.stand = gladiator_stand;
    373 	self->monsterinfo.walk = gladiator_walk;
    374 	self->monsterinfo.run = gladiator_run;
    375 	self->monsterinfo.dodge = NULL;
    376 	self->monsterinfo.attack = gladiator_attack;
    377 	self->monsterinfo.melee = gladiator_melee;
    378 	self->monsterinfo.sight = gladiator_sight;
    379 	self->monsterinfo.idle = gladiator_idle;
    380 	self->monsterinfo.search = gladiator_search;
    381 
    382 	gi.linkentity (self);
    383 	self->monsterinfo.currentmove = &gladiator_move_stand;
    384 	self->monsterinfo.scale = MODEL_SCALE;
    385 
    386 	walkmonster_start (self);
    387 }