/* * Snake clone for the PSX */ #include #include #include #include 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); }