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

units.c

/***************************************************************************
    copyright            : (C) 2003 by Michael Speck
    email                : kulkanie@gmx.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "units.h"

extern SDL_Surface *img_units;
extern SDL_Sound *wav_scream1, *wav_scream2, *wav_expl3;
extern int player_score;
extern int audio_on;

Unit units_anchor;
Unit *units_tail = &units_anchor;
int unit_count = 0; /* number of active units */

int strip_blocked[STRIP_COUNT]; /* number of units in each strip; -1 means the strip is
                               not accessable */

static int pos2dir( int cx, int cy, int x, int y )
{
      int dir;
      int slope;
      
      /* Translate the problem to (0,0) and compute the direction 
       * 0-7 which is closest to (x,y) when cx,cy is the position 
       * of the observer.
       *
       * Therefore the slope is approximated as an integer
       * value multiplied by 100 thus the borders for the 45 degree
       * segments have a slope of 241 (upper border at 67,5 deg) and 
       * 41 (lower border at 22,5 deg) in the 1. quadrant for the segement 
       * with direction1. As to the symmetry all other segments are 
       * handled analouge.
       */
      
      x -= cx; y -= cy;
      if ( x == 0 && y == 0 ) return 0;
      if ( x == 0 ) slope = (y>0)?300:-300; /* prevent floating point exception */
      else          slope = 100 * y / x;
      if ( x >= 0 ) {
            if ( y < 0 ) {
                  /* 1. quadrant */
                  if ( slope < -241 ) return 0; else 
                  if ( slope >  -41 ) return 2; else 
                                      return 1;
            } else {
                  /* 2.quadrant */
                  if ( slope <   41 ) return 2; else
                  if ( slope >  241 ) return 4; else
                                  return 3;
            }
      } else {
            if ( y >= 0 ) {
                  /* 3. quadrant */
                  if ( slope < -241 ) return 4; else
                  if ( slope >  -41 ) return 6; else
                                  return 5;
            } else {
                  /* 4. quadrant */
                  if ( slope <   41 ) return 6; else
                  if ( slope >  241 ) return 0; else
                                  return 7;
            }
      }
      return dir;
}

static void unit_add( Unit *unit )
{
      units_tail->next = unit;
      unit->prev = units_tail;
      units_tail = unit;
      
      unit_count++;
}

static void unit_delete( Unit *unit )
{
      /* each unit has a previous one as we use an anchor which may not be deleted */
      if ( unit == &units_anchor ) return;
      unit->prev->next = unit->next;
      
      if ( unit->next ) 
            unit->next->prev = unit->prev;
      else
            units_tail = unit->prev;
      
      free( unit );

      unit_count--;
}

static Unit* unit_create_basic(
            int type,
            SDL_Surface *img, int img_xoff, int img_yoff, int w, int h,
            int frame_count, double frame_change, double speed, Vector *pos )
{
      Unit *unit = calloc( 1, sizeof( Unit ) );

      if ( unit == 0 ) { printf( "out of memory\n" ); return 0; }
      
      unit->alive = 1;
      unit->type = type;
      unit->img = img; 
      unit->img_x_offset = img_xoff; unit->img_y_offset = img_yoff;
      unit->w = w; unit->h = h;
      unit->frame_count = frame_count;
      unit->frame_change = frame_change;
      unit->speed = speed;
      unit->pos = *pos;
      
      return unit;
}

void units_draw( SDL_Surface *dest, int camera_x, int camera_y )
{
      SDL_Rect srect, drect;
      Unit *unit = units_anchor.next;

      while ( unit ) {
            /* add in camera check? */
            
            srect.x = unit->img_x_offset + (int)unit->frame*unit->w;
            srect.y = unit->img_y_offset + unit->frame_y_offset;
            drect.x = unit->pos.x - camera_x; drect.y = unit->pos.y - camera_y;
            srect.w = drect.w = unit->w;
            srect.h = drect.h = unit->h;
            SDL_BlitSurface( unit->img, &srect, dest, &drect );

            unit = unit->next;
      }
}

