Logo Search packages:      
Sourcecode: xblast version File versions  Download package

player.c

/*
 * Program XBLAST V2.5.15 or higher
 * (C) by Oliver Vogel (e-mail: vogel@ikp.uni-koeln.de)
 * October 18, 1998
 * started August 1993
 *
 * File: player.c 
 * player managment
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2; or (at your option)
 * any later version
 *
 * This program is distributed in the hope that it will be entertaining,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: player.c,v 1.5 1999/05/01 19:34:11 xblast Exp $
 * $Log: player.c,v $
 * Revision 1.5  1999/05/01 19:34:11  xblast
 * Morphed player now can move as a bomb
 * Eyes are no longer visible when bomb explodes
 *
 * Revision 1.4  1999/04/02 18:02:56  xblast
 * Bugfix: player could could morph even when on another bomb
 *
 * Revision 1.3  1999/03/21 13:46:45  xblast
 * Experimental score functions removed
 *
 * Revision 1.2  1998/10/18 12:30:04  xblast
 * Morphing Bomb extra
 *
 * Revision 1.1  1998/01/03 14:08:57  xblast
 * Initial revision
 *
 */
#include <stdio.h>
#include <unistd.h>

#define _PLAYER_C
#include "include.h"
#include "mytypes.h"
#include "const.h"
#include "bomb.h"
#include "data.h"
#include "demo.h"
#include "info.h"
#include "map.h"
#include "player.h"
#include "setup.h"
#include "sprite.h"
#include "status.h"
#include "util.h"
#ifdef XBLAST_SOUND
#include "sound.h"
#endif

/*
 * local constants
 */
#define BOMB_STEP 2

/*
 * global variables
 */
BMPlayer player_stat[2*MAX_PLAYER];
PlayerStrings p_string[2*MAX_PLAYER];

/*
 * local variables
 */
static int min_range, min_bombs;
static BMHealth revive_health;
static int sposswap[MAX_PLAYER];
static int maxShuffle;
static int random_spos, max_lives;
static int num_player;
static int game_mode;

extern void (*special_extra_function)();

/* starting position offsets for double mode */
static BMPosition delta_pos[MAX_PM][4][2] = {
  /* same position */
  {
    { {0, 0}, {0, 0}, },
    { {0, 0}, {0, 0}, },
    { {0, 0}, {0, 0}, },
    { {0, 0}, {0, 0}, },
  },
  /* polar position */
  {
    { {BLOCK_HEIGHT, 0}, {0, BLOCK_WIDTH}, },
    { {BLOCK_HEIGHT, 0}, {0, -BLOCK_WIDTH}, },
    { {-BLOCK_HEIGHT, 0}, {0, -BLOCK_WIDTH}, },
    { {-BLOCK_HEIGHT, 0}, {0, BLOCK_WIDTH}, },
  },
  /* right position */
  {
    { {0, 0}, {0, BLOCK_WIDTH} },
    { {0, 0}, {0, BLOCK_WIDTH} },
    { {0, 0}, {0, BLOCK_WIDTH} },
    { {0, 0}, {0, BLOCK_WIDTH} },
  },
  /* inner position */
  {
    { {0, 0}, {BLOCK_HEIGHT, BLOCK_WIDTH} },
    { {0, 0}, {BLOCK_HEIGHT, -BLOCK_WIDTH} },
    { {0, 0}, {-BLOCK_HEIGHT, -BLOCK_WIDTH} },
    { {0, 0}, {-BLOCK_HEIGHT, BLOCK_WIDTH} },
  },
  /* left & right position */
  {
    { {0, -BLOCK_WIDTH}, {0, BLOCK_WIDTH} },
    { {0, -BLOCK_WIDTH}, {0, BLOCK_WIDTH} },
    { {0, -BLOCK_WIDTH}, {0, BLOCK_WIDTH} },
    { {0, -BLOCK_WIDTH}, {0, BLOCK_WIDTH} },
  },
  /*  position below */
  {
    { {0, 0}, {BLOCK_HEIGHT, 0}, },
    { {0, 0}, {BLOCK_HEIGHT, 0}, },
    { {0, 0}, {BLOCK_HEIGHT, 0}, },
    { {0, 0}, {BLOCK_HEIGHT, 0}, },
  },
  /* horizontal positioning */
  {
    { {0, 0}, {0, BLOCK_WIDTH} },
    { {0, 0}, {0, -BLOCK_WIDTH} },
    { {0, 0}, {0, -BLOCK_WIDTH} },
    { {0, 0}, {0, BLOCK_WIDTH} },
  },
  /* vertical positioning */
  {
    { {0,0}, {BLOCK_HEIGHT, 0} },
    { {0,0}, {BLOCK_HEIGHT, 0} },
    { {0,0}, {-BLOCK_HEIGHT, 0} },
    { {0,0}, {-BLOCK_HEIGHT, 0} },
  },
  /* circle positioning */
  {
    { {-BLOCK_HEIGHT, 0 }, {BLOCK_HEIGHT, 0} },
    { {0, -BLOCK_WIDTH}, {0, BLOCK_WIDTH} },
    { {BLOCK_HEIGHT, 0 }, {-BLOCK_HEIGHT, 0} },
    { {0, BLOCK_WIDTH}, {0, -BLOCK_WIDTH} },
  },
};

