667 lines
12 KiB
C
667 lines
12 KiB
C
/*
|
|
* Snake clone for the PSX
|
|
*/
|
|
|
|
#include <psx.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
int vmode;
|
|
volatile int speed_counter = 0;
|
|
volatile int screen_old = 0;
|
|
|
|
int snake_array[29][40];
|
|
int scc = 0;
|
|
int vibration_cntdown = 0;
|
|
|
|
int snake_size = 3;
|
|
int game_over = 0;
|
|
|
|
int rectangle_mode = 0;
|
|
int l1_pressed = 0;
|
|
|
|
int level_number = 1;
|
|
int score = 0;
|
|
volatile int seed_counter = 0;
|
|
|
|
int sample_pos[3]; // 0 = music, 1 = collision, 2 = apple
|
|
|
|
unsigned int game_draw_list[0x4000]; /* 128 kilobytes */
|
|
|
|
enum
|
|
{
|
|
SNAKE_DIR_LEFT, SNAKE_DIR_RIGHT, SNAKE_DIR_UP, SNAKE_DIR_DOWN
|
|
};
|
|
|
|
int snake_dir = SNAKE_DIR_RIGHT;
|
|
|
|
unsigned char file_buffer[0x30000]; /* 192 kilobytes */
|
|
|
|
void game_init();
|
|
void game_vblank_handler();
|
|
void game_run();
|
|
void game_run_gameover();
|
|
int pal_or_ntsc_selection();
|
|
int main();
|
|
int check_snake_collision(int x, int y);
|
|
int load_file_into_buffer(char *fname);
|
|
void game_print(char *string, int x, int y);
|
|
void game_center_print(char *string, int x, int y);
|
|
void setup_snake_field();
|
|
void game_setup();
|
|
|
|
GsDrawEnv game_drawenv;
|
|
GsDispEnv game_dispenv;
|
|
|
|
GsImage game_image;
|
|
GsSprite game_sprite;
|
|
GsRectangle game_rect;
|
|
|
|
unsigned short game_clut[16];
|
|
|
|
char string_buf[256];
|
|
|
|
int cross_pressed = 0;
|
|
int circle_pressed = 0;
|
|
|
|
void game_init()
|
|
{
|
|
// Initialize the PSXSDK library
|
|
PSX_Init();
|
|
|
|
// Initialize graphics
|
|
GsInit();
|
|
|
|
// Clear video memory
|
|
GsClearMem();
|
|
|
|
// Set up drawing environment
|
|
game_drawenv.dither = 0;
|
|
game_drawenv.draw_on_display = 0;
|
|
game_drawenv.x = 0;
|
|
game_drawenv.y = 0;
|
|
game_drawenv.w = 320;
|
|
game_drawenv.h = 240;
|
|
game_drawenv.ignore_mask = 0;
|
|
game_drawenv.set_mask = 0;
|
|
|
|
GsSetDrawEnv(&game_drawenv);
|
|
|
|
// Set up display environment
|
|
game_dispenv.x = 0;
|
|
game_dispenv.y = 256;
|
|
|
|
GsSetDispEnv(&game_dispenv);
|
|
|
|
// Set drawing list
|
|
GsSetList(game_draw_list);
|
|
|
|
// Initialize sound
|
|
SsInit();
|
|
|
|
|
|
}
|
|
|
|
void game_vblank_handler()
|
|
{
|
|
speed_counter++;
|
|
seed_counter++;
|
|
screen_old = 1;
|
|
}
|
|
|
|
int pal_or_ntsc_selection()
|
|
{
|
|
unsigned short padbuf;
|
|
int x;
|
|
|
|
game_drawenv.draw_on_display = 1;
|
|
x = game_drawenv.y;
|
|
game_drawenv.y = game_dispenv.y;
|
|
GsSetDrawEnv(&game_drawenv);
|
|
|
|
game_rect.x = 0;
|
|
game_rect.y = 0;
|
|
game_rect.w = 320;
|
|
game_rect.h = 240;
|
|
game_rect.r = 0;
|
|
game_rect.g = 0;
|
|
game_rect.b = 0;
|
|
game_rect.attribute = 0;
|
|
|
|
GsSortRectangle(&game_rect);
|
|
|
|
game_print("PAL/NTSC SELECTION", 128, 64);
|
|
game_print("X - PAL", 128, 80);
|
|
game_print("O - NTSC", 128, 88);
|
|
|
|
GsDrawList();
|
|
|
|
while(GsIsDrawing());
|
|
|
|
game_drawenv.draw_on_display = 0;
|
|
game_drawenv.y = x;
|
|
GsSetDrawEnv(&game_drawenv);
|
|
|
|
while(1)
|
|
{
|
|
PSX_ReadPad(&padbuf, NULL);
|
|
|
|
if((padbuf & PAD_CROSS) && !cross_pressed)
|
|
return VMODE_PAL; // PAL
|
|
|
|
if((padbuf & PAD_CIRCLE) && !circle_pressed)
|
|
{
|
|
//printf("circle_pressed = %d\n", circle_pressed);
|
|
return VMODE_NTSC; // NTSC
|
|
}
|
|
|
|
|
|
if(!(padbuf & PAD_CROSS))
|
|
cross_pressed = 0;
|
|
|
|
if(!(padbuf & PAD_CIRCLE))
|
|
circle_pressed = 0;
|
|
}
|
|
}
|
|
|
|
void new_apple()
|
|
{
|
|
int a, b;
|
|
|
|
do
|
|
{
|
|
while((a = rand()%40) < 1);
|
|
srand(seed_counter);
|
|
while((b = rand()%29) < 2);
|
|
srand(seed_counter);
|
|
}while(snake_array[b][a]);
|
|
|
|
snake_array[b][a] = 0x80;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
int c;
|
|
|
|
// Initialize
|
|
game_init();
|
|
|
|
printf("PSXsnake\n");
|
|
printf("(c) 2009 Giuseppe Gatta\n");
|
|
printf("Made with PSXSDK\n\n");
|
|
|
|
load_file_into_buffer("cdrom:FONT.TIM;1");
|
|
GsImageFromTim(&game_image, file_buffer);
|
|
|
|
GsUploadImage(&game_image);
|
|
|
|
game_clut[0] = 0x0;
|
|
game_clut[1] = 0x7fff;
|
|
|
|
LoadImage(game_clut, 640, 24, 16, 1);
|
|
|
|
GsSetVideoMode(320, 240, EXAMPLES_VMODE);
|
|
|
|
vmode = pal_or_ntsc_selection();
|
|
|
|
//printf("vmode = %d\n", vmode);
|
|
|
|
GsSetVideoMode(320, 240, vmode);
|
|
|
|
|
|
load_file_into_buffer("cdrom:BACKGRND.TIM;1");
|
|
GsImageFromTim(&game_image, file_buffer);
|
|
|
|
GsUploadImage(&game_image);
|
|
|
|
sample_pos[0] = SPU_DATA_BASE_ADDR;
|
|
c = load_file_into_buffer("cdrom:MUSIC.RAW;1");
|
|
SsUpload(file_buffer, c, sample_pos[0]);
|
|
|
|
if(c&0x7)
|
|
{
|
|
c|=0x7;
|
|
c++;
|
|
}
|
|
|
|
sample_pos[1] = c + sample_pos[0];
|
|
c = load_file_into_buffer("cdrom:BOMB.RAW;1");
|
|
SsUpload(file_buffer, c, sample_pos[1]);
|
|
|
|
/* ... */
|
|
if(c&0x7)
|
|
{
|
|
c|=0x7;
|
|
c++;
|
|
}
|
|
|
|
sample_pos[2] = c + sample_pos[1];
|
|
c = load_file_into_buffer("cdrom:APPLE.RAW;1");
|
|
SsUpload(file_buffer, c, sample_pos[2]);
|
|
|
|
SsVoiceStartAddr(0, sample_pos[0]);
|
|
SsVoiceStartAddr(1, sample_pos[1]);
|
|
SsVoiceStartAddr(2, sample_pos[2]);
|
|
|
|
SsVoiceVol(0, 0x3fff, 0x3fff);
|
|
SsVoiceVol(1, 0x3fff, 0x3fff);
|
|
SsVoiceVol(2, 0x3fff, 0x3fff);
|
|
|
|
SsVoicePitch(0, 0x1000 / (44100 / 11025));
|
|
SsVoicePitch(1, 0x1000 / (44100 / 11025));
|
|
SsVoicePitch(2, 0x1000);
|
|
|
|
game_setup();
|
|
|
|
SetVBlankHandler(game_vblank_handler);
|
|
|
|
|
|
while(1)
|
|
game_run();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int check_snake_collision(int x, int y)
|
|
{
|
|
if(snake_array[y][x] == 0x80)
|
|
return 2; // Snake ate an apple
|
|
else if(snake_array[y][x] == 0)
|
|
return 1; // Collided with nothing
|
|
|
|
return 0; // Die, because snake collided with itself
|
|
}
|
|
|
|
void game_run()
|
|
{
|
|
int x, y, a, b, c;
|
|
|
|
unsigned short padbuf;
|
|
|
|
while(speed_counter > 0)
|
|
{
|
|
scc++;
|
|
|
|
if(vibration_cntdown > 0)
|
|
{
|
|
printf("vibration = %d\n", vibration_cntdown);
|
|
pad_enable_vibration(0);
|
|
pad_set_vibration(0, 0xFF, 0x80);
|
|
vibration_cntdown--;
|
|
|
|
if(vibration_cntdown == 0)
|
|
pad_set_vibration(0, 0, 0);
|
|
}
|
|
|
|
PSX_ReadPad(&padbuf, NULL);
|
|
|
|
if(scc == 5 && !game_over)
|
|
{
|
|
if(snake_dir <= SNAKE_DIR_RIGHT)
|
|
{
|
|
if(padbuf & PAD_UP)
|
|
snake_dir = SNAKE_DIR_UP;
|
|
|
|
if(padbuf & PAD_DOWN)
|
|
snake_dir = SNAKE_DIR_DOWN;
|
|
}
|
|
else
|
|
{
|
|
if(padbuf & PAD_LEFT)
|
|
snake_dir = SNAKE_DIR_LEFT;
|
|
|
|
if(padbuf & PAD_RIGHT)
|
|
snake_dir = SNAKE_DIR_RIGHT;
|
|
}
|
|
|
|
for(y = 0; y < 29; y++)
|
|
for(x = 0; x < 40; x++)
|
|
{
|
|
if(snake_array[y][x] == snake_size)
|
|
{
|
|
switch(snake_dir)
|
|
{
|
|
case SNAKE_DIR_LEFT:
|
|
b = y;
|
|
a = x-1;
|
|
break;
|
|
case SNAKE_DIR_RIGHT:
|
|
b = y;
|
|
a = x+1;
|
|
break;
|
|
case SNAKE_DIR_UP:
|
|
b = y-1;
|
|
a = x;
|
|
break;
|
|
case SNAKE_DIR_DOWN:
|
|
b = y+1;
|
|
a = x;
|
|
break;
|
|
}
|
|
|
|
c = check_snake_collision(a,b);
|
|
|
|
if(c)
|
|
{
|
|
snake_array[b][a] = snake_size+1;
|
|
|
|
if(c==2)
|
|
{
|
|
snake_size++;
|
|
score+=100;
|
|
//printf("%d\n", score);
|
|
SsKeyOn(2);
|
|
new_apple();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vibration_cntdown = 10;
|
|
game_over = 1;
|
|
SsKeyOff(0);
|
|
SsKeyOn(1);
|
|
scc = 0;
|
|
}
|
|
|
|
if(snake_array[y][x] == 1 && c!=2)
|
|
snake_array[y][x] = 0;
|
|
|
|
goto out_of_collision_checking;
|
|
}
|
|
}
|
|
out_of_collision_checking:
|
|
for(y = 0; y < 29; y++)
|
|
for(x = 0; x < 40; x++)
|
|
if(snake_array[y][x]&&snake_array[y][x]<0x80&&c!=2)
|
|
snake_array[y][x]--;
|
|
|
|
scc = 0;
|
|
}
|
|
else if(game_over)
|
|
{
|
|
scc++;
|
|
|
|
if(scc >= 510)
|
|
{
|
|
if((padbuf & PAD_CROSS) && !cross_pressed)
|
|
{
|
|
game_setup();
|
|
cross_pressed = 1;
|
|
}
|
|
else if((padbuf & PAD_CIRCLE) && !circle_pressed)
|
|
{
|
|
circle_pressed = 1;
|
|
GsSetVideoMode(320, 240, pal_or_ntsc_selection());
|
|
game_setup();
|
|
}
|
|
|
|
if(!(padbuf & PAD_CROSS))
|
|
cross_pressed = 0;
|
|
|
|
if(!(padbuf & PAD_CIRCLE))
|
|
circle_pressed = 0;
|
|
}
|
|
}
|
|
|
|
speed_counter--;
|
|
}
|
|
|
|
|
|
if(screen_old)
|
|
{
|
|
game_rect.x = 0;
|
|
game_rect.y = 0;
|
|
game_rect.w = 320;
|
|
game_rect.h = 240;
|
|
game_rect.r = 0;
|
|
game_rect.g = 0;
|
|
game_rect.b = 0;
|
|
game_rect.attribute = 0;
|
|
|
|
GsSortRectangle(&game_rect);
|
|
|
|
game_sprite.x = 0;
|
|
game_sprite.y = 0;
|
|
game_sprite.w = 256;
|
|
game_sprite.h = 240;
|
|
game_sprite.u = 0;
|
|
game_sprite.v = 0;
|
|
game_sprite.r = NORMAL_LUMINOSITY;
|
|
game_sprite.g = NORMAL_LUMINOSITY;
|
|
game_sprite.b = NORMAL_LUMINOSITY;
|
|
game_sprite.tpage = 5;
|
|
game_sprite.attribute = COLORMODE(COLORMODE_16BPP);
|
|
|
|
GsSortSimpleSprite(&game_sprite);
|
|
|
|
game_sprite.x += 256;
|
|
game_sprite.w = 64;
|
|
game_sprite.tpage = 9;
|
|
|
|
GsSortSimpleSprite(&game_sprite);
|
|
|
|
game_rect.w = 8;
|
|
game_rect.h = 8;
|
|
game_rect.attribute = ENABLE_TRANS | TRANS_MODE(0);
|
|
|
|
for(y = 0; y < 29; y++)
|
|
{
|
|
for(x = 0; x < 40; x++)
|
|
{
|
|
game_rect.x = x * 8;
|
|
game_rect.y = y * 8;
|
|
|
|
if(snake_array[y][x] >= 1 && snake_array[y][x] <= 0x7F)
|
|
{
|
|
game_rect.r = 0;
|
|
game_rect.g = 255;
|
|
game_rect.b = 0;
|
|
GsSortRectangle(&game_rect);
|
|
}
|
|
else if(snake_array[y][x] == 0x80)
|
|
{
|
|
game_rect.r = 255;
|
|
game_rect.g = 0;
|
|
game_rect.b = 255;
|
|
GsSortRectangle(&game_rect);
|
|
}
|
|
else if(snake_array[y][x] == 0x81)
|
|
{
|
|
game_rect.r = 0;
|
|
game_rect.g = 0;
|
|
game_rect.b = 128;
|
|
GsSortRectangle(&game_rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf(string_buf, "SCORE: %d", score);
|
|
game_print(string_buf, 0, 232);
|
|
|
|
if(game_over)
|
|
{
|
|
|
|
game_rect.w = 320;
|
|
game_rect.h = 240;
|
|
|
|
game_rect.x = 0;
|
|
game_rect.y = 0;
|
|
|
|
if(scc<=255)x=scc;else x=255;
|
|
|
|
game_rect.r = x;
|
|
game_rect.g = x;
|
|
game_rect.b = x;
|
|
game_rect.attribute = ENABLE_TRANS|TRANS_MODE(2);
|
|
|
|
GsSortRectangle(&game_rect);
|
|
|
|
if(scc>=300)
|
|
{
|
|
game_center_print("GAME OVER!", 160, 120);
|
|
}
|
|
|
|
if(scc>=420)
|
|
game_center_print("WHAT DO YOU WANT TO DO NOW?", 160, 136);
|
|
|
|
if(scc>=450)
|
|
game_center_print("PRESS X TO RESTART THE GAME.",160, 152);
|
|
|
|
if(scc>=480)
|
|
game_center_print("PRESS O FOR PAL/NTSC SELECTION SCREEN.",160,168);
|
|
|
|
if(scc>=510)
|
|
game_center_print("MADE WITH PSXSDK BY GIUSEPPE GATTA, 2010", 160, 200);
|
|
}
|
|
|
|
GsDrawList();
|
|
|
|
// While the graphic synthesizer (video card) is drawing
|
|
// just sleep.
|
|
while(GsIsDrawing());
|
|
|
|
// Swap drawing and display Y position, and swap list array
|
|
// to use. In this way we achieve a double buffer.
|
|
|
|
if(game_dispenv.y == 0)
|
|
{
|
|
game_dispenv.y = 256;
|
|
game_drawenv.y = 0;
|
|
}
|
|
else
|
|
{
|
|
game_dispenv.y = 0;
|
|
game_drawenv.y = 256;
|
|
}
|
|
|
|
GsSetDispEnv(&game_dispenv);
|
|
GsSetDrawEnv(&game_drawenv);
|
|
|
|
screen_old = 0;
|
|
}
|
|
}
|
|
|
|
void game_run_gameover()
|
|
{
|
|
printf("GAME OVER!\n");
|
|
while(1);
|
|
}
|
|
|
|
int load_file_into_buffer(char *fname)
|
|
{
|
|
FILE *f;
|
|
int sz;
|
|
|
|
/*int fd;
|
|
|
|
fd = open(fname, O_RDONLY);
|
|
|
|
printf("%s (%d)\n", fname, get_file_size(fname));
|
|
|
|
read(fd, file_buffer, get_file_size(fname));
|
|
|
|
close(fd);*/
|
|
f = fopen(fname, "rb");
|
|
|
|
//f->pos = 0;
|
|
fseek(f, 0, SEEK_END);
|
|
|
|
sz = ftell(f);
|
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
printf("%s (%d)\n", fname, sz);
|
|
|
|
fread(file_buffer, sizeof(char), sz, f);
|
|
|
|
fclose(f);
|
|
|
|
return sz;
|
|
}
|
|
|
|
void game_print(char *string, int x, int y)
|
|
{
|
|
GsSprite print_char;
|
|
char q;
|
|
|
|
print_char.x = x;
|
|
print_char.y = y;
|
|
print_char.w = 8;
|
|
print_char.h = 8;
|
|
print_char.r = NORMAL_LUMINOSITY;
|
|
print_char.g = NORMAL_LUMINOSITY;
|
|
print_char.b = NORMAL_LUMINOSITY;
|
|
print_char.cx = 640;
|
|
print_char.cy = 24;
|
|
print_char.tpage = 10;
|
|
print_char.attribute = COLORMODE(COLORMODE_4BPP);
|
|
|
|
while(*string)
|
|
{
|
|
if(*string >= 0x20 && *string <= 0x7F)
|
|
{
|
|
q = *string;
|
|
q -= 0x20;
|
|
|
|
print_char.u = (q&0x1f)<<3;
|
|
print_char.v = (q/0x20)<<3;
|
|
GsSortSimpleSprite(&print_char);
|
|
}
|
|
print_char.x+=8;
|
|
string++;
|
|
}
|
|
}
|
|
|
|
void game_center_print(char *string, int x, int y)
|
|
{
|
|
int l = strlen(string);
|
|
l<<=2;
|
|
|
|
game_print(string, x - l, y);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void setup_snake_field()
|
|
{
|
|
int x, y;
|
|
|
|
for(y=0;y<29;y++)
|
|
for(x=0;x<40;x++)
|
|
snake_array[y][x] = 0;
|
|
|
|
for(y=0;y<29;y++)
|
|
{
|
|
snake_array[y][0] = 0x81;
|
|
snake_array[y][39] = 0x81;
|
|
}
|
|
|
|
for(x=0;x<40;x++)
|
|
{
|
|
snake_array[0][x] = 0x81;
|
|
snake_array[28][x] = 0x81;
|
|
}
|
|
|
|
new_apple();
|
|
|
|
for(x=1;x<=snake_size;x++)
|
|
snake_array[1][x]=x;
|
|
|
|
snake_dir = SNAKE_DIR_RIGHT;
|
|
}
|
|
|
|
void game_setup()
|
|
{
|
|
game_over = 0;
|
|
scc = 0;
|
|
snake_size = 3;
|
|
speed_counter = 0;
|
|
score = 0;
|
|
setup_snake_field();
|
|
SsKeyOn(0);
|
|
}
|
|
|