void units_update( int ms )
{
      Unit *unit = units_anchor.next, *next;
      
      while ( unit ) {
            /* dead? */
            if ( !unit->alive ) {
                  if ( unit->move_time ) {
                        unit->move_time -= ms; /* used as wrack time */
                        if ( unit->move_time <= 0 ) {
                              next = unit->next;
                              unit_delete( unit );
                              unit = next;
                              continue;
                        }
                  }
                  unit = unit->next;
                  continue;
            }
            
            /* move */
            if ( unit->move_time > 0 ) {
                  /* animate */
                  if ( unit->type == UT_SOLDIER ) {
                        unit->frame += unit->frame_change * ms;
                        if ( unit->frame >= unit->frame_count ) {
                              unit->frame = 1; /* start at the beginning, frame 0
                                              is standing unit */
                        }
                  }

                  /* position */
                  unit->pos.x += unit->dir.x * ms;
                  unit->pos.y += unit->dir.y * ms;
                  unit->pos.z += unit->dir.z * ms;
                  unit->move_time -= ms;
                  if ( unit->move_time <= 0 ) {
                        /* stop */
                        unit->move_time = 0;
                        unit->frame = 0;
                        /* units that stop at the moment are saved */
                        switch ( unit->type ) {
                              case UT_SOLDIER:
                                    player_score += SCORE_HUMAN_SAVE;
                                    break;
                              case UT_TANK:
                                    player_score += SCORE_TANK_SAVE;
                                    strip_blocked[unit->strip_id] = 0;
                                    break;
                              case UT_RECON:
                                    player_score += SCORE_RECON_SAVE;
                                    strip_blocked[unit->strip_id] = 0;
                                    break;
                        }
                        next = unit->next;
                        unit_delete( unit );
                        unit = next;
                        continue;
                  }
            }
            
            unit = unit->next;
      }

}

void unit_start_move( Unit *unit, Vector *dest )
{
      double len;
      
      unit->dest = *dest;
      unit->dir.x = dest->x - unit->pos.x;
      unit->dir.y = dest->y - unit->pos.y;
      unit->dir.z = 0;
      len = sqrt(unit->dir.x*unit->dir.x + unit->dir.y*unit->dir.y);
      unit->move_time = len / unit->speed;
      len /= unit->speed;
      unit->dir.x /= len; unit->dir.y /= len;

      if ( unit->type == UT_SOLDIER )
            unit->frame_y_offset = 
                  unit->h * pos2dir( unit->pos.x, unit->pos.y, dest->x, dest->y );
      
      /* animation starts at frame 1 as frame 0 is the standing figure */
      if ( unit->type == UT_SOLDIER )
            unit->frame = 1;
}

void units_delete()
{
      while ( units_anchor.next )
            unit_delete( units_anchor.next );
}

void units_add_soldier( int strip_id, int x, int y, int move_up )
{
      Unit *unit;
      Vector pos, dest;
      
      pos.x = STRIP_OFFSET + strip_id * STRIP_SIZE + x; pos.y = y; pos.z = 0;
      unit = unit_create_basic( 
                  UT_SOLDIER, 
                  img_units, 0, 0, 12, 12, 5, 0.006, 0.012, &pos );
      if ( !unit ) return;
      unit->frame_y_offset = move_up?0:(unit->h*4);
      unit->hx = 5; unit->hy = 9;
      unit_add( unit );

      dest.x = unit->pos.x; dest.y = move_up?-20:480;
      unit_start_move( unit, &dest );
}

void units_add_dummy_tank( int strip_id, int x, int y, int speed )
{
      Vector pos, dest;
      Unit *unit;
      
      pos.x = STRIP_OFFSET + strip_id * STRIP_SIZE + x; pos.y = y; pos.z = 0;
      unit = unit_create_basic( 
                  UT_TANK, 
                  img_units, 0, 128, 13, 22, 1, 0.0, (double)speed/1000, &pos );
      if ( unit == 0 ) return;
      unit->strip_id = strip_id; strip_blocked[strip_id] = 1;
      unit->hx = 5; unit->hy = 13;
      unit->armor = 30;
      unit_add( unit );

      dest.x = pos.x; dest.y = -40;
      unit_start_move( unit, &dest );
}