#ifdef __STDC__
void 
init_shuffle_startpos (int npos)
#else
void 
init_shuffle_startpos (npos)
     int npos;
#endif
{
  int i,x;
  int j;
  int a;

  maxShuffle = npos;

  for(i=0; i<npos; i++) {
    sposswap[i] = i;
  }
  for(x=0; x<(npos-1); x++) {
    for(i=0; i<npos; i++) {
      j = random_number(npos);
      a           = sposswap[i];
      sposswap[i] = sposswap[j];
      sposswap[j] = a;
    }
  }
}

/*
 * public function setup_players
 */
#ifdef __STDC__
void
setup_players (unsigned long g_mode, 
             BMPlayerData *data)
#else
void
setup_players (g_mode, data)
     unsigned long g_mode;
     BMPlayerData *data;
#endif
{
  BMPlayer *ps;
  int player;
  static int tmpx[MAX_PLAYER];
  static int tmpy[MAX_PLAYER];

  /* set player info */
  set_info_player(data);

  min_range = (int) data->range;
  min_bombs = (int) data->bombs;

  revive_health = data->revive_health;

  /* Shuffle start positions (if desired) */
  
  /* Must load for all players as we scramble the x/y positions */
  for (player = 0; player < MAX_PLAYER; player ++) {
    ps = player_stat + player;

    if ( GM_NoGrid & g_mode) {
      ps->y = data->position[player].y;
      ps->x = data->position[player].x;
    } else {
      ps->y = (data->position[player].y-1) * BLOCK_HEIGHT;
      ps->x =  data->position[player].x * BLOCK_WIDTH;
    }
  }
  if ( (random_spos) && ( g_mode & GM_Random)  && !(game_mode & GM_Double) ) {
    int i;
    
    for(i=0;i<maxShuffle;i++) {
      tmpx[i] = player_stat[i].x;
      tmpy[i] = player_stat[i].y;
    }
    for(i=0;i<maxShuffle;i++) {
      player_stat[i].x = tmpx[sposswap[i]];
      player_stat[i].y = tmpy[sposswap[i]];
    }
  }

  /* setup other player attribtes */
  for (player = 0; player < num_player; player ++) {
    ps = player_stat + player;

    if (game_mode & GM_Double) {
      /* set new player positions here */
      if (player >= (num_player/2)) {
      ps->y = player_stat[player-(num_player/2)].y 
        - data->pm_radius*delta_pos[data->pos_mod][player-(num_player/2)][0].y
        + data->pm_radius*delta_pos[data->pos_mod][player-(num_player/2)][1].y;
      ps->x = player_stat[player-(num_player/2)].x
        - data->pm_radius*delta_pos[data->pos_mod][player-(num_player/2)][0].x
        + data->pm_radius*delta_pos[data->pos_mod][player-(num_player/2)][1].x;
      } else {
      ps->y += data->pm_radius*delta_pos[data->pos_mod][player][0].y;
      ps->x += data->pm_radius*delta_pos[data->pos_mod][player][0].x;
      }
    } 

    ps->invincible = NEW_INVINCIBLE;
    ps->illness = data->init_health;
    ps->health = data->init_health;
    ps->illtime = 0;
    ps->junkie = 0;
    ps->dying = 0;
    ps->stunned = 0;
    ps->lives = max_lives;
    ps->range = data->range;
    ps->bombs = data->bombs;
    ps->extra_flags = data->init_flags;
    ps->special_bombs = 0;
    ps->cloaking = 0;
    if (LF_RC & ps->extra_flags) {
      ps->remote_control = 1;
    } else {
      ps->remote_control = 0;
    }
    if (LF_Teleport & ps->extra_flags) {
      ps->teleport = 1;
    } else {
      ps->teleport = 0;
    }      
    if (LF_Kick & ps->extra_flags) {
      ps->kick = 1;
    } else {
      ps->kick = 0;
    }
    if (LF_Airpump & ps->extra_flags) {
      ps->air_button = TRUE;
    } else {
      ps->air_button = FALSE;
    }
    if (LF_Cloak & ps->extra_flags) {
      ps->cloaking = -GAME_TIME;
    }
    ps->num_extras = 0;
    ps->abort = FALSE;
    ps->d_ist = GoStop;
    ps->d_soll= GoStop;
    ps->d_look= GoDown;
    ps->num_morph = 0;
    ps->morphed = 0;
  }
}

/*
 * global function init_players
 */
#ifdef __STDC__
void
init_players (XBConfig *config, 
            XBSettings *setup,
            int g_mode)
#else
void
init_players (config, setup, g_mode)
  XBConfig *config;
  XBSettings *setup;
  int g_mode;
