File: game\m_gladiator.c

    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 }
  388