void units_add_dummy_recon( int strip_id, int x, int y, int speed )
{
      Vector pos, dest;
      Unit *unit;
      
      pos.x = STRIP_OFFSET + strip_id * STRIP_SIZE + x; pos.y = y; pos.z = 0;
      unit = unit_create_basic( 
                  UT_RECON, 
                  img_units, 13, 128, 12, 18, 1, 0.0, (double)speed/1000, &pos );
      if ( unit == 0 ) return;
      unit->strip_id = strip_id; strip_blocked[strip_id] = 1;
      unit->hx = 5; unit->hy = 10;
      unit->armor = 12;
      unit_add( unit );

      dest.x = pos.x; dest.y = 480;
      unit_start_move( unit, &dest );
}

void units_check_impact( int x, int y, int radius )
{
      Unit *unit = units_anchor.next;
      Unit *next;
      
      while ( unit ) {
            if ( unit->alive )
            if ( DIST(x,y,unit->pos.x+unit->hx,unit->pos.y+unit->hy) <= (radius-unit->armor) ) {
                  if ( unit->type == UT_SOLDIER ) {
                        particles_explode_human( 
                                    unit->pos.x+unit->hx,
                                    unit->pos.y+unit->hy, 
                                    x,y );
                        if ( rand() % 2 ) {
                              if ( rand() % 2 ) {
                                    SDL_PlaySound( wav_scream1 );
                              }
                              else {
                                    SDL_PlaySound( wav_scream2 );
                              }
                        }
                        next = unit->next;
                        unit_delete( unit );
                        unit = next;
                        player_score += SCORE_HUMAN_HIT;
                        continue;
                  } else {
                        particles_add_emitter( PT_FIRE, 
                                    unit->pos.x+unit->hx,unit->pos.y+unit->hy,
                                    3,
                                    0.05,
                                    WRACK_TIME );
                        SDL_PlaySound( wav_expl3 );
                        unit->alive = 0;
                        unit->move_time = WRACK_TIME;
                        if ( unit->type == UT_TANK )
                              player_score += SCORE_TANK_HIT;
                        else
                              player_score += SCORE_RECON_HIT;
                        strip_blocked[unit->strip_id] = 0;
                  }
            }
            
            unit = unit->next;
      }
}

/* return id of a free strip */
int units_get_rand_strip( int type )
{
      int i, start;
      
      /* soldiers may walk in strips with uneven numbers */
      if ( type == UT_SOLDIER ) {
            i = rand() % STRIP_COUNT; 
            if ( !(i&1) ) i++;
            while ( strip_blocked[i] ) {
                  i += 2;
                  if ( i >= STRIP_COUNT )
                        i = 1;
            }
            return i;
      }
      
      /* tanks may drive in even numbered strips */
      i = rand() % STRIP_COUNT; 
      if ( i&1) i--;
      start = i;
      while ( strip_blocked[i] ) {
            i+=2; if ( i >= STRIP_COUNT ) i = 0;
            if ( i == start ) return -1; /* dont loop endlessly */
      }
      return i;
}

/* return a random vehicle that is in the screen or 0 if no available */
Unit *units_get_first_vehicle()
{
      Unit *unit = units_anchor.next;

      while ( unit ) {
            if ( unit->type != UT_SOLDIER )
            if ( unit->alive )
            if ( unit->pos.y > 0 && unit->pos.y < 470 )
                  return unit;
            unit = unit->next;
      }

      return 0;
}

/* return first soldier that is in the screen or 0 if no available */
Unit *units_get_first_soldier()
{
      Unit *unit = units_anchor.next;

      while ( unit ) {
            if ( unit->type == UT_SOLDIER )
            if ( unit->alive )
            if ( unit->pos.y > 0 && unit->pos.y < 470 )
                  return unit;
            unit = unit->next;
      }

      return 0;
}




Generated by  Doxygen 1.6.0   Back to index