#endif
{
  BMPlayer *ps;
  int player;

  /* get names and messages */
  if (config->record_mode != RM_PLAYBACK) {
    player_from_database (player_stat);
    player_strings_from_database (p_string, config);
  } else {
    /* player_from_demo (player_stat); */
    player_strings_from_demo (p_string, config);
  }

  /* copy player settings */
  max_lives = setup->max_lives;
  random_spos = setup->random_spos;
  num_player = config->num_player;
  game_mode = g_mode;

  for (player =0; player < num_player; player++) {
    ps = player_stat + player;
    ps->victories = 0;
    ps->id = player;

    /* set partner and sprite if in team mode */
    switch (config->team_mode) {
    case TM_Single:
      ps->number = player;
      ps->team = ps->id;
      break;

    case TM_Team:
      ps->number = player;
      if (player % 2) {
      ps->team = ps->id-1;;
      } else {
      ps->team = ps->id;
      }
      break;

    case TM_Double:
      if (player < config->num_player/2) {
      ps->team = ps->id;
      ps->number = player;
      } else {
      ps->team = ps->id - config->num_player/2;
      ps->number = player - (config->num_player/2);
      }
    }
    ps->sprite = create_player_sprite(ps->number, 0, 0, 0, SPM_UNMAPPED);

#ifdef DEBUG
    fprintf(stderr, "XBlast[%d]: Player(%d) @ Display(%d)\n",
          (int) getpid(), ps->id, ps->disp);
#endif
  }
}

/*
 * global function: delete_player_sprites
 */
#ifdef __STDC__
void
delete_player_sprites (void)
#else
void
delete_player_sprites ()
#endif
{
  int player;

  for (player=0; player<num_player; player++) {
    delete_sprite(player_stat[player].sprite);
  }
}

/* 
 * global function drop_bomb 
 */
#ifdef __STDC__
void 
drop_bomb (BMPlayer *ps,
         int type)
#else
void 
drop_bomb(ps, type)
     BMPlayer *ps;
     int type;
#endif
{
  if ( (ps->bombs !=0) && 
       (ps->illness!=IllEmpty) && 
       (ps->morphed < 2) &&
       (type == BMTdefault || ps->special_bombs > 0) ) {
    if (ps->lives >0) {
      if (new_player_bomb(ps, type)) {
#ifdef XBLAST_SOUND
      play_sound(SND_DROP, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
      ps->bombs --;
      if (ps->morphed) {
        ps->morphed = 2;
        ps->num_morph --;
      }
      if (type != BMTdefault) {
        ps->special_bombs --;
      }
      } else {
      if (ps->morphed) {
        ps->morphed = 0;
      }
      }
    }
  }
}

/* 
 * local fucntion walk_stop 
 */
#ifdef __STDC__
static void 
walk_stop (BMPlayer *ps,
         int flag,
         int mazex, 
         int mazey)
#else
static void 
walk_stop (ps, flag, mazex, mazey)
     BMPlayer *ps;
     int flag;
     int mazex, mazey;
#endif
{
  if (ps->illness != IllReverse) {
    switch(ps->d_look) {
    case GoDown:
      set_sprite_anime(ps->sprite,SpriteStopDown);
      break;
    case GoUp:
      set_sprite_anime(ps->sprite,SpriteStopUp);
      break;
    case GoLeft:
      set_sprite_anime(ps->sprite,SpriteStopLeft);
      break;
    case GoRight:
      set_sprite_anime(ps->sprite,SpriteStopRight);
      break;
    default:
      break;
    }
  } else {
    switch(ps->d_look) {
    case GoDown:
      set_sprite_anime(ps->sprite,SpriteStopUp);
      break;
    case GoUp:
      set_sprite_anime(ps->sprite,SpriteStopDown);
      break;
    case GoLeft:
      set_sprite_anime(ps->sprite,SpriteStopRight);
      break;
    case GoRight:
      set_sprite_anime(ps->sprite,SpriteStopLeft);
      break;
    default:
      break;
    }
  }
}



/* 
 * local function walk_up 
 */
#ifdef __STDC__
static void 
walk_up (BMPlayer *ps,
       int flag,
       int mazex, 
       int mazey)
#else
static void 
walk_up (ps, flag, mazex, mazey)
     BMPlayer *ps;
     int flag;
     int mazex, mazey;
#endif
{
  if ( !(flag && check_maze(mazex, mazey-1))) {
    ps->y -= STEP_VERT;
    mazey = ps->y/BLOCK_HEIGHT+1;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteWalkUp0 + ((ps->y/STEP_VERT) % 4));
    } else {
      set_sprite_anime(ps->sprite, SpriteWalkDown0 + ((ps->y/STEP_VERT) % 4));
    }
  } else {
    ps->d_ist = GoStop;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteStopUp);
    } else {
      set_sprite_anime(ps->sprite, SpriteStopDown);
    }
  }

  /* try a kick */
  if ( check_bomb(mazex, mazey) 
      && ( (ps->y % BLOCK_HEIGHT) == (STEP_VERT*BOMB_STEP) ) ) {
    if (ps->kick) {
#ifdef XBLAST_SOUND
      play_sound(SND_KICK, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
      move_bomb(mazex, mazey, GoUp);
      ps->d_soll = GoStop;
    }
    ps->y += STEP_VERT;
  }
}



