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

shots.c

/***************************************************************************
    copyright            : (C) 2003 by Michael Speck
    email                : http://lgames.sf.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 "defs.h"
#include "units.h"
#include "shots.h"

extern SDL_Surface *screen;
extern SDL_Surface *img_shots;

Shot shots_anchor;
Shot *shots_tail = &shots_anchor;

static Vector grav = { 0, 0, -GRAV }; /* for all projectiles that are influenced by gravity */
static void (*impact_handler)(Shot *shot) = 0;

/* used by other modules as well */
void vec2xy( Vector *v, int *sx, int *sy )
{
      /* convert to screen */
      *sx = (int)v->x;
      *sy = (int)v->y - (((int)v->z)>>1);
}

static void shot_add( Shot *shot )
{
      shots_tail->next = shot;
      shot->prev = shots_tail;
      shots_tail = shot;
}

static void shot_delete( Shot *shot )
{
      /* each shot has a previous one as we use an anchor which may not be deleted */
      if ( shot == &shots_anchor ) return;
      shot->prev->next = shot->next;
      
      if ( shot->next ) 
            shot->next->prev = shot->prev;
      else
            shots_tail = shot->prev;

      free( shot );
}

void shots_draw( SDL_Surface *dest, int camera_x, int camera_y )
{
      int sx, sy;
      SDL_Rect srect, drect;
      Shot *shot = shots_anchor.next;

      while ( shot ) {
            vec2xy( &shot->pos, &sx, &sy );
            /* add in camera check? */
            
            /* the position refers to the center of of the projectile
             * but we have to start drawing at the upper left pixel */
            sx -= shot->w>>1;
            sy -= shot->h>>1; /* center */
            
            /* projectile */
            srect.x = shot->img_x_offset;
            srect.y = shot->img_y_offset;
            drect.x = sx - camera_x; drect.y = sy - camera_y;
            srect.w = drect.w = shot->w;
            srect.h = drect.h = shot->h;
            SDL_SetAlpha( shot->img, 0, 0 );
            SDL_BlitSurface( shot->img, &srect, dest, &drect );

            /* shadow */
            if ( shot->with_shadow ) {
                  srect.x = shot->img_x_offset;
                  srect.y = shot->img_y_offset + shot->h;
                  drect.x = shot->pos.x - (shot->w>>1); 
                  drect.x += ((int)shot->pos.z)>>3;
                  drect.y = shot->pos.y - (shot->h>>1);
                  srect.w = drect.w = shot->w;
                  srect.h = drect.h = shot->h;
                  SDL_SetAlpha( shot->img, SDL_SRCALPHA, 128 );
                  SDL_BlitSurface( shot->img, &srect, dest, &drect );
            }
            
            shot = shot->next;
      }
}

void shots_update( int ms )
{
      int i;
      Shot *shot = shots_anchor.next, *next;

      while ( shot ) {
            /* update position at ground */
            shot->pos.x += shot->dir.x * ms;
            shot->pos.y += shot->dir.y * ms;
            /* as we approach the projectile curve by vectors
             * the frame rate is essentially for the accuracy of the
             * height as with each call the tangential speed vector
             * is added which is instantly out of sync due to
             * a non-linear movement */
            for ( i = 0; i < ms; i++ ) {
                  shot->pos.z += shot->dir.z;
                  shot->dir.z += grav.z; /* apply gravity */
            }
                  
            
            if ( shot->dir.z < 0 ) /* must be coming down */
            if ( shot->pos.z <= shot->dest.z ) {
                  shot->pos.z = shot->dest.z;
                  if ( impact_handler )
                        impact_handler( shot );
                  next = shot->next;
                  shot_delete( shot );
                  shot = next;
                  continue;
            }
      
            shot = shot->next;
      }
}

void shots_delete()
{
      while ( shots_anchor.next )
            shot_delete( shots_anchor.next );
}

void shots_set_impact_handler( void (*callback)(Shot* shot) )
{
      impact_handler = callback;
}

void shots_fire_ballistic(
            int type,
            SDL_Surface *img, int img_xoff, int img_yoff, int w, int h,
            Vector *src, Vector *dest, double alpha, double power )
{
      double len, height, r;
      Shot *shot = calloc( 1, sizeof( Shot ) );

      if ( shot == 0 ) { printf( "out of memory\n" ); return; }

      /* graphics and type */
      shot->type = type;
      if ( img == 0 ) 
            shot->img = img_shots;
      else
            shot->img = img; 
      shot->img_x_offset = img_xoff; shot->img_y_offset = img_yoff;
      shot->w = w; shot->h = h;
      shot->with_shadow = 1;

      /* convert alpha from degree to radiant */
      alpha = 3.14 * alpha / 180;
      
      /* position and destination */
      shot->pos = *src;
      shot->dest = *dest;

      shot->dir.x = dest->x - src->x; shot->dir.y = dest->y - src->y; 
      len = sqrt(shot->dir.x*shot->dir.x + shot->dir.y*shot->dir.y);
      height = dest->z - src->z;
      if ( power == 0 ) { 
            /* if not specified compute by angle and hit destination exactly */
            r = -0.5 * GRAV / ( height - len * tan(alpha) );
            if ( r < 0 ) {
                  printf( "impossible movement for ballistic projectile!\n" );
                  free( shot );
                  return;
            }
            else {
                  power = sqrt(r) * len / cos(alpha);
                  shot->is_precise = 1;
            }
      }
      shot->dir.z = len * tan(alpha);
      len = sqrt(shot->dir.x*shot->dir.x + shot->dir.y*shot->dir.y + shot->dir.z*shot->dir.z);
      shot->dir.x /= len; shot->dir.y /= len; shot->dir.z /= len;
      shot->dir.x *= power; shot->dir.y *= power; shot->dir.z *= power;
      
      shot_add( shot );
}



Generated by  Doxygen 1.6.0   Back to index