File: game\m_mutant.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 mutant
   24 
   25 ==============================================================================
   26 */
   27 
   28 #include "g_local.h"
   29 #include "m_mutant.h"
   30 
   31 
   32 static int      sound_swing;
   33 static int      sound_hit;
   34 static int      sound_hit2;
   35 static int      sound_death;
   36 static int      sound_idle;
   37 static int      sound_pain1;
   38 static int      sound_pain2;
   39 static int      sound_sight;
   40 static int      sound_search;
   41 static int      sound_step1;
   42 static int      sound_step2;
   43 static int      sound_step3;
   44 static int      sound_thud;
   45 
   46 //
   47 // SOUNDS
   48 //
   49 
   50 void mutant_step (edict_t *self)
   51 {
   52         int             n;
   53         n = (rand() + 1) % 3;
   54         if (n == 0)
   55                 gi.sound (self, CHAN_VOICE, sound_step1, 1, ATTN_NORM, 0);              
   56         else if (n == 1)
   57                 gi.sound (self, CHAN_VOICE, sound_step2, 1, ATTN_NORM, 0);
   58         else
   59                 gi.sound (self, CHAN_VOICE, sound_step3, 1, ATTN_NORM, 0);
   60 }
   61 
   62 void mutant_sight (edict_t *self, edict_t *other)
   63 {
   64         gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
   65 }
   66 
   67 void mutant_search (edict_t *self)
   68 {
   69         gi.sound (self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
   70 }
   71 
   72 void mutant_swing (edict_t *self)
   73 {
   74         gi.sound (self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0);
   75 }
   76 
   77 
   78 //
   79 // STAND
   80 //
   81 
   82 mframe_t mutant_frames_stand [] =
   83 {
   84         ai_stand, 0, NULL,
   85         ai_stand, 0, NULL,
   86         ai_stand, 0, NULL,
   87         ai_stand, 0, NULL,
   88         ai_stand, 0, NULL,
   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,              // 10
   94 
   95         ai_stand, 0, NULL,
   96         ai_stand, 0, NULL,
   97         ai_stand, 0, NULL,
   98         ai_stand, 0, NULL,
   99         ai_stand, 0, NULL,
  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,              // 20
  105 
  106         ai_stand, 0, NULL,
  107         ai_stand, 0, NULL,
  108         ai_stand, 0, NULL,
  109         ai_stand, 0, NULL,
  110         ai_stand, 0, NULL,
  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,              // 30
  116 
  117         ai_stand, 0, NULL,
  118         ai_stand, 0, NULL,
  119         ai_stand, 0, NULL,
  120         ai_stand, 0, NULL,
  121         ai_stand, 0, NULL,
  122         ai_stand, 0, NULL,
  123         ai_stand, 0, NULL,
  124         ai_stand, 0, NULL,
  125         ai_stand, 0, NULL,
  126         ai_stand, 0, NULL,              // 40
  127 
  128         ai_stand, 0, NULL,
  129         ai_stand, 0, NULL,
  130         ai_stand, 0, NULL,
  131         ai_stand, 0, NULL,
  132         ai_stand, 0, NULL,
  133         ai_stand, 0, NULL,
  134         ai_stand, 0, NULL,
  135         ai_stand, 0, NULL,
  136         ai_stand, 0, NULL,
  137         ai_stand, 0, NULL,              // 50
  138 
  139         ai_stand, 0, NULL
  140 };
  141 mmove_t mutant_move_stand = {FRAME_stand101, FRAME_stand151, mutant_frames_stand, NULL};
  142 
  143 void mutant_stand (edict_t *self)
  144 {
  145         self->monsterinfo.currentmove = &mutant_move_stand;
  146 }
  147 
  148 
  149 //
  150 // IDLE
  151 //
  152 
  153 void mutant_idle_loop (edict_t *self)
  154 {
  155         if (random() < 0.75)
  156                 self->monsterinfo.nextframe = FRAME_stand155;
  157 }
  158 
  159 mframe_t mutant_frames_idle [] =
  160 {
  161         ai_stand, 0, NULL,
  162         ai_stand, 0, NULL,
  163         ai_stand, 0, NULL,
  164         ai_stand, 0, NULL,                                      // scratch loop start
  165         ai_stand, 0, NULL,
  166         ai_stand, 0, NULL,
  167         ai_stand, 0, mutant_idle_loop,          // scratch loop end
  168         ai_stand, 0, NULL,
  169         ai_stand, 0, NULL,
  170         ai_stand, 0, NULL,
  171         ai_stand, 0, NULL,
  172         ai_stand, 0, NULL,
  173         ai_stand, 0, NULL
  174 };
  175 mmove_t mutant_move_idle = {FRAME_stand152, FRAME_stand164, mutant_frames_idle, mutant_stand};
  176 
  177 void mutant_idle (edict_t *self)
  178 {
  179         self->monsterinfo.currentmove = &mutant_move_idle;
  180         gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
  181 }
  182 
  183 
  184 //
  185 // WALK
  186 //
  187 
  188 void mutant_walk (edict_t *self);
  189 
  190 mframe_t mutant_frames_walk [] =
  191 {
  192         ai_walk,        3,              NULL,
  193         ai_walk,        1,              NULL,
  194         ai_walk,        5,              NULL,
  195         ai_walk,        10,             NULL,
  196         ai_walk,        13,             NULL,
  197         ai_walk,        10,             NULL,
  198         ai_walk,        0,              NULL,
  199         ai_walk,        5,              NULL,
  200         ai_walk,        6,              NULL,
  201         ai_walk,        16,             NULL,
  202         ai_walk,        15,             NULL,
  203         ai_walk,        6,              NULL
  204 };
  205 mmove_t mutant_move_walk = {FRAME_walk05, FRAME_walk16, mutant_frames_walk, NULL};
  206 
  207 void mutant_walk_loop (edict_t *self)
  208 {
  209         self->monsterinfo.currentmove = &mutant_move_walk;
  210 }
  211 
  212 mframe_t mutant_frames_start_walk [] =
  213 {
  214         ai_walk,        5,              NULL,
  215         ai_walk,        5,              NULL,
  216         ai_walk,        -2,             NULL,
  217         ai_walk,        1,              NULL
  218 };
  219 mmove_t mutant_move_start_walk = {FRAME_walk01, FRAME_walk04, mutant_frames_start_walk, mutant_walk_loop};
  220 
  221 void mutant_walk (edict_t *self)
  222 {
  223         self->monsterinfo.currentmove = &mutant_move_start_walk;
  224 }
  225 
  226 
  227 //
  228 // RUN
  229 //
  230 
  231 mframe_t mutant_frames_run [] =
  232 {
  233         ai_run, 40,             NULL,
  234         ai_run, 40,             mutant_step,
  235         ai_run, 24,             NULL,
  236         ai_run, 5,              mutant_step,
  237         ai_run, 17,             NULL,
  238         ai_run, 10,             NULL
  239 };
  240 mmove_t mutant_move_run = {FRAME_run03, FRAME_run08, mutant_frames_run, NULL};
  241 
  242 void mutant_run (edict_t *self)
  243 {
  244         if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  245                 self->monsterinfo.currentmove = &mutant_move_stand;
  246         else
  247                 self->monsterinfo.currentmove = &mutant_move_run;
  248 }
  249 
  250 
  251 //
  252 // MELEE
  253 //
  254 
  255 void mutant_hit_left (edict_t *self)
  256 {
  257         vec3_t  aim;
  258 
  259         VectorSet (aim, MELEE_DISTANCE, self->mins[0], 8);
  260         if (fire_hit (self, aim, (10 + (rand() %5)), 100))
  261                 gi.sound (self, CHAN_WEAPON, sound_hit, 1, ATTN_NORM, 0);
  262         else
  263                 gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
  264 }
  265 
  266 void mutant_hit_right (edict_t *self)
  267 {
  268         vec3_t  aim;
  269 
  270         VectorSet (aim, MELEE_DISTANCE, self->maxs[0], 8);
  271         if (fire_hit (self, aim, (10 + (rand() %5)), 100))
  272                 gi.sound (self, CHAN_WEAPON, sound_hit2, 1, ATTN_NORM, 0);
  273         else
  274                 gi.sound (self, CHAN_WEAPON, sound_swing, 1, ATTN_NORM, 0);
  275 }
  276 
  277 void mutant_check_refire (edict_t *self)
  278 {
  279         if (!self->enemy || !self->enemy->inuse || self->enemy->health <= 0)
  280                 return;
  281 
  282         if ( ((skill->value == 3) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE) )
  283                 self->monsterinfo.nextframe = FRAME_attack09;
  284 }
  285 
  286 mframe_t mutant_frames_attack [] =
  287 {
  288         ai_charge,      0,      NULL,
  289         ai_charge,      0,      NULL,
  290         ai_charge,      0,      mutant_hit_left,
  291         ai_charge,      0,      NULL,
  292         ai_charge,      0,      NULL,
  293         ai_charge,      0,      mutant_hit_right,
  294         ai_charge,      0,      mutant_check_refire
  295 };
  296 mmove_t mutant_move_attack = {FRAME_attack09, FRAME_attack15, mutant_frames_attack, mutant_run};
  297 
  298 void mutant_melee (edict_t *self)
  299 {
  300         self->monsterinfo.currentmove = &mutant_move_attack;
  301 }
  302 
  303 
  304 //
  305 // ATTACK
  306 //
  307 
  308 void mutant_jump_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  309 {
  310         if (self->health <= 0)
  311         {
  312                 self->touch = NULL;
  313                 return;
  314         }
  315 
  316         if (other->takedamage)
  317         {
  318                 if (VectorLength(self->velocity) > 400)
  319                 {
  320                         vec3_t  point;
  321                         vec3_t  normal;
  322                         int             damage;
  323 
  324                         VectorCopy (self->velocity, normal);
  325                         VectorNormalize(normal);
  326                         VectorMA (self->s.origin, self->maxs[0], normal, point);
  327                         damage = 40 + 10 * random();
  328                         T_Damage (other, self, self, self->velocity, point, normal, damage, damage, 0, MOD_UNKNOWN);
  329                 }
  330         }
  331 
  332         if (!M_CheckBottom (self))
  333         {
  334                 if (self->groundentity)
  335                 {
  336                         self->monsterinfo.nextframe = FRAME_attack02;
  337                         self->touch = NULL;
  338                 }
  339                 return;
  340         }
  341 
  342         self->touch = NULL;
  343 }
  344 
  345 void mutant_jump_takeoff (edict_t *self)
  346 {
  347         vec3_t  forward;
  348 
  349         gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  350         AngleVectors (self->s.angles, forward, NULL, NULL);
  351         self->s.origin[2] += 1;
  352         VectorScale (forward, 600, self->velocity);
  353         self->velocity[2] = 250;
  354         self->groundentity = NULL;
  355         self->monsterinfo.aiflags |= AI_DUCKED;
  356         self->monsterinfo.attack_finished = level.time + 3;
  357         self->touch = mutant_jump_touch;
  358 }
  359 
  360 void mutant_check_landing (edict_t *self)
  361 {
  362         if (self->groundentity)
  363         {
  364                 gi.sound (self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
  365                 self->monsterinfo.attack_finished = 0;
  366                 self->monsterinfo.aiflags &= ~AI_DUCKED;
  367                 return;
  368         }
  369 
  370         if (level.time > self->monsterinfo.attack_finished)
  371                 self->monsterinfo.nextframe = FRAME_attack02;
  372         else
  373                 self->monsterinfo.nextframe = FRAME_attack05;
  374 }
  375 
  376 mframe_t mutant_frames_jump [] =
  377 {
  378         ai_charge,       0,     NULL,
  379         ai_charge,      17,     NULL,
  380         ai_charge,      15,     mutant_jump_takeoff,
  381         ai_charge,      15,     NULL,
  382         ai_charge,      15,     mutant_check_landing,
  383         ai_charge,       0,     NULL,
  384         ai_charge,       3,     NULL,
  385         ai_charge,       0,     NULL
  386 };
  387 mmove_t mutant_move_jump = {FRAME_attack01, FRAME_attack08, mutant_frames_jump, mutant_run};
  388 
  389 void mutant_jump (edict_t *self)
  390 {
  391         self->monsterinfo.currentmove = &mutant_move_jump;
  392 }
  393 
  394 
  395 //
  396 // CHECKATTACK
  397 //
  398 
  399 qboolean mutant_check_melee (edict_t *self)
  400 {
  401         if (range (self, self->enemy) == RANGE_MELEE)
  402                 return true;
  403         return false;
  404 }
  405 
  406 qboolean mutant_check_jump (edict_t *self)
  407 {
  408         vec3_t  v;
  409         float   distance;
  410 
  411         if (self->absmin[2] > (self->enemy->absmin[2] + 0.75 * self->enemy->size[2]))
  412                 return false;
  413 
  414         if (self->absmax[2] < (self->enemy->absmin[2] + 0.25 * self->enemy->size[2]))
  415                 return false;
  416 
  417         v[0] = self->s.origin[0] - self->enemy->s.origin[0];
  418         v[1] = self->s.origin[1] - self->enemy->s.origin[1];
  419         v[2] = 0;
  420         distance = VectorLength(v);
  421 
  422         if (distance < 100)
  423                 return false;
  424         if (distance > 100)
  425         {
  426                 if (random() < 0.9)
  427                         return false;
  428         }
  429 
  430         return true;
  431 }
  432 
  433 qboolean mutant_checkattack (edict_t *self)
  434 {
  435         if (!self->enemy || self->enemy->health <= 0)
  436                 return false;
  437 
  438         if (mutant_check_melee(self))
  439         {
  440                 self->monsterinfo.attack_state = AS_MELEE;
  441                 return true;
  442         }
  443 
  444         if (mutant_check_jump(self))
  445         {
  446                 self->monsterinfo.attack_state = AS_MISSILE;
  447                 // FIXME play a jump sound here
  448                 return true;
  449         }
  450 
  451         return false;
  452 }
  453 
  454 
  455 //
  456 // PAIN
  457 //
  458 
  459 mframe_t mutant_frames_pain1 [] =
  460 {
  461         ai_move,        4,      NULL,
  462         ai_move,        -3,     NULL,
  463         ai_move,        -8,     NULL,
  464         ai_move,        2,      NULL,
  465         ai_move,        5,      NULL
  466 };
  467 mmove_t mutant_move_pain1 = {FRAME_pain101, FRAME_pain105, mutant_frames_pain1, mutant_run};
  468 
  469 mframe_t mutant_frames_pain2 [] =
  470 {
  471         ai_move,        -24,NULL,
  472         ai_move,        11,     NULL,
  473         ai_move,        5,      NULL,
  474         ai_move,        -2,     NULL,
  475         ai_move,        6,      NULL,
  476         ai_move,        4,      NULL
  477 };
  478 mmove_t mutant_move_pain2 = {FRAME_pain201, FRAME_pain206, mutant_frames_pain2, mutant_run};
  479 
  480 mframe_t mutant_frames_pain3 [] =
  481 {
  482         ai_move,        -22,NULL,
  483         ai_move,        3,      NULL,
  484         ai_move,        3,      NULL,
  485         ai_move,        2,      NULL,
  486         ai_move,        1,      NULL,
  487         ai_move,        1,      NULL,
  488         ai_move,        6,      NULL,
  489         ai_move,        3,      NULL,
  490         ai_move,        2,      NULL,
  491         ai_move,        0,      NULL,
  492         ai_move,        1,      NULL
  493 };
  494 mmove_t mutant_move_pain3 = {FRAME_pain301, FRAME_pain311, mutant_frames_pain3, mutant_run};
  495 
  496 void mutant_pain (edict_t *self, edict_t *other, float kick, int damage)
  497 {
  498         float   r;
  499 
  500         if (self->health < (self->max_health / 2))
  501                 self->s.skinnum = 1;
  502 
  503         if (level.time < self->pain_debounce_time)
  504                 return;
  505 
  506         self->pain_debounce_time = level.time + 3;
  507 
  508         if (skill->value == 3)
  509                 return;         // no pain anims in nightmare
  510 
  511         r = random();
  512         if (r < 0.33)
  513         {
  514                 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  515                 self->monsterinfo.currentmove = &mutant_move_pain1;
  516         }
  517         else if (r < 0.66)
  518         {
  519                 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  520                 self->monsterinfo.currentmove = &mutant_move_pain2;
  521         }
  522         else
  523         {
  524                 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  525                 self->monsterinfo.currentmove = &mutant_move_pain3;
  526         }
  527 }
  528 
  529 
  530 //
  531 // DEATH
  532 //
  533 
  534 void mutant_dead (edict_t *self)
  535 {
  536         VectorSet (self->mins, -16, -16, -24);
  537         VectorSet (self->maxs, 16, 16, -8);
  538         self->movetype = MOVETYPE_TOSS;
  539         self->svflags |= SVF_DEADMONSTER;
  540         gi.linkentity (self);
  541 
  542         M_FlyCheck (self);
  543 }
  544 
  545 mframe_t mutant_frames_death1 [] =
  546 {
  547         ai_move,        0,      NULL,
  548         ai_move,        0,      NULL,
  549         ai_move,        0,      NULL,
  550         ai_move,        0,      NULL,
  551         ai_move,        0,      NULL,
  552         ai_move,        0,      NULL,
  553         ai_move,        0,      NULL,
  554         ai_move,        0,      NULL,
  555         ai_move,        0,      NULL
  556 };
  557 mmove_t mutant_move_death1 = {FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead};
  558 
  559 mframe_t mutant_frames_death2 [] =
  560 {
  561         ai_move,        0,      NULL,
  562         ai_move,        0,      NULL,
  563         ai_move,        0,      NULL,
  564         ai_move,        0,      NULL,
  565         ai_move,        0,      NULL,
  566         ai_move,        0,      NULL,
  567         ai_move,        0,      NULL,
  568         ai_move,        0,      NULL,
  569         ai_move,        0,      NULL,
  570         ai_move,        0,      NULL
  571 };
  572 mmove_t mutant_move_death2 = {FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead};
  573 
  574 void mutant_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  575 {
  576         int             n;
  577 
  578         if (self->health <= self->gib_health)
  579         {
  580                 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  581                 for (n= 0; n < 2; n++)
  582                         ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  583                 for (n= 0; n < 4; n++)
  584                         ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  585                 ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
  586                 self->deadflag = DEAD_DEAD;
  587                 return;
  588         }
  589 
  590         if (self->deadflag == DEAD_DEAD)
  591                 return;
  592 
  593         gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
  594         self->deadflag = DEAD_DEAD;
  595         self->takedamage = DAMAGE_YES;
  596         self->s.skinnum = 1;
  597 
  598         if (random() < 0.5)
  599                 self->monsterinfo.currentmove = &mutant_move_death1;
  600         else
  601                 self->monsterinfo.currentmove = &mutant_move_death2;
  602 }
  603 
  604 
  605 //
  606 // SPAWN
  607 //
  608 
  609 /*QUAKED monster_mutant (1 .5 0) (-32 -32 -24) (32 32 32) Ambush Trigger_Spawn Sight
  610 */
  611 void SP_monster_mutant (edict_t *self)
  612 {
  613         if (deathmatch->value)
  614         {
  615                 G_FreeEdict (self);
  616                 return;
  617         }
  618 
  619         sound_swing = gi.soundindex ("mutant/mutatck1.wav");
  620         sound_hit = gi.soundindex ("mutant/mutatck2.wav");
  621         sound_hit2 = gi.soundindex ("mutant/mutatck3.wav");
  622         sound_death = gi.soundindex ("mutant/mutdeth1.wav");
  623         sound_idle = gi.soundindex ("mutant/mutidle1.wav");
  624         sound_pain1 = gi.soundindex ("mutant/mutpain1.wav");
  625         sound_pain2 = gi.soundindex ("mutant/mutpain2.wav");
  626         sound_sight = gi.soundindex ("mutant/mutsght1.wav");
  627         sound_search = gi.soundindex ("mutant/mutsrch1.wav");
  628         sound_step1 = gi.soundindex ("mutant/step1.wav");
  629         sound_step2 = gi.soundindex ("mutant/step2.wav");
  630         sound_step3 = gi.soundindex ("mutant/step3.wav");
  631         sound_thud = gi.soundindex ("mutant/thud1.wav");
  632         
  633         self->movetype = MOVETYPE_STEP;
  634         self->solid = SOLID_BBOX;
  635         self->s.modelindex = gi.modelindex ("models/monsters/mutant/tris.md2");
  636         VectorSet (self->mins, -32, -32, -24);
  637         VectorSet (self->maxs, 32, 32, 48);
  638 
  639         self->health = 300;
  640         self->gib_health = -120;
  641         self->mass = 300;
  642 
  643         self->pain = mutant_pain;
  644         self->die = mutant_die;
  645 
  646         self->monsterinfo.stand = mutant_stand;
  647         self->monsterinfo.walk = mutant_walk;
  648         self->monsterinfo.run = mutant_run;
  649         self->monsterinfo.dodge = NULL;
  650         self->monsterinfo.attack = mutant_jump;
  651         self->monsterinfo.melee = mutant_melee;
  652         self->monsterinfo.sight = mutant_sight;
  653         self->monsterinfo.search = mutant_search;
  654         self->monsterinfo.idle = mutant_idle;
  655         self->monsterinfo.checkattack = mutant_checkattack;
  656 
  657         gi.linkentity (self);
  658         
  659         self->monsterinfo.currentmove = &mutant_move_stand;
  660 
  661         self->monsterinfo.scale = MODEL_SCALE;
  662         walkmonster_start (self);
  663 }
  664