/* 
 * local function walk_left 
 */
#ifdef __STDC__
static void 
walk_left (BMPlayer *ps,
         int flag,
         int mazex, 
         int mazey)
#else
static void 
walk_left (ps, flag, mazex, mazey)
     BMPlayer *ps;
     int flag;
     int mazex, mazey;
#endif
{
  if ( !(flag && check_maze(mazex -1, mazey) )) {
    ps->x -= STEP_HORI;
    mazex = ps->x/BLOCK_WIDTH;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteWalkLeft0 + ((ps->x/STEP_HORI) % 4));
    } else {
      set_sprite_anime(ps->sprite, SpriteWalkRight0 + ((ps->x/STEP_HORI) % 4));
    }
  } else {
    ps->d_ist = GoStop;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteStopLeft);
    } else {
      set_sprite_anime(ps->sprite, SpriteStopRight);
    }
  }

  /* try a kick */
  if ( check_bomb(mazex, mazey) 
      && ((ps->x % BLOCK_WIDTH) == (STEP_HORI*BOMB_STEP) ) ) {
    if (ps->kick) {
#ifdef XBLAST_SOUND
      play_sound(SND_KICK, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
      move_bomb(mazex, mazey, GoLeft);
      ps->d_soll = GoStop;
    }
    ps->x += STEP_HORI;
  }
}



/* 
 * local function walk_down 
 */
#ifdef __STDC__
static void 
walk_down (BMPlayer *ps,
         int flag,
         int mazex, 
         int mazey)
#else
static void 
walk_down (ps, flag, mazex, mazey)
     BMPlayer *ps;
     int flag;
     int mazex, mazey;
#endif
{
  if ( !(flag && check_maze(mazex, mazey+1) )) {
    ps->y += STEP_VERT;
    mazey = ps->y/BLOCK_HEIGHT + 1;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteWalkDown0 + ((ps->y/STEP_VERT) % 4));
    } else {
      set_sprite_anime(ps->sprite, SpriteWalkUp0 + ((ps->y/STEP_VERT) % 4));
    }
  } else {
    ps->d_ist = GoStop;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteStopDown);
    } else {
      set_sprite_anime(ps->sprite, SpriteStopUp);
    }
  }
  
  /* try a kick */
  if ( check_bomb(mazex, mazey+1)
      && ( (ps->y % BLOCK_HEIGHT) == (BLOCK_HEIGHT - STEP_VERT*BOMB_STEP) )
      ) {
    if (ps->kick) {
#ifdef XBLAST_SOUND
      play_sound(SND_KICK, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
      move_bomb(mazex, mazey+1,     GoDown);
      ps->d_soll = GoStop;
    }
    ps->y -= STEP_VERT;
  }
}



/* 
 * local function walk_right 
 */
#ifdef __STDC__
static void 
walk_right (BMPlayer *ps,
          int flag,
          int mazex, 
          int mazey)
#else
static void 
walk_right (ps, flag, mazex, mazey)
     BMPlayer *ps;
     int flag;
     int mazex, mazey;
#endif
{
  if ( !(flag && check_maze(mazex +1, mazey))) {
    ps->x += STEP_HORI;
    mazex = ps->x/BLOCK_WIDTH;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteWalkRight0 + ((ps->x/STEP_HORI) % 4));
    } else {
      set_sprite_anime(ps->sprite, SpriteWalkLeft0 + ((ps->x/STEP_HORI) % 4));
    }
  } else {
    ps->d_ist = GoStop;
    if (ps->illness != IllReverse) {
      set_sprite_anime(ps->sprite, SpriteStopRight);
    } else {
      set_sprite_anime(ps->sprite, SpriteStopLeft);
    }
  }

  /* try kick */
  if ( check_bomb(mazex+1, mazey)
      && ( (ps->x % BLOCK_WIDTH) == (BLOCK_WIDTH - STEP_HORI*BOMB_STEP) ) ) {
    if (ps->kick) {
#ifdef XBLAST_SOUND
      play_sound(SND_KICK, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
      move_bomb(mazex+1, mazey, GoRight);
      ps->d_soll = GoStop;
    }
    ps->x -= STEP_HORI;
  }
}


/*
 * local function teleport_player
 */
#ifdef __STDC__
static int
teleport_player (BMPlayer *ps,
             int mazex,
             int mazey) 
#else
static int
teleport_player (ps, mazex, mazey) 
     BMPlayer *ps;
     int mazex, mazey;
