File: game\m_flipper.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 FLIPPER
   24 
   25 ==============================================================================
   26 */
   27 
   28 #include "g_local.h"
   29 #include "m_flipper.h"
   30 
   31 
   32 static int      sound_chomp;
   33 static int      sound_attack;
   34 static int      sound_pain1;
   35 static int      sound_pain2;
   36 static int      sound_death;
   37 static int      sound_idle;
   38 static int      sound_search;
   39 static int      sound_sight;
   40 
   41 
   42 void flipper_stand (edict_t *self);
   43 
   44 mframe_t flipper_frames_stand [] =
   45 {
   46         ai_stand, 0, NULL
   47 };
   48         
   49 mmove_t flipper_move_stand = {FRAME_flphor01, FRAME_flphor01, flipper_frames_stand, NULL};
   50 
   51 void flipper_stand (edict_t *self)
   52 {
   53                 self->monsterinfo.currentmove = &flipper_move_stand;
   54 }
   55 
   56 #define FLIPPER_RUN_SPEED       24
   57 
   58 mframe_t flipper_frames_run [] =
   59 {
   60         ai_run, FLIPPER_RUN_SPEED, NULL,        // 6
   61         ai_run, FLIPPER_RUN_SPEED, NULL,
   62         ai_run, FLIPPER_RUN_SPEED, NULL,
   63         ai_run, FLIPPER_RUN_SPEED, NULL,
   64         ai_run, FLIPPER_RUN_SPEED, NULL,        // 10
   65 
   66         ai_run, FLIPPER_RUN_SPEED, NULL,
   67         ai_run, FLIPPER_RUN_SPEED, NULL,
   68         ai_run, FLIPPER_RUN_SPEED, NULL,
   69         ai_run, FLIPPER_RUN_SPEED, NULL,
   70         ai_run, FLIPPER_RUN_SPEED, NULL,
   71         ai_run, FLIPPER_RUN_SPEED, NULL,
   72         ai_run, FLIPPER_RUN_SPEED, NULL,
   73         ai_run, FLIPPER_RUN_SPEED, NULL,
   74         ai_run, FLIPPER_RUN_SPEED, NULL,
   75         ai_run, FLIPPER_RUN_SPEED, NULL,        // 20
   76 
   77         ai_run, FLIPPER_RUN_SPEED, NULL,
   78         ai_run, FLIPPER_RUN_SPEED, NULL,
   79         ai_run, FLIPPER_RUN_SPEED, NULL,
   80         ai_run, FLIPPER_RUN_SPEED, NULL,
   81         ai_run, FLIPPER_RUN_SPEED, NULL,
   82         ai_run, FLIPPER_RUN_SPEED, NULL,
   83         ai_run, FLIPPER_RUN_SPEED, NULL,
   84         ai_run, FLIPPER_RUN_SPEED, NULL,
   85         ai_run, FLIPPER_RUN_SPEED, NULL         // 29
   86 };
   87 mmove_t flipper_move_run_loop = {FRAME_flpver06, FRAME_flpver29, flipper_frames_run, NULL};
   88 
   89 void flipper_run_loop (edict_t *self)
   90 {
   91         self->monsterinfo.currentmove = &flipper_move_run_loop;
   92 }
   93 
   94 mframe_t flipper_frames_run_start [] =
   95 {
   96         ai_run, 8, NULL,
   97         ai_run, 8, NULL,
   98         ai_run, 8, NULL,
   99         ai_run, 8, NULL,
  100         ai_run, 8, NULL,
  101         ai_run, 8, NULL
  102 };
  103 mmove_t flipper_move_run_start = {FRAME_flpver01, FRAME_flpver06, flipper_frames_run_start, flipper_run_loop};
  104 
  105 void flipper_run (edict_t *self)
  106 {
  107         self->monsterinfo.currentmove = &flipper_move_run_start;
  108 }
  109 
  110 /* Standard Swimming */ 
  111 mframe_t flipper_frames_walk [] =
  112 {
  113         ai_walk, 4, NULL,
  114         ai_walk, 4, NULL,
  115         ai_walk, 4, NULL,
  116         ai_walk, 4, NULL,
  117         ai_walk, 4, NULL,
  118         ai_walk, 4, NULL,
  119         ai_walk, 4, NULL,
  120         ai_walk, 4, NULL,
  121         ai_walk, 4, NULL,
  122         ai_walk, 4, NULL,
  123         ai_walk, 4, NULL,
  124         ai_walk, 4, NULL,
  125         ai_walk, 4, NULL,
  126         ai_walk, 4, NULL,
  127         ai_walk, 4, NULL,
  128         ai_walk, 4, NULL,
  129         ai_walk, 4, NULL,
  130         ai_walk, 4, NULL,
  131         ai_walk, 4, NULL,
  132         ai_walk, 4, NULL,
  133         ai_walk, 4, NULL,
  134         ai_walk, 4, NULL,
  135         ai_walk, 4, NULL,
  136         ai_walk, 4, NULL
  137 };
  138 mmove_t flipper_move_walk = {FRAME_flphor01, FRAME_flphor24, flipper_frames_walk, NULL};
  139 
  140 void flipper_walk (edict_t *self)
  141 {
  142         self->monsterinfo.currentmove = &flipper_move_walk;
  143 }
  144 
  145 mframe_t flipper_frames_start_run [] =
  146 {
  147         ai_run, 8, NULL,
  148         ai_run, 8, NULL,
  149         ai_run, 8, NULL,
  150         ai_run, 8, NULL,
  151         ai_run, 8, flipper_run
  152 };
  153 mmove_t flipper_move_start_run = {FRAME_flphor01, FRAME_flphor05, flipper_frames_start_run, NULL};
  154 
  155 void flipper_start_run (edict_t *self)
  156 {
  157         self->monsterinfo.currentmove = &flipper_move_start_run;
  158 }
  159 
  160 mframe_t flipper_frames_pain2 [] =
  161 {
  162         ai_move, 0, NULL,
  163         ai_move, 0, NULL,
  164         ai_move, 0,     NULL,
  165         ai_move, 0,     NULL,
  166         ai_move, 0, NULL
  167 };
  168 mmove_t flipper_move_pain2 = {FRAME_flppn101, FRAME_flppn105, flipper_frames_pain2, flipper_run};
  169 
  170 mframe_t flipper_frames_pain1 [] =
  171 {
  172         ai_move, 0, NULL,
  173         ai_move, 0, NULL,
  174         ai_move, 0,     NULL,
  175         ai_move, 0,     NULL,
  176         ai_move, 0, NULL
  177 };
  178 mmove_t flipper_move_pain1 = {FRAME_flppn201, FRAME_flppn205, flipper_frames_pain1, flipper_run};
  179 
  180 void flipper_bite (edict_t *self)
  181 {
  182         vec3_t  aim;
  183 
  184         VectorSet (aim, MELEE_DISTANCE, 0, 0);
  185         fire_hit (self, aim, 5, 0);
  186 }
  187 
  188 void flipper_preattack (edict_t *self)
  189 {
  190         gi.sound (self, CHAN_WEAPON, sound_chomp, 1, ATTN_NORM, 0);
  191 }
  192 
  193 mframe_t flipper_frames_attack [] =
  194 {
  195         ai_charge, 0,   flipper_preattack,
  196         ai_charge, 0,   NULL,
  197         ai_charge, 0,   NULL,
  198         ai_charge, 0,   NULL,
  199         ai_charge, 0,   NULL,
  200         ai_charge, 0,   NULL,
  201         ai_charge, 0,   NULL,
  202         ai_charge, 0,   NULL,
  203         ai_charge, 0,   NULL,
  204         ai_charge, 0,   NULL,
  205         ai_charge, 0,   NULL,
  206         ai_charge, 0,   NULL,
  207         ai_charge, 0,   NULL,
  208         ai_charge, 0,   flipper_bite,
  209         ai_charge, 0,   NULL,
  210         ai_charge, 0,   NULL,
  211         ai_charge, 0,   NULL,
  212         ai_charge, 0,   NULL,
  213         ai_charge, 0,   flipper_bite,
  214         ai_charge, 0,   NULL
  215 };
  216 mmove_t flipper_move_attack = {FRAME_flpbit01, FRAME_flpbit20, flipper_frames_attack, flipper_run};
  217 
  218 void flipper_melee(edict_t *self)
  219 {
  220         self->monsterinfo.currentmove = &flipper_move_attack;
  221 }
  222 
  223 void flipper_pain (edict_t *self, edict_t *other, float kick, int damage)
  224 {
  225         int             n;
  226 
  227         if (self->health < (self->max_health / 2))
  228                 self->s.skinnum = 1;
  229 
  230         if (level.time < self->pain_debounce_time)
  231                 return;
  232 
  233         self->pain_debounce_time = level.time + 3;
  234         
  235         if (skill->value == 3)
  236                 return;         // no pain anims in nightmare
  237 
  238         n = (rand() + 1) % 2;
  239         if (n == 0)
  240         {
  241                 gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
  242                 self->monsterinfo.currentmove = &flipper_move_pain1;
  243         }
  244         else
  245         {
  246                 gi.sound (self, CHAN_VOICE, sound_pain2, 1, ATTN_NORM, 0);
  247                 self->monsterinfo.currentmove = &flipper_move_pain2;
  248         }
  249 }
  250 
  251 void flipper_dead (edict_t *self)
  252 {
  253         VectorSet (self->mins, -16, -16, -24);
  254         VectorSet (self->maxs, 16, 16, -8);
  255         self->movetype = MOVETYPE_TOSS;
  256         self->svflags |= SVF_DEADMONSTER;
  257         self->nextthink = 0;
  258         gi.linkentity (self);
  259 }
  260 
  261 mframe_t flipper_frames_death [] =
  262 {
  263         ai_move, 0,      NULL,
  264         ai_move, 0,      NULL,
  265         ai_move, 0,      NULL,
  266         ai_move, 0,      NULL,
  267         ai_move, 0,      NULL,
  268         ai_move, 0,      NULL,
  269         ai_move, 0,      NULL,
  270         ai_move, 0,      NULL,
  271         ai_move, 0,      NULL,
  272         ai_move, 0,      NULL,
  273 
  274         ai_move, 0,      NULL,
  275         ai_move, 0,      NULL,
  276         ai_move, 0,      NULL,
  277         ai_move, 0,      NULL,
  278         ai_move, 0,      NULL,
  279         ai_move, 0,      NULL,
  280         ai_move, 0,      NULL,
  281         ai_move, 0,      NULL,
  282         ai_move, 0,      NULL,
  283         ai_move, 0,      NULL,
  284 
  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 
  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         ai_move, 0,      NULL,
  306 
  307         ai_move, 0,      NULL,
  308         ai_move, 0,      NULL,
  309         ai_move, 0,      NULL,
  310         ai_move, 0,      NULL,
  311         ai_move, 0,      NULL,
  312         ai_move, 0,      NULL,
  313         ai_move, 0,      NULL,
  314         ai_move, 0,      NULL,
  315         ai_move, 0,      NULL,
  316         ai_move, 0,      NULL,
  317 
  318         ai_move, 0,      NULL,
  319         ai_move, 0,      NULL,
  320         ai_move, 0,      NULL,
  321         ai_move, 0,      NULL,
  322         ai_move, 0,      NULL,
  323         ai_move, 0,      NULL
  324 };
  325 mmove_t flipper_move_death = {FRAME_flpdth01, FRAME_flpdth56, flipper_frames_death, flipper_dead};
  326 
  327 void flipper_sight (edict_t *self, edict_t *other)
  328 {
  329         gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  330 }
  331 
  332 void flipper_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  333 {
  334         int             n;
  335 
  336 // check for gib
  337         if (self->health <= self->gib_health)
  338         {
  339                 gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  340                 for (n= 0; n < 2; n++)
  341                         ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
  342                 for (n= 0; n < 2; n++)
  343                         ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  344                 ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  345                 self->deadflag = DEAD_DEAD;
  346                 return;
  347         }
  348 
  349         if (self->deadflag == DEAD_DEAD)
  350                 return;
  351 
  352 // regular death
  353         gi.sound (self, CHAN_VOICE, sound_death, 1, ATTN_NORM, 0);
  354         self->deadflag = DEAD_DEAD;
  355         self->takedamage = DAMAGE_YES;
  356         self->monsterinfo.currentmove = &flipper_move_death;
  357 }
  358 
  359 /*QUAKED monster_flipper (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
  360 */
  361 void SP_monster_flipper (edict_t *self)
  362 {
  363         if (deathmatch->value)
  364         {
  365                 G_FreeEdict (self);
  366                 return;
  367         }
  368 
  369         sound_pain1             = gi.soundindex ("flipper/flppain1.wav");       
  370         sound_pain2             = gi.soundindex ("flipper/flppain2.wav");       
  371         sound_death             = gi.soundindex ("flipper/flpdeth1.wav");       
  372         sound_chomp             = gi.soundindex ("flipper/flpatck1.wav");
  373         sound_attack    = gi.soundindex ("flipper/flpatck2.wav");
  374         sound_idle              = gi.soundindex ("flipper/flpidle1.wav");
  375         sound_search    = gi.soundindex ("flipper/flpsrch1.wav");
  376         sound_sight             = gi.soundindex ("flipper/flpsght1.wav");
  377 
  378         self->movetype = MOVETYPE_STEP;
  379         self->solid = SOLID_BBOX;
  380         self->s.modelindex = gi.modelindex ("models/monsters/flipper/tris.md2");
  381         VectorSet (self->mins, -16, -16, 0);
  382         VectorSet (self->maxs, 16, 16, 32);
  383 
  384         self->health = 50;
  385         self->gib_health = -30;
  386         self->mass = 100;
  387 
  388         self->pain = flipper_pain;
  389         self->die = flipper_die;
  390 
  391         self->monsterinfo.stand = flipper_stand;
  392         self->monsterinfo.walk = flipper_walk;
  393         self->monsterinfo.run = flipper_start_run;
  394         self->monsterinfo.melee = flipper_melee;
  395         self->monsterinfo.sight = flipper_sight;
  396 
  397         gi.linkentity (self);
  398 
  399         self->monsterinfo.currentmove = &flipper_move_stand;    
  400         self->monsterinfo.scale = MODEL_SCALE;
  401 
  402         swimmonster_start (self);
  403 }
  404