File: game\m_infantry.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 INFANTRY
   24 
   25 ==============================================================================
   26 */
   27 
   28 #include "g_local.h"
   29 #include "m_infantry.h"
   30 
   31 void InfantryMachineGun (edict_t *self);
   32 
   33 
   34 static int      sound_pain1;
   35 static int      sound_pain2;
   36 static int      sound_die1;
   37 static int      sound_die2;
   38 
   39 static int      sound_gunshot;
   40 static int      sound_weapon_cock;
   41 static int      sound_punch_swing;
   42 static int      sound_punch_hit;
   43 static int      sound_sight;
   44 static int      sound_search;
   45 static int      sound_idle;
   46 
   47 
   48 mframe_t infantry_frames_stand [] =
   49 {
   50         ai_stand, 0, NULL,
   51         ai_stand, 0, NULL,
   52         ai_stand, 0, NULL,
   53         ai_stand, 0, NULL,
   54         ai_stand, 0, NULL,
   55         ai_stand, 0, NULL,
   56         ai_stand, 0, NULL,
   57         ai_stand, 0, NULL,
   58         ai_stand, 0, NULL,
   59         ai_stand, 0, NULL,
   60         ai_stand, 0, NULL,
   61         ai_stand, 0, NULL,
   62         ai_stand, 0, NULL,
   63         ai_stand, 0, NULL,
   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 };
   73 mmove_t infantry_move_stand = {FRAME_stand50, FRAME_stand71, infantry_frames_stand, NULL};
   74 
   75 void infantry_stand (edict_t *self)
   76 {
   77         self->monsterinfo.currentmove = &infantry_move_stand;
   78 }
   79 
   80 
   81 mframe_t infantry_frames_fidget [] =
   82 {
   83         ai_stand, 1,  NULL,
   84         ai_stand, 0,  NULL,
   85         ai_stand, 1,  NULL,
   86         ai_stand, 3,  NULL,
   87         ai_stand, 6,  NULL,
   88         ai_stand, 3,  NULL,
   89         ai_stand, 0,  NULL,
   90         ai_stand, 0,  NULL,
   91         ai_stand, 0,  NULL,
   92         ai_stand, 0,  NULL,
   93         ai_stand, 1,  NULL,
   94         ai_stand, 0,  NULL,
   95         ai_stand, 0,  NULL,
   96         ai_stand, 0,  NULL,
   97         ai_stand, 0,  NULL,
   98         ai_stand, 1,  NULL,
   99         ai_stand, 0,  NULL,
  100         ai_stand, -1, NULL,
  101         ai_stand, 0,  NULL,
  102         ai_stand, 0,  NULL,
  103         ai_stand, 1,  NULL,
  104         ai_stand, 0,  NULL,
  105         ai_stand, -2, NULL,
  106         ai_stand, 1,  NULL,
  107         ai_stand, 1,  NULL,
  108         ai_stand, 1,  NULL,
  109         ai_stand, -1, NULL,
  110         ai_stand, 0,  NULL,
  111         ai_stand, 0,  NULL,
  112         ai_stand, -1, 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, -1, NULL,
  119         ai_stand, 0,  NULL,
  120         ai_stand, 0,  NULL,
  121         ai_stand, 1,  NULL,
  122         ai_stand, 0,  NULL,
  123         ai_stand, 0,  NULL,
  124         ai_stand, -1, NULL,
  125         ai_stand, -1, NULL,
  126         ai_stand, 0,  NULL,
  127         ai_stand, -3, NULL,
  128         ai_stand, -2, NULL,
  129         ai_stand, -3, NULL,
  130         ai_stand, -3, NULL,
  131         ai_stand, -2, NULL
  132 };
  133 mmove_t infantry_move_fidget = {FRAME_stand01, FRAME_stand49, infantry_frames_fidget, infantry_stand};
  134 
  135 void infantry_fidget (edict_t *self)
  136 {
  137         self->monsterinfo.currentmove = &infantry_move_fidget;
  138         gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
  139 }
  140 
  141 mframe_t infantry_frames_walk [] =
  142 {
  143         ai_walk, 5,  NULL,
  144         ai_walk, 4,  NULL,
  145         ai_walk, 4,  NULL,
  146         ai_walk, 5,  NULL,
  147         ai_walk, 4,  NULL,
  148         ai_walk, 5,  NULL,
  149         ai_walk, 6,  NULL,
  150         ai_walk, 4,  NULL,
  151         ai_walk, 4,  NULL,
  152         ai_walk, 4,  NULL,
  153         ai_walk, 4,  NULL,
  154         ai_walk, 5,  NULL
  155 };
  156 mmove_t infantry_move_walk = {FRAME_walk03, FRAME_walk14, infantry_frames_walk, NULL};
  157 
  158 void infantry_walk (edict_t *self)
  159 {
  160         self->monsterinfo.currentmove = &infantry_move_walk;
  161 }
  162 
  163 mframe_t infantry_frames_run [] =
  164 {
  165         ai_run, 10, NULL,
  166         ai_run, 20, NULL,
  167         ai_run, 5,  NULL,
  168         ai_run, 7,  NULL,
  169         ai_run, 30, NULL,
  170         ai_run, 35, NULL,
  171         ai_run, 2,  NULL,
  172         ai_run, 6,  NULL
  173 };
  174 mmove_t infantry_move_run = {FRAME_run01, FRAME_run08, infantry_frames_run, NULL};
  175 
  176 void infantry_run (edict_t *self)
  177 {
  178         if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  179                 self->monsterinfo.currentmove = &infantry_move_stand;
  180         else
  181                 self->monsterinfo.currentmove = &infantry_move_run;
  182 }
  183 
  184 
  185 mframe_t infantry_frames_pain1 [] =
  186 {
  187         ai_move, -3, NULL,
  188         ai_move, -2, NULL,
  189         ai_move, -1, NULL,
  190         ai_move, -2, NULL,
  191         ai_move, -1, NULL,
  192         ai_move, 1,  NULL,
  193         ai_move, -1, NULL,
  194         ai_move, 1,  NULL,
  195         ai_move, 6,  NULL,
  196         ai_move, 2,  NULL
  197 };
  198 mmove_t infantry_move_pain1 = {FRAME_pain101, FRAME_pain110, infantry_frames_pain1, infantry_run};
  199 
  200 mframe_t infantry_frames_pain2 [] =
  201 {
  202         ai_move, -3, NULL,
  203         ai_move, -3, NULL,
  204         ai_move, 0,  NULL,
  205         ai_move, -1, NULL,
  206         ai_move, -2, NULL,
  207         ai_move, 0,  NULL,
  208         ai_move, 0,  NULL,
  209         ai_move, 2,  NULL,
  210         ai_move, 5,  NULL,
  211         ai_move, 2,  NULL
  212 };
  213 mmove_t infantry_move_pain2 = {FRAME_pain201, FRAME_pain210, infantry_frames_pain2, infantry_run};
  214 
  215 void infantry_pain (edict_t *self, edict_t *other, float kick, int damage)
  216 {
  217         int             n;
  218 
  219         if (self->health < (self->max_health / 2))
  220                 self->s.skinnum = 1;
  221 
  222         if (level.time < self->pain_debounce_time)
  223                 return;
  224 
  225         self->pain_debounce_time = level.time + 3;
  226         
  227         if (skill->value == 3)
  228                 return;         // no pain anims in nightmare
  229 
  230         n = rand() % 2;
  231         if (n == 0)
  232         {
  233                 self->monsterinfo.currentmove = &infantry_move_pain1;
  234                 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  235         }
  236         else
  237         {
  238                 self->monsterinfo.currentmove = &infantry_move_pain2;
  239                 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  240         }
  241 }
  242 
  243 
  244 vec3_t  aimangles[] =
  245 {
  246         0.0, 5.0, 0.0,
  247         10.0, 15.0, 0.0,
  248         20.0, 25.0, 0.0,
  249         25.0, 35.0, 0.0,
  250         30.0, 40.0, 0.0,
  251         30.0, 45.0, 0.0,
  252         25.0, 50.0, 0.0,
  253         20.0, 40.0, 0.0,
  254         15.0, 35.0, 0.0,
  255         40.0, 35.0, 0.0,
  256         70.0, 35.0, 0.0,
  257         90.0, 35.0, 0.0
  258 };
  259 
  260 void InfantryMachineGun (edict_t *self)
  261 {
  262         vec3_t  start, target;
  263         vec3_t  forward, right;
  264         vec3_t  vec;
  265         int             flash_number;
  266 
  267         if (self->s.frame == FRAME_attak111)
  268         {
  269                 flash_number = MZ2_INFANTRY_MACHINEGUN_1;
  270                 AngleVectors (self->s.angles, forward, right, NULL);
  271                 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  272 
  273                 if (self->enemy)
  274                 {
  275                         VectorMA (self->enemy->s.origin, -0.2, self->enemy->velocity, target);
  276                         target[2] += self->enemy->viewheight;
  277                         VectorSubtract (target, start, forward);
  278                         VectorNormalize (forward);
  279                 }
  280                 else
  281                 {
  282                         AngleVectors (self->s.angles, forward, right, NULL);
  283                 }
  284         }
  285         else
  286         {
  287                 flash_number = MZ2_INFANTRY_MACHINEGUN_2 + (self->s.frame - FRAME_death211);
  288 
  289                 AngleVectors (self->s.angles, forward, right, NULL);
  290                 G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  291 
  292                 VectorSubtract (self->s.angles, aimangles[flash_number-MZ2_INFANTRY_MACHINEGUN_2], vec);
  293                 AngleVectors (vec, forward, NULL, NULL);
  294         }
  295 
  296         monster_fire_bullet (self, start, forward, 3, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
  297 }
  298 
  299 void infantry_sight (edict_t *self, edict_t *other)
  300 {
  301         gi.sound (self, CHAN_BODY, sound_sight, 1, ATTN_NORM, 0);
  302 }
  303 
  304 void infantry_dead (edict_t *self)
  305 {
  306         VectorSet (self->mins, -16, -16, -24);
  307         VectorSet (self->maxs, 16, 16, -8);
  308         self->movetype = MOVETYPE_TOSS;
  309         self->svflags |= SVF_DEADMONSTER;
  310         gi.linkentity (self);
  311 
  312         M_FlyCheck (self);
  313 }
  314 
  315 mframe_t infantry_frames_death1 [] =
  316 {
  317         ai_move, -4, NULL,
  318         ai_move, 0,  NULL,
  319         ai_move, 0,  NULL,
  320         ai_move, -1, NULL,
  321         ai_move, -4, NULL,
  322         ai_move, 0,  NULL,
  323         ai_move, 0,  NULL,
  324         ai_move, 0,  NULL,
  325         ai_move, -1, NULL,
  326         ai_move, 3,  NULL,
  327         ai_move, 1,  NULL,
  328         ai_move, 1,  NULL,
  329         ai_move, -2, NULL,
  330         ai_move, 2,  NULL,
  331         ai_move, 2,  NULL,
  332         ai_move, 9,  NULL,
  333         ai_move, 9,  NULL,
  334         ai_move, 5,  NULL,
  335         ai_move, -3, NULL,
  336         ai_move, -3, NULL
  337 };
  338 mmove_t infantry_move_death1 = {FRAME_death101, FRAME_death120, infantry_frames_death1, infantry_dead};
  339 
  340 // Off with his head
  341 mframe_t infantry_frames_death2 [] =
  342 {
  343         ai_move, 0,   NULL,
  344         ai_move, 1,   NULL,
  345         ai_move, 5,   NULL,
  346         ai_move, -1,  NULL,
  347         ai_move, 0,   NULL,
  348         ai_move, 1,   NULL,
  349         ai_move, 1,   NULL,
  350         ai_move, 4,   NULL,
  351         ai_move, 3,   NULL,
  352         ai_move, 0,   NULL,
  353         ai_move, -2,  InfantryMachineGun,
  354         ai_move, -2,  InfantryMachineGun,
  355         ai_move, -3,  InfantryMachineGun,
  356         ai_move, -1,  InfantryMachineGun,
  357         ai_move, -2,  InfantryMachineGun,
  358         ai_move, 0,   InfantryMachineGun,
  359         ai_move, 2,   InfantryMachineGun,
  360         ai_move, 2,   InfantryMachineGun,
  361         ai_move, 3,   InfantryMachineGun,
  362         ai_move, -10, InfantryMachineGun,
  363         ai_move, -7,  InfantryMachineGun,
  364         ai_move, -8,  InfantryMachineGun,
  365         ai_move, -6,  NULL,
  366         ai_move, 4,   NULL,
  367         ai_move, 0,   NULL
  368 };
  369 mmove_t infantry_move_death2 = {FRAME_death201, FRAME_death225, infantry_frames_death2, infantry_dead};
  370 
  371 mframe_t infantry_frames_death3 [] =
  372 {
  373         ai_move, 0,   NULL,
  374         ai_move, 0,   NULL,
  375         ai_move, 0,   NULL,
  376         ai_move, -6,  NULL,
  377         ai_move, -11, NULL,
  378         ai_move, -3,  NULL,
  379         ai_move, -11, NULL,
  380         ai_move, 0,   NULL,
  381         ai_move, 0,   NULL
  382 };
  383 mmove_t infantry_move_death3 = {FRAME_death301, FRAME_death309, infantry_frames_death3, infantry_dead};
  384 
  385 
  386 void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  387 {
  388         int             n;
  389 
  390 // check for gib
  391         if (self->health <= self->gib_health)
  392         {
  393                 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  394                 for (n= 0; n < 2; n++)
  395                         ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  396                 for (n= 0; n < 4; n++)
  397                         ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  398                 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  399                 self->deadflag = DEAD_DEAD;
  400                 return;
  401         }
  402 
  403         if (self->deadflag == DEAD_DEAD)
  404                 return;
  405 
  406 // regular death
  407         self->deadflag = DEAD_DEAD;
  408         self->takedamage = DAMAGE_YES;
  409 
  410         n = rand() % 3;
  411         if (n == 0)
  412         {
  413                 self->monsterinfo.currentmove = &infantry_move_death1;
  414                 gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
  415         }
  416         else if (n == 1)
  417         {
  418                 self->monsterinfo.currentmove = &infantry_move_death2;
  419                 gi.sound (self, CHAN_VOICE, sound_die1, 1, ATTN_NORM, 0);
  420         }
  421         else
  422         {
  423                 self->monsterinfo.currentmove = &infantry_move_death3;
  424                 gi.sound (self, CHAN_VOICE, sound_die2, 1, ATTN_NORM, 0);
  425         }
  426 }
  427 
  428 
  429 void infantry_duck_down (edict_t *self)
  430 {
  431         if (self->monsterinfo.aiflags & AI_DUCKED)
  432                 return;
  433         self->monsterinfo.aiflags |= AI_DUCKED;
  434         self->maxs[2] -= 32;
  435         self->takedamage = DAMAGE_YES;
  436         self->monsterinfo.pausetime = level.time + 1;
  437         gi.linkentity (self);
  438 }
  439 
  440 void infantry_duck_hold (edict_t *self)
  441 {
  442         if (level.time >= self->monsterinfo.pausetime)
  443                 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  444         else
  445                 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
  446 }
  447 
  448 void infantry_duck_up (edict_t *self)
  449 {
  450         self->monsterinfo.aiflags &= ~AI_DUCKED;
  451         self->maxs[2] += 32;
  452         self->takedamage = DAMAGE_AIM;
  453         gi.linkentity (self);
  454 }
  455 
  456 mframe_t infantry_frames_duck [] =
  457 {
  458         ai_move, -2, infantry_duck_down,
  459         ai_move, -5, infantry_duck_hold,
  460         ai_move, 3,  NULL,
  461         ai_move, 4,  infantry_duck_up,
  462         ai_move, 0,  NULL
  463 };
  464 mmove_t infantry_move_duck = {FRAME_duck01, FRAME_duck05, infantry_frames_duck, infantry_run};
  465 
  466 void infantry_dodge (edict_t *self, edict_t *attacker, float eta)
  467 {
  468         if (random() > 0.25)
  469                 return;
  470 
  471         if (!self->enemy)
  472                 self->enemy = attacker;
  473 
  474         self->monsterinfo.currentmove = &infantry_move_duck;
  475 }
  476 
  477 
  478 void infantry_cock_gun (edict_t *self)
  479 {
  480         int             n;
  481 
  482         gi.sound (self, CHAN_WEAPON, sound_weapon_cock, 1, ATTN_NORM, 0);
  483         n = (rand() & 15) + 3 + 7;
  484         self->monsterinfo.pausetime = level.time + n * FRAMETIME;
  485 }
  486 
  487 void infantry_fire (edict_t *self)
  488 {
  489         InfantryMachineGun (self);
  490 
  491         if (level.time >= self->monsterinfo.pausetime)
  492                 self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
  493         else
  494                 self->monsterinfo.aiflags |= AI_HOLD_FRAME;
  495 }
  496 
  497 mframe_t infantry_frames_attack1 [] =
  498 {
  499         ai_charge, 4,  NULL,
  500         ai_charge, -1, NULL,
  501         ai_charge, -1, NULL,
  502         ai_charge, 0,  infantry_cock_gun,
  503         ai_charge, -1, NULL,
  504         ai_charge, 1,  NULL,
  505         ai_charge, 1,  NULL,
  506         ai_charge, 2,  NULL,
  507         ai_charge, -2, NULL,
  508         ai_charge, -3, NULL,
  509         ai_charge, 1,  infantry_fire,
  510         ai_charge, 5,  NULL,
  511         ai_charge, -1, NULL,
  512         ai_charge, -2, NULL,
  513         ai_charge, -3, NULL
  514 };
  515 mmove_t infantry_move_attack1 = {FRAME_attak101, FRAME_attak115, infantry_frames_attack1, infantry_run};
  516 
  517 
  518 void infantry_swing (edict_t *self)
  519 {
  520         gi.sound (self, CHAN_WEAPON, sound_punch_swing, 1, ATTN_NORM, 0);
  521 }
  522 
  523 void infantry_smack (edict_t *self)
  524 {
  525         vec3_t  aim;
  526 
  527         VectorSet (aim, MELEE_DISTANCE, 0, 0);
  528         if (fire_hit (self, aim, (5 + (rand() % 5)), 50))
  529                 gi.sound (self, CHAN_WEAPON, sound_punch_hit, 1, ATTN_NORM, 0);
  530 }
  531 
  532 mframe_t infantry_frames_attack2 [] =
  533 {
  534         ai_charge, 3, NULL,
  535         ai_charge, 6, NULL,
  536         ai_charge, 0, infantry_swing,
  537         ai_charge, 8, NULL,
  538         ai_charge, 5, NULL,
  539         ai_charge, 8, infantry_smack,
  540         ai_charge, 6, NULL,
  541         ai_charge, 3, NULL,
  542 };
  543 mmove_t infantry_move_attack2 = {FRAME_attak201, FRAME_attak208, infantry_frames_attack2, infantry_run};
  544 
  545 void infantry_attack(edict_t *self)
  546 {
  547         if (range (self, self->enemy) == RANGE_MELEE)
  548                 self->monsterinfo.currentmove = &infantry_move_attack2;
  549         else
  550                 self->monsterinfo.currentmove = &infantry_move_attack1;
  551 }
  552 
  553 
  554 /*QUAKED monster_infantry (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  555 */
  556 void SP_monster_infantry (edict_t *self)
  557 {
  558         if (deathmatch->value)
  559         {
  560                 G_FreeEdict (self);
  561                 return;
  562         }
  563 
  564         sound_pain1 = gi.soundindex ("infantry/infpain1.wav");
  565         sound_pain2 = gi.soundindex ("infantry/infpain2.wav");
  566         sound_die1 = gi.soundindex ("infantry/infdeth1.wav");
  567         sound_die2 = gi.soundindex ("infantry/infdeth2.wav");
  568 
  569         sound_gunshot = gi.soundindex ("infantry/infatck1.wav");
  570         sound_weapon_cock = gi.soundindex ("infantry/infatck3.wav");
  571         sound_punch_swing = gi.soundindex ("infantry/infatck2.wav");
  572         sound_punch_hit = gi.soundindex ("infantry/melee2.wav");
  573         
  574         sound_sight = gi.soundindex ("infantry/infsght1.wav");
  575         sound_search = gi.soundindex ("infantry/infsrch1.wav");
  576         sound_idle = gi.soundindex ("infantry/infidle1.wav");
  577         
  578 
  579         self->movetype = MOVETYPE_STEP;
  580         self->solid = SOLID_BBOX;
  581         self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
  582         VectorSet (self->mins, -16, -16, -24);
  583         VectorSet (self->maxs, 16, 16, 32);
  584 
  585         self->health = 100;
  586         self->gib_health = -40;
  587         self->mass = 200;
  588 
  589         self->pain = infantry_pain;
  590         self->die = infantry_die;
  591 
  592         self->monsterinfo.stand = infantry_stand;
  593         self->monsterinfo.walk = infantry_walk;
  594         self->monsterinfo.run = infantry_run;
  595         self->monsterinfo.dodge = infantry_dodge;
  596         self->monsterinfo.attack = infantry_attack;
  597         self->monsterinfo.melee = NULL;
  598         self->monsterinfo.sight = infantry_sight;
  599         self->monsterinfo.idle = infantry_fidget;
  600 
  601         gi.linkentity (self);
  602 
  603         self->monsterinfo.currentmove = &infantry_move_stand;
  604         self->monsterinfo.scale = MODEL_SCALE;
  605 
  606         walkmonster_start (self);
  607 }
  608