commit a97a9b50042dfad9bd08a3b67727d992cffd485e Author: sam Date: Fri Dec 13 19:23:07 2002 +0000 * First commit. Scrolling works, some weaponry, controls, tunnel blowing, the nuke is still ugly, almost no collision detection. Nice demo :) git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/ttyvaders/trunk@12 92316355-f0b4-4df1-b90c-862c8a59935f diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..15a46c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ + +# Fallback to ncurses if this is set to 0 +USE_SLANG = 1 + +CC = gcc +CFLAGS = -g -O6 -fno-strength-reduce -fomit-frame-pointer + +# Code qui fait des warnings == code de porc == deux baffes dans ta gueule +CFLAGS += -Wall -Wpointer-arith -Wcast-align -Wcast-qual -Wstrict-prototypes -Wshadow -Waggregate-return -Wmissing-prototypes -Wnested-externs + +ifeq (1,$(USE_SLANG)) +CFLAGS += -DUSE_SLANG +EXECLIBS = -lslang -lm +else +CFLAGS += -DUSE_NCURSES +EXECLIBS = -lncurses -lm +endif + +COMPILE_CMD = $(CC) -c $(ALL_CFLAGS) + +PROGRAM = ttyvaders +SOURCES = main.c graphics.c tunnel.c starfield.c player.c weapons.c collide.c explosions.c aliens.c +HEADERS = common.h +OBJECTS = $(SOURCES:%.c=%.o) + +all: $(PROGRAM) + +ttyvaders: $(OBJECTS) + $(CC) -o $@ $(LDFLAGS) $^ $(EXECLIBS) + +$(OBJECTS): Makefile $(HEADERS) + +clean: + -/bin/rm -f $(PROGRAM) $(OBJECTS) + diff --git a/aliens.c b/aliens.c new file mode 100644 index 0000000..bf5eec8 --- /dev/null +++ b/aliens.c @@ -0,0 +1,176 @@ + +#include + +#include "common.h" + +static void draw_alien( game *g, int x, int y, int type ); + +void init_aliens( game *g, aliens *al ) +{ + int i; + + for( i = 0; i < ALIENS; i++ ) + { + al->x[i] = -1; + al->y[i] = -1; + al->img[i] = 0; + al->life[i] = 0; + } +} + +void draw_aliens( game *g, aliens *al ) +{ + int i; + + for( i = 0; i < ALIENS; i++ ) + { + if( al->y[i] >= 0 ) + { + draw_alien( g, al->x[i], al->y[i], al->img[i] % 2 ); + } + } +} + +void update_aliens( game *g, aliens *al ) +{ + int i; + + for( i = 0; i < ALIENS; i++ ) + { + if( al->y[i] < 0 ) + { + //al->x[i] = g->w; + } + else + { + al->x[i] = ((al->x[i] + 5) % (g->w + 3)) - 3; + al->y[i] = al->y[i] + (rand() % 8) / 7 - (rand() % 8) / 7; + al->img[i] = al->img[i] + rand() % 4; + + /* Check collisions */ + if( al->y[i] < 0 ) al->y[i] = 0; + if( al->y[i] > g->w - 1 ) al->y[i] = g->w - 1; + } + } +} + +void add_alien( game *g, aliens *al, int x, int y ) +{ + int i; + + for( i = 0; i < ALIENS; i++ ) + { + if( al->y[i] < 0 ) + { + al->x[i] = x; + al->y[i] = y; + al->img[i] = 0; + al->life[i] = 2; + break; + } + } +} + +static void draw_alien( game *g, int x, int y, int type ) +{ + switch( type ) + { + case 0: + GFX_COLOR( MAGENTA ); + GFX_GOTO( x, y ); + GFX_WRITE( ',' ); + GFX_WRITE( '-' ); + GFX_WRITE( '-' ); + GFX_WRITE( '-' ); + GFX_WRITE( '.' ); + GFX_GOTO( x, y+1 ); + GFX_WRITE( '\\' ); + GFX_COLOR( WHITE ); + GFX_WRITE( 'o' ); + GFX_WRITE( ' ' ); + GFX_WRITE( 'O' ); + GFX_COLOR( MAGENTA ); + GFX_WRITE( '/' ); + GFX_GOTO( x, y+2 ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + break; + case 1: + GFX_COLOR( MAGENTA ); + GFX_GOTO( x, y ); + GFX_WRITE( ',' ); + GFX_WRITE( '-' ); + GFX_WRITE( '-' ); + GFX_WRITE( '-' ); + GFX_WRITE( '.' ); + GFX_GOTO( x, y+1 ); + GFX_WRITE( '\\' ); + GFX_COLOR( WHITE ); + GFX_WRITE( 'O' ); + GFX_WRITE( ' ' ); + GFX_WRITE( 'o' ); + GFX_COLOR( MAGENTA ); + GFX_WRITE( '/' ); + GFX_GOTO( x, y+2 ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + GFX_WRITE( '^' ); + break; + } +} + +#if 0 +void draw_rock( int x, int y, int type ) +{ + switch( type ) + { + case 0: + GFX_COLOR( RED ); + GFX_GOTO( x, y ); + GFX_WRITE( '/' ); + GFX_WRITE( '\\' ); + GFX_WRITE( '_' ); + GFX_WRITE( '/' ); + GFX_WRITE( '\\' ); + GFX_GOTO( x, y+1 ); + GFX_WRITE( '>' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '/' ); + GFX_GOTO( x, y+2 ); + GFX_WRITE( '\\' ); + GFX_WRITE( '/' ); + GFX_WRITE( '\\' ); + GFX_WRITE( '_' ); + GFX_WRITE( '>' ); + break; + case 1: + GFX_COLOR( RED ); + GFX_GOTO( x, y ); + GFX_WRITE( '_' ); + GFX_WRITE( '/' ); + GFX_WRITE( '\\' ); + GFX_WRITE( '/' ); + GFX_WRITE( '>' ); + GFX_GOTO( x, y+1 ); + GFX_WRITE( '\\' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '\\' ); + GFX_GOTO( x, y+2 ); + GFX_WRITE( '<' ); + GFX_WRITE( '_' ); + GFX_WRITE( '/' ); + GFX_WRITE( '\\' ); + GFX_WRITE( '/' ); + break; + } +} +#endif diff --git a/collide.c b/collide.c new file mode 100644 index 0000000..85c1411 --- /dev/null +++ b/collide.c @@ -0,0 +1,121 @@ + +#include + +#include "common.h" + +void collide_weapons_tunnel( game *g, weapons *wp, tunnel *t, explosions *ex ) +{ + int i; + + for( i = 0; i < SHOTS; i++ ) + { + if( wp->y[i] >= 0 ) + { + if( wp->x[i] <= t->left[wp->y[i]+1] + || wp->x[i] >= t->right[wp->y[i]+1] ) + { + add_explosion( g, ex, wp->x[i], wp->y[i]+1, 0, 1, 0 ); + + if( wp->x[i] <= t->left[wp->y[i]+1] ) + { + t->left[wp->y[i]]--; + t->left[wp->y[i]+1]-=2; + t->left[wp->y[i]+2]--; + } + else + { + t->right[wp->y[i]]++; + t->right[wp->y[i]+1]+=2; + t->right[wp->y[i]+2]++; + } + + wp->y[i] = -1; + } + else if( wp->x[i] <= t->left[wp->y[i]] + || wp->x[i] >= t->right[wp->y[i]] ) + { + add_explosion( g, ex, wp->x[i], wp->y[i], 0, 1, 0 ); + + if( wp->x[i] <= t->left[wp->y[i]] ) + { + t->left[wp->y[i]-1]--; + t->left[wp->y[i]]-=2; + t->left[wp->y[i]+1]--; + } + else + { + t->right[wp->y[i]-1]++; + t->right[wp->y[i]]+=2; + t->right[wp->y[i]+1]++; + } + + wp->y[i] = -1; + } + } + } +} + +void collide_weapons_aliens( game *g, weapons *wp, aliens *al, explosions *ex ) +{ + int i, j; + + for( i = 0; i < SHOTS; i++ ) + { + if( wp->y[i] >= 0 ) + { + int ok = 0; + + for( j = 0; j < ALIENS; j++ ) + { + if( wp->x[i] >= al->x[j] + && wp->x[i] <= al->x[j] + 4 + && wp->y[i] >= al->y[j] + && wp->y[i] <= al->y[j] + 2 ) + { + al->life[j]--; + if( al->life[j] == 0 ) + { + al->x[j] = -1; + al->y[j] = -1; + add_explosion( g, ex, wp->x[i], wp->y[i], 0, 0, 1 ); + } + ok = 1; + } + else if( wp->x[i] >= al->x[j] + && wp->x[i] <= al->x[j] + 4 + && wp->y[i]+1 >= al->y[j] + && wp->y[i]+1 <= al->y[j] + 2 ) + { + al->life[j]--; + if( al->life[j] == 0 ) + { + al->x[j] = -1; + al->y[j] = -1; + add_explosion( g, ex, wp->x[i], wp->y[i]+1, 0, 0, 1 ); + } + ok = 1; + } + } + + if( ok ) + { + wp->y[i] = -1; + } + } + } +} + +void collide_player_tunnel( game *g, player *p, tunnel *t, explosions *ex ) +{ + if( p->x <= t->left[p->y] ) + { + p->x += 3; + //add_explosion( g, ex, x+1, y-2, 0, 1, 0 ); + } + else if( p->x + 5 >= t->right[p->y] ) + { + p->x -= 3; + //add_explosion( g, ex, x+4, y-2, 0, 1, 0 ); + } +} + diff --git a/common.h b/common.h new file mode 100644 index 0000000..12ea864 --- /dev/null +++ b/common.h @@ -0,0 +1,130 @@ + +#define STARS 50 +#define SHOTS 50 +#define ROCKS 10 +#define ALIENS 10 +#define EXPLOSIONS 20 + +#ifdef USE_SLANG +# include +# define GFX_COLOR(x) SLsmg_set_color(x) +# define GFX_GOTO(x,y) SLsmg_gotorc(y,x) +# define GFX_WRITE(x) SLsmg_write_char(x) +#else +# include +# define GFX_COLOR(x) attrset(COLOR_PAIR(x)) +# define GFX_GOTO(x,y) move(y,x) +# define GFX_WRITE(x) addch(x) +#endif + +#define GET_RAND(p,q) ((p)+(int)((1.0*((q)-(p)))*rand()/(RAND_MAX+1.0))) + +typedef struct +{ + int w, h; + +} game; + +typedef struct +{ + int w, h, *left, *right; + +} tunnel; + +typedef struct +{ + int x[STARS]; + int y[STARS]; + int z[STARS]; + char ch[STARS]; + int c[STARS]; + +} starfield; + +typedef struct +{ + int x[EXPLOSIONS]; + int y[EXPLOSIONS]; + int vx[EXPLOSIONS]; + int vy[EXPLOSIONS]; + int type[EXPLOSIONS]; + int n[EXPLOSIONS]; + +} explosions; + +typedef struct +{ + int x[SHOTS]; + int y[SHOTS]; + int v[SHOTS]; + +} weapons; + +typedef struct +{ + int x, y; + int dir; + int weapon; + +} player; + +typedef struct +{ + int x[ALIENS]; + int y[ALIENS]; + int life[ALIENS]; + int img[ALIENS]; + +} aliens; + +#define BLACK 1 +#define GREEN 2 +#define YELLOW 3 +#define WHITE 4 +#define RED 5 +#define GRAY 6 +#define LIGHTGRAY 7 +#define BLUE 8 +#define CYAN 9 +#define MAGENTA 10 + +void collide_weapons_tunnel( game *g, weapons *wp, tunnel *t, explosions *ex ); +void collide_weapons_aliens( game *g, weapons *wp, aliens *al, explosions *ex ); +void collide_player_tunnel( game *g, player *p, tunnel *t, explosions *ex ); + +void init_aliens( game *g, aliens *al ); +void draw_aliens( game *g, aliens *al ); +void update_aliens( game *g, aliens *al ); +void add_alien( game *g, aliens *al, int x, int y ); + +int init_graphics( void ); +void init_game( game *g ); +char get_key( void ); +void clear_graphics( void ); +void refresh_graphics( void ); +void end_graphics( void ); + +player * create_player( game *g ); +void free_player( player *p ); +void draw_player( game *g, player *p ); +void update_player( game *g, player *p ); + +void init_weapons( game *g, weapons *wp ); +void draw_weapons( game *g, weapons *wp ); +void update_weapons( game *g, weapons *wp ); +void add_weapon( game *g, weapons *wp, int x, int y ); + +void init_starfield( game *g, starfield *s ); +void draw_starfield( game *g, starfield *s ); +void update_starfield( game *g, starfield *s ); + +tunnel * create_tunnel( game *g, int w, int h ); +void free_tunnel( tunnel *t ); +void draw_tunnel( game *g, tunnel *t ); +void update_tunnel( game *g, tunnel *t ); + +void init_explosions( game *g, explosions *ex ); +void add_explosion( game *g, explosions *ex, int x, int y, int vx, int vy, int type ); +void draw_explosions( game *g, explosions *ex ); +void update_explosions( game *g, explosions *ex ); + diff --git a/explosions.c b/explosions.c new file mode 100644 index 0000000..c6fcd99 --- /dev/null +++ b/explosions.c @@ -0,0 +1,405 @@ + +#include +#include + +#include "common.h" + +static void draw_small_explosion( int x, int y, int frame ); +static void draw_big_explosion( int x, int y, int frame ); +static void draw_huge_explosion( int x, int y, int frame ); + +void init_explosions( game *g, explosions *ex ) +{ + int i; + + for( i = 0; i < EXPLOSIONS; i++ ) + { + ex->n[i] = 0; + ex->x[i] = -1; + ex->y[i] = -1; + ex->vx[i] = -1; + ex->vy[i] = -1; + ex->type[i] = 0; + } +} + +void add_explosion( game *g, explosions *ex, int x, int y, int vx, int vy, int type ) +{ + int i; + + for( i = 0; i < EXPLOSIONS; i++ ) + { + if( ex->n[i] <= 0 ) + { + ex->x[i] = x; + ex->y[i] = y; + ex->vx[i] = vx; + ex->vy[i] = vy; + switch( type ) + { + case 1: ex->n[i] = 13; break; + case 2: ex->n[i] = 30; break; + case 0: default: ex->n[i] = 7; break; + } + ex->type[i] = type; + break; + } + } +} + +void draw_explosions( game *g, explosions *ex ) +{ + int i; + + for( i = 0; i < EXPLOSIONS; i++ ) + { + if( ex->n[i] <= 0 ) + { + continue; + } + +#if 0 + GFX_COLOR( GREEN ); + GFX_GOTO( ex->x[i] + 3, ex->y[i] ); + switch( GET_RAND(0,3) ) + { + case 0: + GFX_WRITE( 'p' ); + GFX_WRITE( 'i' ); + GFX_WRITE( 'f' ); + break; + case 1: + GFX_WRITE( 'p' ); + GFX_WRITE( 'a' ); + GFX_WRITE( 'f' ); + break; + case 2: + GFX_WRITE( 'p' ); + GFX_WRITE( 'o' ); + GFX_WRITE( 'u' ); + GFX_WRITE( 'f' ); + break; + } + GFX_WRITE( '!' ); +#endif + + switch( ex->type[i] ) + { + case 2: + draw_huge_explosion( ex->x[i], ex->y[i], ex->n[i] ); + break; + case 1: + draw_big_explosion( ex->x[i], ex->y[i], ex->n[i] ); + break; + case 0: + default: + draw_small_explosion( ex->x[i], ex->y[i], ex->n[i] ); + break; + } + + } +} + +void update_explosions( game *g, explosions *ex ) +{ + int i; + + for( i = 0; i < EXPLOSIONS; i++ ) + { + if( ex->n[i] > 0 ) + { + ex->x[i] += ex->vx[i]; + ex->y[i] += ex->vy[i]; + ex->n[i]--; + } + } +} + +static void draw_small_explosion( int x, int y, int frame ) +{ + switch( frame ) + { + default: + case 6: + GFX_COLOR( YELLOW ); + GFX_GOTO( x, y ); + GFX_WRITE( '+' ); + break; + case 5: + GFX_COLOR( YELLOW ); + GFX_GOTO( x, y ); + GFX_WRITE( 'o' ); + break; + case 4: + GFX_COLOR( YELLOW ); + GFX_GOTO( x, y-1 ); + GFX_WRITE( '_' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( ')' ); + GFX_WRITE( '_' ); + GFX_WRITE( '(' ); + break; + case 3: + GFX_COLOR( YELLOW ); + GFX_GOTO( x-1, y-1 ); + GFX_WRITE( '.' ); + GFX_WRITE( '_' ); + GFX_WRITE( ',' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( ')' ); + GFX_WRITE( '_' ); + GFX_WRITE( '(' ); + GFX_GOTO( x-1, y+1 ); + GFX_WRITE( '\'' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '`' ); + break; + case 2: + GFX_COLOR( YELLOW ); + GFX_GOTO( x-1, y-1 ); + GFX_WRITE( '.' ); + GFX_WRITE( 'v' ); + GFX_WRITE( ',' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( '>' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '<' ); + GFX_GOTO( x-1, y+1 ); + GFX_WRITE( '\'' ); + GFX_WRITE( '^' ); + GFX_WRITE( '`' ); + break; + case 1: + GFX_COLOR( WHITE ); + GFX_GOTO( x-1, y-1 ); + GFX_WRITE( '.' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ',' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_GOTO( x-1, y+1 ); + GFX_WRITE( '\'' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '`' ); + break; + } +} + +static void draw_big_explosion( int x, int y, int frame ) +{ + GFX_COLOR( YELLOW ); + + switch( frame ) + { + default: + case 12: + GFX_GOTO( x, y ); + GFX_WRITE( '+' ); + break; + case 11: + GFX_GOTO( x, y ); + GFX_WRITE( 'o' ); + break; + case 10: + GFX_GOTO( x, y-1 ); + GFX_WRITE( '_' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( ')' ); + GFX_WRITE( '_' ); + GFX_WRITE( '(' ); + break; + case 9: + GFX_GOTO( x-1, y-1 ); + GFX_WRITE( '.' ); + GFX_WRITE( '_' ); + GFX_WRITE( ',' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( ')' ); + GFX_WRITE( '_' ); + GFX_WRITE( '(' ); + GFX_GOTO( x-1, y+1 ); + GFX_WRITE( '\'' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '`' ); + break; + case 8: + GFX_GOTO( x-1, y-1 ); + GFX_WRITE( '.' ); + GFX_WRITE( 'v' ); + GFX_WRITE( ',' ); + GFX_GOTO( x-1, y ); + GFX_WRITE( '>' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '<' ); + GFX_GOTO( x-1, y+1 ); + GFX_WRITE( '\'' ); + GFX_WRITE( '^' ); + GFX_WRITE( '`' ); + break; + case 6: + GFX_COLOR( RED ); + case 7: + case 5: + GFX_GOTO( x-2, y-1 ); + GFX_WRITE( '_' ); + GFX_WRITE( '\\' ); + GFX_WRITE( '~' ); + GFX_WRITE( '/' ); + GFX_WRITE( '_' ); + GFX_GOTO( x-2, y ); + GFX_WRITE( '>' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '<' ); + GFX_GOTO( x-2, y+1 ); + GFX_WRITE( '~' ); + GFX_WRITE( '/' ); + GFX_WRITE( '_' ); + GFX_WRITE( '\\' ); + GFX_WRITE( '~' ); + break; + case 3: + GFX_COLOR( RED ); + case 4: + case 2: + GFX_GOTO( x-2, y-1 ); + GFX_WRITE( '_' ); + GFX_WRITE( '\\' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '/' ); + GFX_WRITE( '_' ); + GFX_GOTO( x-2, y ); + GFX_WRITE( '_' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '_' ); + GFX_GOTO( x-2, y+1 ); + GFX_WRITE( ' ' ); + GFX_WRITE( '/' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '\\' ); + GFX_WRITE( ' ' ); + break; + case 1: + GFX_COLOR( WHITE ); + GFX_GOTO( x-2, y-1 ); + GFX_WRITE( '.' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '\'' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ',' ); + GFX_GOTO( x-2, y ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_WRITE( ' ' ); + GFX_GOTO( x-2, y+1 ); + GFX_WRITE( '\'' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '.' ); + GFX_WRITE( ' ' ); + GFX_WRITE( '`' ); + break; + } +} + +static void draw_circle( int x, int y, float r ); + +static void draw_huge_explosion( int x, int y, int frame ) +{ + float r = 1.5 * (30 - frame); + + GFX_COLOR( BLUE ); + draw_circle( x, y, r ); + + r += 0.7; + + GFX_COLOR( CYAN ); + draw_circle( x, y, r ); + + r += 0.7; + + GFX_COLOR( WHITE ); + draw_circle( x, y, r ); +} + +static void draw_circle( int x, int y, float r ) +{ +#if 1 + float c; + + for( c = 0 ; c <= 90 ; c += 1 ) + { + float dx = 0.5 + r * 2.0 * sin( c * M_PI / 180.0 ); + float dy = 0.5 + r * cos( c * M_PI / 180.0 ); + + GFX_GOTO( x + dx, y + dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x - dx, y + dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x + dx, y - dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x - dx, y - dy ); + GFX_WRITE( '#' ); + } +#endif + +#if 0 +int dx,dy,a2,b2, S, T; +float a = r*8, b = r*2; + + a2 = a*a; + b2 = b*b; + dx = 0; + dy = b; + S = a2*(1-2*b) + 2*b2; + T = b2 - 2*a2*(2*b-1); + GFX_GOTO( x + dx, y + dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x - dx, y + dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x + dx, y - dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x - dx, y - dy ); + GFX_WRITE( '#' ); + + do + { + if (S<0) + { + S += 2*b2*(2*x+3); + T += 4*b2*(x+1); + dx++; + } + else if (T<0) + { + S += 2*b2*(2*x+3) - 4*a2*(dy-1); + T += 4*b2*(x+1) - 2*a2*(2*dy-3); + dx++; + dy--; + } + else + { + S -= 4*a2*(dy-1); + T -= 2*a2*(2*dy-3); + dy--; + } + GFX_GOTO( x + dx, y + dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x - dx, y + dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x + dx, y - dy ); + GFX_WRITE( '#' ); + GFX_GOTO( x - dx, y - dy ); + GFX_WRITE( '#' ); + } + while (dy>0); +#endif + +} + diff --git a/graphics.c b/graphics.c new file mode 100644 index 0000000..ac7d4b7 --- /dev/null +++ b/graphics.c @@ -0,0 +1,129 @@ + +#include + +#include "common.h" + +int init_graphics( void ) +{ +#ifdef USE_SLANG + /* Initialize slang library */ + SLsig_block_signals(); + SLtt_get_terminfo(); + + if( SLkp_init() == -1 ) + { + SLsig_unblock_signals(); + return 1; + } + + SLang_init_tty (-1, 0, 1); + + if( SLsmg_init_smg() == -1 ) + { + SLsig_unblock_signals(); + return 1; + } + + SLsig_unblock_signals(); + + SLsmg_cls(); + SLsmg_refresh(); +#else + /* Initialize ncurses library */ + initscr(); + keypad(stdscr, TRUE); + nonl(); + cbreak(); + noecho(); + nodelay(stdscr, TRUE); +#endif + + return 0; +} + +void init_game( game *g ) +{ +#ifdef USE_SLANG + static char * const colors[] = + { + "black", "green", "yellow", "white", + "red", "gray", "lightgray", "blue", "cyan", "magenta", NULL + }; + + int i; + + for( i = 0; colors[i] ; i++ ) + { + SLtt_set_color( i+1, NULL, colors[i], "black" ); + } + + g->w = SLtt_Screen_Cols; + g->h = SLtt_Screen_Rows; +#else + start_color(); + + init_pair( BLACK, COLOR_BLACK, COLOR_BLACK ); + init_pair( GREEN, COLOR_GREEN, COLOR_BLACK ); + init_pair( YELLOW, COLOR_YELLOW, COLOR_BLACK ); + init_pair( WHITE, COLOR_WHITE, COLOR_BLACK ); + init_pair( RED, COLOR_RED, COLOR_BLACK ); + init_pair( GRAY, COLOR_WHITE, COLOR_BLACK ); // XXX + init_pair( LIGHTGRAY, COLOR_WHITE, COLOR_BLACK ); // XXX + init_pair( BLUE, COLOR_BLUE, COLOR_BLACK ); + init_pair( CYAN, COLOR_CYAN, COLOR_BLACK ); + init_pair( MAGENTA, COLOR_MAGENTA, COLOR_BLACK ); + + g->w = COLS; + g->h = LINES; +#endif +} + +char get_key( void ) +{ +#ifdef USE_SLANG + if( SLang_input_pending (0) ) + { + return SLang_getkey(); + } +#else + char key; + + if( ( key = getch() ) != ERR ) + { + return key; + } +#endif + + return 0; +} + +void clear_graphics( void ) +{ +#ifdef USE_SLANG + SLsmg_cls(); +#else + clear(); +#endif +} + +void refresh_graphics( void ) +{ + GFX_GOTO( 0, 0 ); +#ifdef USE_SLANG + SLsmg_refresh(); +#else + refresh(); +#endif +} + +void end_graphics( void ) +{ +#ifdef USE_SLANG + SLang_reset_tty(); + SLsmg_reset_smg(); +#else + endwin(); +#endif +} + + diff --git a/main.c b/main.c new file mode 100644 index 0000000..cdeaafa --- /dev/null +++ b/main.c @@ -0,0 +1,179 @@ +/* + * ttyvaders - a tty based shoot'em'up + * Copyright (C) 2002 Sam Hocevar + * + * 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 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY 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. + * + */ + +#include +#include + +#include +#include + +#include "common.h" + +static void start_game (game *); + +int main (int argc, char **argv) +{ + game *g = malloc(sizeof(game)); + +// srand(time(NULL)); + + if( init_graphics() ) + { + return 1; + } + + /* Initialize our program */ + init_game(g); + + /* Go ! */ + start_game(g); + + /* Clean up */ + end_graphics(); + + return 0; +} + +static void start_game (game *g) +{ + int i; + int quit = 0; + int poz = 0; + int skip = 0; + + starfield *sf = malloc(sizeof(starfield)); + weapons *wp = malloc(sizeof(weapons)); + explosions *ex = malloc(sizeof(explosions)); + tunnel *t = create_tunnel( g, g->w, g->h ); + player *p = create_player( g ); + aliens *al = malloc(sizeof(aliens)); + + init_starfield( g, sf ); + init_weapons( g, wp ); + init_explosions( g, ex ); + init_aliens( g, al ); + + /* Temporary stuff */ + for( i = 0; i < 5; i++ ) + { + add_alien( g, al, rand() % g->w, rand() % g->h / 2 ); + } + t->w = 25; + + while( !quit ) + { + char key; + + while( ( key = get_key() ) ) + { + switch( key ) + { + case 'q': + quit = 1; + break; + case 'p': + poz = !poz; + break; + case 's': + skip = 1; + break; + case 'h': + p->dir = -3; + break; + case 'j': + //if( p->y < g->h - 2 ) p->y += 1; + break; + case 'k': + //if( p->y > 1 ) p->y -= 1; + break; + case 'l': + p->dir = 3; + break; + case '\r': + add_explosion( g, ex, p->x + 2, p->y, 0, 0, 2 ); + break; + case ' ': + if( p->weapon == 0 ) + { + p->weapon = 4; + add_weapon( g, wp, p->x, p->y ); + add_weapon( g, wp, p->x + 5, p->y ); + } + break; + } + } + + usleep(40000); + + if( GET_RAND(0,10) == 0 ) + { + add_alien( g, al, 0, rand() % g->h / 2 ); + } + + if( poz ) + { + if( skip ) + { + skip = 0; + } + else + { + continue; + } + } + + /* Scroll and update positions */ + collide_player_tunnel( g, p, t, ex ); + update_player( g, p ); + collide_player_tunnel( g, p, t, ex ); + + update_starfield( g, sf ); + update_aliens( g, al ); + + collide_weapons_tunnel( g, wp, t, ex ); + collide_weapons_aliens( g, wp, al, ex ); + update_weapons( g, wp ); + collide_weapons_tunnel( g, wp, t, ex ); + collide_weapons_aliens( g, wp, al, ex ); + + update_explosions( g, ex ); + update_tunnel( g, t ); + + /* Clear screen */ + clear_graphics(); + + /* Print starfield, tunnel, aliens, player and explosions */ + draw_starfield( g, sf ); + draw_tunnel( g, t ); + draw_aliens( g, al ); + draw_player( g, p ); + draw_weapons( g, wp ); + draw_explosions( g, ex ); + + /* Refresh */ + refresh_graphics(); + } + +#if 0 + free_player( p ); + free_tunnel( t ); +#endif +} + diff --git a/player.c b/player.c new file mode 100644 index 0000000..87e9f2e --- /dev/null +++ b/player.c @@ -0,0 +1,68 @@ + +#include + +#include "common.h" + +/* Init tunnel */ +player * create_player( game *g ) +{ + player *p = malloc(sizeof(player)); + + p->x = g->w / 2; + p->y = g->h - 3; + p->dir = 0; + p->weapon = 0; + + return p; +} + +void free_player( player *p ) +{ + free( p ); +} + +void draw_player( game *g, player *p ) +{ + GFX_GOTO( p->x + 2, p->y - 2 ); + GFX_COLOR( GREEN ); + GFX_WRITE( '/' ); + GFX_WRITE( '\\' ); + GFX_GOTO( p->x + 1, p->y - 1 ); + GFX_WRITE( '(' ); + GFX_COLOR( YELLOW ); + GFX_WRITE( '(' ); + GFX_WRITE( ')' ); + GFX_COLOR( GREEN ); + GFX_WRITE( ')' ); + GFX_GOTO( p->x, p->y ); + GFX_COLOR( GREEN ); + GFX_WRITE( 'I' ); + GFX_WRITE( '<' ); + GFX_WRITE( '_' ); + GFX_WRITE( '_' ); + GFX_WRITE( '>' ); + GFX_WRITE( 'I' ); +} + +void update_player( game *g, player *p ) +{ + if( p->weapon ) + { + p->weapon--; + } + + if( p->dir < 0 ) + { + if( p->dir == -3 && p->x > -2 ) p->x -= 1; + else if( p->x > -1 ) p->x -= 1; + + p->dir++; + } + else if( p->dir > 0 ) + { + if( p->dir == 3 && p->x < g->w - 8 ) p->x += 1; + else if( p->x < g->w - 7 ) p->x += 1; + p->dir--; + } +} + diff --git a/shapes.txt b/shapes.txt new file mode 100644 index 0000000..d7aded8 --- /dev/null +++ b/shapes.txt @@ -0,0 +1,135 @@ + +Starship +-------- + + /\ + (()) + I<__>I + + +Aliens +------ + + ,---. ,---. + \O o/ \o O/ + ^^^^^ ^^^^^ + +Shots +----- + + | / _, ___ \ + | / ' \ + + + | __/ \__ | + / \ + + + \ __ __ / + | \ / | + + +Explosions +---------- + + | .v, .v, .v, .v, .v, .v, . , + + o -o- >o< >o< >o< >o< > < > < + | '^` '^` '^` '^` '^` '^` ' ` + + .|, .v, .v, .v, .v, .v, . , + + o -o- --o-- > o < >( )< > < > o < >( )< - - + '|` '^` '^` '^` '^` '^` ' ` + + _ ._, .v, _\~/_ _\ /_ . ' , + + o )_( )_( > < > < _ _ + ' ` '^` ~/_\~ / \ ' . ` + + _ ._, .v, . , + + o )_( )_( > < + ' ` '^` ' ` + + + + ####### + ### ### + ## ## + # # + # # + # # + ## ## + ### ### + ####### + + _______ + ,-'_______`-. + ,',-' _____ `-.`. + / / ,' ___ `. \ \ + | | / ,' _ `. \ | | + | | | | |_| | | | | + | | \ `.___,' / | | + \ \ `._____,' / / + `.`-._______,-',' + `-._______,-' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/starfield.c b/starfield.c new file mode 100644 index 0000000..5f1844b --- /dev/null +++ b/starfield.c @@ -0,0 +1,59 @@ + +#include + +#include "common.h" + +void init_starfield( game *g, starfield *s ) +{ + int i; + + for( i = 0; i < STARS; i++ ) + { + s->x[i] = rand() % g->w; + s->y[i] = rand() % g->h; + s->z[i] = 1 + rand() % 3; + s->ch[i] = (rand() % 2) ? '.' : '\''; + s->c[i] = 6 + rand() % 2; + } +} + +void draw_starfield( game *g, starfield *s ) +{ + int i; + + for( i = 0; i < STARS; i++ ) + { + if( s->x[i] >= 0 ) + { + GFX_COLOR( s->c[i] ); + GFX_GOTO( s->x[i], s->y[i] ); + GFX_WRITE( s->ch[i] ); + } + } +} + +void update_starfield( game *g, starfield *s ) +{ + int i; + + for( i = 0; i < STARS; i++ ) + { + if( s->x[i] < 0 ) + { + s->x[i] = rand() % g->w; + s->y[i] = 0; + s->z[i] = 1 + rand() % 2; + s->ch[i] = (rand() % 2) ? '.' : '\''; + s->c[i] = 6 + rand() % 2; + } + else if( s->y[i] < g->h-1 ) + { + s->y[i] += s->z[i]; + } + else + { + s->x[i] = -1; + } + } +} + diff --git a/tunnel.c b/tunnel.c new file mode 100644 index 0000000..8d1b614 --- /dev/null +++ b/tunnel.c @@ -0,0 +1,171 @@ + +#include + +#include "common.h" + +static void draw_wall( game *g, int *wall ); + +/* Init tunnel */ +tunnel * create_tunnel( game *g, int w, int h ) +{ + int i; + tunnel *t = malloc(sizeof(tunnel)); + + t->left = malloc(h*sizeof(int)); + t->right = malloc(h*sizeof(int)); + t->w = w; + t->h = h; + + if( t->w >= g->w ) + { + t->left[0] = -1; + t->right[0] = g->w; + for( i = 0; i < g->h; i++ ) + { + t->left[i] = -1; + t->right[i] = g->w; + } + } + else + { + t->left[0] = (g->w - w) / 2; + t->right[0] = (g->w + w) / 2; + /* Yeah, sub-efficient, but less code to do :-) */ + for( i = 0; i < g->h; i++ ) + { + update_tunnel( g, t ); + } + } + + return t; +} + +void free_tunnel( tunnel *t ) +{ + free( t->left ); + free( t->right ); + free( t ); +} + +void draw_tunnel( game *g, tunnel *t ) +{ + /* Print tunnel */ + draw_wall( g, t->left ); + draw_wall( g, t->right ); +} + +void update_tunnel( game *g, tunnel *t ) +{ + static int const delta[] = { -2, -1, 1, 2 }; + int i,j,k; + + /* Slide tunnel one block vertically */ + for( i = t->h; i--; ) + { + t->left[i+1] = t->left[i]; + t->right[i+1] = t->right[i]; + } + + /* Generate new values */ + i = delta[GET_RAND(0,4)]; + j = delta[GET_RAND(0,4)]; + + /* Check in which direction we need to alter tunnel */ + if( t->right[1] - t->left[1] < t->w ) + { + /* Not wide enough */ + if( i > j ) + { + k = j; j = i; i = k; + } + } + else if( t->right[1] - t->left[1] - 2 > t->w ) + { + /* Too wide */ + if( i < j ) + { + k = j; j = i; i = k; + } + } + else + { + /* No need to mess with i and j: width is OK */ + } + + /* If width doesn't exceed game size, update coords */ + if( t->w <= g->w || t->right[1] - t->left[1] < t->w ) + { + t->left[0] = t->left[1] + i; + t->right[0] = t->right[1] + j; + } + else + { + t->left[0] = -1; + t->right[0] = g->w; + } + + if( t->w > g->w ) + { + if( t->left[0] < 0 && t->right[0] < g->w - 2 ) + { + t->left[0] = t->left[1] + 1; + } + + if( t->left[0] > 1 && t->right[0] > g->w - 1 ) + { + t->right[0] = t->right[1] - 1; + } + } + else + { + if( t->left[0] < 0 ) + { + t->left[0] = t->left[1] + 1; + } + + if( t->right[0] > g->w - 1 ) + { + t->right[0] = t->right[1] - 1; + } + } +} + +static void draw_wall( game *g, int *wall ) +{ + int i; + + for( i = 0; i < g->h ; i++ ) + { + char c; + + if( wall[i] < 0 || wall[i] >= g->w ) + { + continue; + } + + if( wall[i] > wall[i+1] ) + { + c = wall[i] > wall[i-1] ? '>' : '/'; + } + else + { + c = wall[i] > wall[i-1] ? '\\' : '<'; + } + + GFX_COLOR( RED ); + if( wall[i] == wall[i+1] + 2 ) + { + GFX_GOTO( wall[i] - 1, i ); + GFX_WRITE( '_' ); + } + else + { + GFX_GOTO( wall[i], i ); + } + GFX_WRITE( c ); + GFX_WRITE( '#' ); + GFX_WRITE( c ); + if( wall[i] == wall[i+1] - 2 ) GFX_WRITE( '_' ); + } +} + diff --git a/weapons.c b/weapons.c new file mode 100644 index 0000000..ba41857 --- /dev/null +++ b/weapons.c @@ -0,0 +1,71 @@ + +#include + +#include "common.h" + +void init_weapons( game *g, weapons *wp ) +{ + int i; + + for( i = 0; i < SHOTS; i++ ) + { + wp->x[i] = -1; + wp->y[i] = -1; + wp->v[i] = 0; + } +} + +void draw_weapons( game *g, weapons *wp ) +{ + int i; + + for( i = 0; i < SHOTS; i++ ) + { + if( wp->x[i] >= 0 ) + { + GFX_COLOR( WHITE ); + GFX_GOTO( wp->x[i], wp->y[i] ); + GFX_WRITE( '|' ); + GFX_COLOR( CYAN ); + GFX_GOTO( wp->x[i], wp->y[i] + 1 ); + GFX_WRITE( '|' ); + } + } +} + +void update_weapons( game *g, weapons *wp ) +{ + int i; + + for( i = 0; i < SHOTS; i++ ) + { + if( wp->y[i] < 0 ) + { + wp->x[i] = -1; + wp->y[i] = -1; + } + else + { + wp->y[i] += wp->v[i]; + + /* Check collisions */ + } + } +} + +void add_weapon( game *g, weapons *wp, int x, int y ) +{ + int i; + + for( i = 0; i < SHOTS; i++ ) + { + if( wp->y[i] < 0 ) + { + wp->x[i] = x; + wp->y[i] = y; + wp->v[i] = -2; + break; + } + } +} +