From a97a9b50042dfad9bd08a3b67727d992cffd485e Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 13 Dec 2002 19:23:07 +0000 Subject: [PATCH] * 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 --- Makefile | 35 +++++ aliens.c | 176 ++++++++++++++++++++++ collide.c | 121 +++++++++++++++ common.h | 130 +++++++++++++++++ explosions.c | 405 +++++++++++++++++++++++++++++++++++++++++++++++++++ graphics.c | 129 ++++++++++++++++ main.c | 179 +++++++++++++++++++++++ player.c | 68 +++++++++ shapes.txt | 135 +++++++++++++++++ starfield.c | 59 ++++++++ tunnel.c | 171 ++++++++++++++++++++++ weapons.c | 71 +++++++++ 12 files changed, 1679 insertions(+) create mode 100644 Makefile create mode 100644 aliens.c create mode 100644 collide.c create mode 100644 common.h create mode 100644 explosions.c create mode 100644 graphics.c create mode 100644 main.c create mode 100644 player.c create mode 100644 shapes.txt create mode 100644 starfield.c create mode 100644 tunnel.c create mode 100644 weapons.c 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; + } + } +} +