#endif
{
  /* teleport dri@eup.siemens-albis.ch */
  /* 'No spare space' bug killed by Garth Denley */
  /* Horizontal/Vertical teleport re-enabled */
  int new_mazex, new_mazey;
  int tele_tries;
  int tele_success;
  
  tele_tries = 25;
  tele_success = FALSE;
  
  do {
    new_mazex = random_number(MAZE_W);
    new_mazey = random_number(MAZE_H);
    tele_tries--;
    if ((!check_maze(new_mazex,new_mazey))
      && ((mazex != new_mazex) || (mazey != new_mazey))) {
      tele_success = TRUE;
    }
  } while ((!tele_success) && (tele_tries>0) );
  
  if (tele_success) {
#ifdef XBLAST_SOUND
      play_sound(SND_TELE1, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
    mazex = new_mazex;
    mazey = new_mazey;
    ps->x = BLOCK_WIDTH * mazex;
    ps->y = BLOCK_HEIGHT * (mazey - 1);
    ps->d_soll = GoStop;
    ps->d_look = GoDown;
#ifdef XBLAST_SOUND
      play_sound(SND_TELE2, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
  }

  return tele_success;
}


/*
 * array of walk functions
 */

static PFV walk_dir[MAX_DIR] = {
  walk_stop,
  walk_up,
  walk_left,
  walk_down,
  walk_right,
  walk_stop,
};

/* 
 * local function do_walk 
 */
#ifdef __STDC__
static void 
do_walk (BMPlayer *ps, 
       int game_time)
#else
static void 
do_walk (ps, game_time)
  BMPlayer *ps;
  int game_time;
#endif
{
  int flag;
  int mazex,mazey;
  int i;
  int xalt,yalt;
  int spm_mode;

  xalt = ps->x;
  yalt = ps->y;

  if ( !( (ps->illness == IllSlow) && (game_time & 0x01) ) ) {
    for (i=0; i<=(ps->illness == IllRun); i++) {
      flag = FALSE;
      
      mazex = ps->x / BLOCK_WIDTH;
      mazey = ps->y / BLOCK_HEIGHT + 1;
      
      if ( ( (ps->x % BLOCK_WIDTH) == 0)
        && ((ps->y % BLOCK_HEIGHT) == 0) ) {
      flag = TRUE;
      
      if (ps->teleport == TELEPORT_TIME) {
        if (teleport_player(ps, mazex, mazey)) {
          ps->teleport--;
        }
      }

      ps->d_ist = ps->d_soll;
      if (ps->d_ist != GoStop)
        ps->d_look = ps->d_ist;
      }
      
      /* random teleporting */
      if ( (ps->illness == IllTeleport) && (0 == random_number(32) ) ) {
      mark_maze_rect (ps->x + SPRITE_X_OFF, ps->y + SPRITE_Y_OFF,
                  SPRITE_WIDTH, SPRITE_HEIGHT);
      teleport_player(ps, mazex, mazey);
      ps->d_ist = GoStop;
      ps->d_soll = GoStop;
      mark_maze_rect (ps->x + SPRITE_X_OFF, ps->y + SPRITE_Y_OFF,
                  SPRITE_WIDTH, SPRITE_HEIGHT);
      }

      /* let the player walk */
      (*walk_dir[ps->d_ist])(ps, flag, mazex, mazey);
      move_sprite (ps->sprite, ps->x, ps->y);

      /* insert get _extra here */
      if ( (ps->x % BLOCK_WIDTH == 0) && (ps->y % BLOCK_HEIGHT == 0) ) {
      switch(get_extra(ps->invincible, ps->x / BLOCK_WIDTH ,
                   ps->y / BLOCK_HEIGHT + 1 ))
        {
        case BTBomb:
#ifdef XBLAST_SOUND
            play_sound(SND_NEWBOMB, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
          ps->bombs ++;
          break;
        case BTRange:
#ifdef XBLAST_SOUND
            play_sound(SND_MOREFIRE, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
          if (ps->range < MAX_RANGE)
            ps->range ++;
          break;
        case BTSick:
          ps->illtime = ILLTIME;
          ps->illness = random_number(MAX_ILL)+1;

#ifdef XBLAST_SOUND
          if (ps->illness == IllInvisible) {
            play_sound(SND_INVIS, ps->x / (PIXW / MAX_SOUND_POSITION));
          } else {
            play_sound(SND_BAD, ps->x / (PIXW / MAX_SOUND_POSITION));
          } 
#endif
          if (ps->illness == IllReverse) {
            switch (ps->d_ist) {
            case GoDown:
            ps->d_ist = GoUp;
            break;
            case GoUp:
            ps->d_ist = GoDown;
            break;
            case GoLeft:
            ps->d_ist = GoRight;
            break;
            case GoRight:
            ps->d_ist = GoLeft;
            break;
            default:
            break;
            }
          }
          break;

        case BTSpecial:
          ps->num_extras++;
          (*special_extra_function)(ps);
          break;
        }
      }
    }
  }

  /* draw player if not totally invisible or morphed */
  if (ps->illness != IllInvisible) {
    /* set default mode */
    spm_mode = SPM_MAPPED;
    /* first check for cloak */
    if (ps->cloaking < 0) {
      ps->cloaking ++;
      if (ps->cloaking & 0x01) {
      spm_mode = ps->disp;
      } else {
      spm_mode = SPM_UNMAPPED;
      }
    }
    /* blinking if invincible */
    if(ps->invincible > 0) {
      ps->invincible --;
      if (ps->invincible & 0x01) {
      spm_mode |= SPM_MASKED;
      }
      /* or slower blinking if arrived from teleport */
    } else if (ps->teleport > 1) {
      ps->teleport --;
      if ( (ps->teleport>>1) & 0x01) {
      spm_mode |= SPM_MASKED;
      }
    }
  } else {
    spm_mode = SPM_UNMAPPED;
  }
  set_sprite_mode (ps->sprite, spm_mode);

  /* is player still sick? */
  if (ps->illness != ps->health) {
    /* decrement illness timer */
    if ( (ps->illtime --) == 0) {
      /* heal if time is over */
      ps->illness = ps->health;
    }
  }

  /* drop random bombs if needed */
  if ( (ps->x % BLOCK_WIDTH == 0) && (ps->y % BLOCK_HEIGHT == 0) ) {
    if (ps->illness == IllBomb) {
      if ( random_number(4) != 0) {
      drop_bomb(ps, BMTdefault);
      }
    }
  }
}

#define JUNKIE_ILL_TIME (ILLTIME)
#define JUNKIE_STUN_TIME 12
#define JUNKIE_TIME_1 360
#define JUNKIE_TIME_2 210
#define JUNKIE_TIME_3 60   /* Speed */

/* 
 * local function do_morph 
 */
#ifdef __STDC__
static void 
do_morph (BMPlayer *ps)
#else
static void 
do_morph (ps)
  BMPlayer *ps;
#endif
{
  set_sprite_anime (ps->sprite, SpriteMorphed);
  set_sprite_mode (ps->sprite, (ps->morphed == 2) ? SPM_MAPPED : SPM_UNMAPPED);
  if (ps->d_soll != GoStop) {
    move_bomb (ps->x / BLOCK_WIDTH, ps->y / BLOCK_HEIGHT + 1, ps->d_soll);
    ps->d_soll = GoStop;
  }
}

/*
 * local function do_junkie
 */
#ifdef __STDC__
void
do_junkie (void)
#else
void
do_junkie ()
#endif
{
  BMPlayer *ps1;

  /* Junkie countdown */
  for (ps1 = player_stat; ps1 < player_stat + num_player; ps1++) {
    if ((ps1->lives) && (ps1->junkie)) {
      /* Junkie sickness */
      switch (--(ps1->junkie)) {
      case JUNKIE_TIME_1:
      case JUNKIE_TIME_2:
        /* Give a random illness */
        ps1->illtime = JUNKIE_ILL_TIME;
      ps1->illness = random_number(MAX_ILL)+1;
      break;
      
      case JUNKIE_TIME_3:
        /* Stun player and give speed */
        ps1->stunned += JUNKIE_STUN_TIME;
        ps1->illtime = JUNKIE_ILL_TIME;
        ps1->illness = IllRun;
      break;

      case 0:
        /* Too long! Take a hit. */
        ps1->dying = DEAD_TIME;
        ps1->junkie = MAX_JUNKIE_TIME;
      break;
      }
    }
  }
}


/*
 * local function infect_other_players
 */
#ifdef __STDC__
void 
infect_other_players (void)
#else
void 
infect_other_players ()
#endif
{
  BMPlayer *ps1,*ps2;

  for (ps1 = player_stat; ps1 < player_stat+num_player; ps1 ++) {
    for (ps2= ps1+1; ps2 < player_stat+num_player; ps2 ++) {
      if ( (ABS(ps1->x - ps2->x) < ILL_X)
        && (ABS(ps1->y - ps2->y) < ILL_Y)) {
      /* infection with "normal" viruses */
      if (ps1->illness != ps2->illness) {
        if ( (! ps2->invincible) &&  (ps1->illtime > ps2->illtime) ) {
          ps2->illness = ps1->illness;
          ps2->illtime = ILLTIME;
        } else if ( (! ps1->invincible) &&  (ps2->illtime > ps1->illtime) ) {
          ps1->illness = ps2->illness;
          ps1->illtime = ILLTIME;
        }
      }
      /* infection with junkie virus */
      if ( ( (ps2->junkie) && (!ps1->invincible) ) || (ps1->junkie) ) {
        ps1->junkie = MAX_JUNKIE_TIME;
      }
      if ( ( (ps1->junkie) && (!ps2->invincible) ) || (ps2->junkie) ) {
        ps2->junkie = MAX_JUNKIE_TIME;
      } 
      }
    }
  }
}


/*
 * local functzion have_a_gloat
 */
#ifdef __STDC__
static void 
have_a_gloat (int player)
#else
static void 
have_a_gloat (player)
     int player;
#endif
{
  int g,gloatpl,gloatpltt;
  
  gloatpl = -1;
  for(g=0; g<6; g++) {
    gloatpltt = random_number(num_player);
    if ((gloatpltt != player) && (player_stat[gloatpltt].lives > 0)) {
      gloatpl = gloatpltt;
      break;
    }
  }      
  if(gloatpl>-1) {
    set_message(p_string[gloatpl].gloat, FALSE);
  }
}


/*
 * local function kill_player_at
 */
#ifdef __STDC__
void
kill_player_at (int x, int y)
#else
void
kill_player_at (x,y)
     int x, y;
#endif
{
  BMPlayer *ps;
  int player;

  for (player = 0; player < num_player; player ++) {
    ps = player_stat + player;
    if ( ps->lives > 0 ) {
      if (    (ps->x < (x+1)*BLOCK_WIDTH)
           && (ps->x > (x-1)*BLOCK_WIDTH)
           && (ps->y < (y)  *BLOCK_HEIGHT)
           && (ps->y > (y-2)*BLOCK_HEIGHT) ) {
        ps->lives = 1;
        ps->dying = DEAD_TIME;
      }
    }
  }
}


/*
 * public function kill_other_players
 */
#ifdef __STDC__
int
kill_other_players (int team)
#else
int
kill_other_players (team)
  int team;
#endif
{
  int count = 0;
  int player;

  for (player = 0; player <num_player; player ++) {
    if ( (player_stat[player].team != team) 
       && (player_stat[player].lives > 0) ) {
      player_stat[player].dying= DEAD_TIME;
      count ++;
    }
  }

  return count;
}


/*
 * public function stun_other_players
 */
#ifdef __STDC__
int
stun_other_players (int team, 
                int time)
#else
int
stun_other_players (team, time)
  int team, time;
#endif
{
  int count = 0;
  int player;

  for (player = 0; player <num_player; player ++) {
    if ( (player_stat[player].team != team) 
       && (! player_stat[player].invincible > 0) ) {
#ifdef XBLAST_SOUND
      play_sound(SND_STUN, player_stat[player].x / (PIXW / MAX_SOUND_POSITION));
#endif
      player_stat[player].stunned = time;
      count ++;
    }
  }

  return count;
}


/*
 * local function revive_player 
 */
#ifdef __STDC__
static void 
revive_player (BMPlayer *ps, 
             int *active_player)
#else
static void 
revive_player (ps, active_player)
  BMPlayer *ps;
  int *active_player;
#endif 
{
  BMPlayer *ptr;
  PlayerStrings *st;
  int i, team_alive;
  
  st = p_string + ps->id;

  ps->lives --;

  if (ps->lives == 0) {
    set_sprite_mode (ps->sprite, SPM_UNMAPPED);
#ifdef XBLAST_SOUND
    play_sound(SND_DEAD, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
    team_alive = FALSE;
    for (i = 0, ptr = player_stat; i<num_player; i++, ptr++) {
      if (ptr->team == ps->team) {
      team_alive |= (ptr->lives != 0);
      }
    }
    if (!team_alive) {
      (*active_player) --;
    }
    
    distribute_extras(ps->bombs - min_bombs, 
                  ps->range - min_range,
                  ps->num_extras,
                  ps->special_bombs);
    set_message (st->loselevel, FALSE);
  }  else {
#ifdef XBLAST_SOUND
    play_sound(SND_OUCH, ps->x / (PIXW / MAX_SOUND_POSITION));
#endif
    distribute_extras(0, 0,
                  ps->num_extras,
                  ps->special_bombs);
    set_message (st->loselife, FALSE);
  }

  have_a_gloat(ps->id);

  /* reset values */
  ps->invincible = NEW_INVINCIBLE;
  ps->dying = 0;
  ps->stunned = 0;
  ps->illness = revive_health;
  ps->health = revive_health;
  ps->illtime = 0;
  ps->teleport = 0;
  ps->cloaking = 0;
  ps->morphed = 0;
  ps->num_morph = 0;

  /* Note that junkie ISN'T reset (not a bug) */

  /* very important */
  if (ps->remote_control > 0) {
    ignite_players_bombs(ps);
  }

  ps->remote_control = 0;
  ps->kick = 0;
  ps->air_button = FALSE;

  /* If special bombs are distributed, then zero the count */
  if (distrib_special()) {
    ps->special_bombs = 0;
  }

  /* Reset extra pickup count */
  ps->num_extras = 0;

  /* reset inital extras */
  if (RF_RC & ps->extra_flags) {
    ps->remote_control = 1;
  }
  if (RF_Teleport & ps->extra_flags) {
    ps->teleport = 1;
  }
  if (RF_Kick & ps->extra_flags) {
    ps->kick = 1;
  }
  if (RF_Airpump & ps->extra_flags) {
    ps->air_button = 1;
  }
  if (RF_Cloak & ps->extra_flags) {
    ps->cloaking = -GAME_TIME;
  }
  mark_maze_rect (ps->x + SPRITE_X_OFF, ps->y + SPRITE_Y_OFF,
              SPRITE_WIDTH, SPRITE_HEIGHT);
}



/*
 * local function do_stunned
 */
#ifdef __STDC__
static void 
do_stunned (BMPlayer *ps)
#else
static void 
do_stunned (ps)
     BMPlayer *ps;
#endif
{
  switch( (ps->d_look + ps->stunned - 1)%4 + GoStop + 1) {
  case GoDown:
    set_sprite_anime(ps->sprite,SpriteStopDown);
    break;
  case GoUp:
    set_sprite_anime(ps->sprite,SpriteStopUp);
    break;
  case GoLeft:
    set_sprite_anime(ps->sprite,SpriteStopLeft);
    break;
  case GoRight:
    set_sprite_anime(ps->sprite,SpriteStopRight);
    break;
  }
  
  ps->stunned -- ;
}



/*
 * local function do_die
 */
#ifdef __STDC__
static void 
do_die (BMPlayer *ps)
#else
static void 
do_die (ps)
     BMPlayer *ps;
#endif
{
  if (ps->dying == DEAD_TIME) {
    set_sprite_mode (ps->sprite, SPM_MAPPED);
  }
  ps->dying --;

  if (ps->lives > 1) {
    switch (ps->d_look) {
    case GoLeft:
      set_sprite_anime (ps->sprite, SpriteDamagedLeft);
      break;
    case GoUp:
      set_sprite_anime (ps->sprite, SpriteDamagedUp);
      break;
    case GoRight:
      set_sprite_anime (ps->sprite, SpriteDamagedRight);
      break;
    default:
      set_sprite_anime (ps->sprite, SpriteDamagedDown);
      break;
    }
  } else {
    switch (ps->d_look) {
    case GoLeft:
      set_sprite_anime (ps->sprite, SpriteDeadLeft);
      break;
    case GoUp:
      set_sprite_anime (ps->sprite, SpriteDeadUp);
      break;
    case GoRight:
      set_sprite_anime (ps->sprite, SpriteDeadRight);
      break;
    default:
      set_sprite_anime (ps->sprite, SpriteDeadDown);
      break;
    }
  }
}


#ifdef __STDC__
int 
check_b_near (int x,
            int y)
#else
int 
check_b_near (x,y)
     int x,y;
#endif
{
  int player;

  for (player = 0; player < num_player; player ++) {
    if ((ABS(x*BLOCK_WIDTH - player_stat[player].x) < BLOCK_WIDTH)
      && (ABS(y*BLOCK_HEIGHT-BLOCK_HEIGHT - player_stat[player].y)  
          < BLOCK_HEIGHT)) {
      return 0;
    }
  }
  return 1;
}


#ifdef __STDC__
void 
do_all_players (int game_time, int *active_player)
#else
void 
do_all_players (game_time, active_player)
  int game_time;
  int *active_player;
#endif
{
  int p, player;
  
  /* if time is over, kill them all */
  if (game_time == (GAME_TIME - DEAD_TIME + 1)) {
    for (player = 0; player < num_player; player ++) {
      if (player_stat[player].lives>0) {
      player_stat[player].lives = 1;
      player_stat[player].dying = DEAD_TIME;
      }
    }
  }

  /* check player status */
  for (p = 0; p <num_player; p ++) {
    /* to permute player when drawing and stunning */
    /* quick and dirty but hopefully it solves some problems */
    player = (p + game_time) % num_player;
    if (player_stat[player].lives != 0) {
      
      switch(player_stat[player].dying) {
      case 0:
      /* player is alive and ... */
      if (player_stat[player].morphed) {
        /* ... or morphed */
        do_morph(player_stat + player);
      } else if (player_stat[player].stunned) {
        /* ... and stunned */
        do_stunned(player_stat + player);
      } else {
        /* ... walks around */
        do_walk(player_stat + player, game_time);
      }
      break;
      
      case 1:
      /* try to revive player */
      revive_player(player_stat + player, active_player);
      break;
      
      default:
      /* player is dying */
      do_die(player_stat + player);
      break;
      }
    }
  }
}

#ifdef __STDC__
void
check_player_hit (void)
#else
void
check_player_hit ()
#endif
{
  int player;
  int gridx, gridy;

  for (player = 0; player < num_player; player ++) {
    gridx = (player_stat[player].x + (BLOCK_WIDTH>>1))/BLOCK_WIDTH;
    gridy = (player_stat[player].y + (BLOCK_HEIGHT>>1))/BLOCK_HEIGHT +1;
    if ((player_stat[player].lives !=0  )
      && (player_stat[player].invincible==0)
      && (player_stat[player].morphed==0)
      && (player_stat[player].dying == 0)
      && check_explosion (gridx, gridy) ) {
      player_stat[player].dying = DEAD_TIME;
    }
  }
}

/*
 * end of file player.c
 */

Generated by  Doxygen 1.6.0   Back to index