#include #include #include #include "pad.h" typedef void (*callbackFN) (void); callbackFN draw_func; callbackFN pad_func; #define TIM_ADDR (0x80090000) #define VH_ADDR (0x80091000) #define VB_ADDR (0x80150000) #define OCTAVE_FACTOR 24 #define SCREEN_WIDTH 384 #define SCREEN_HEIGHT 256 #define TITLE 0 #define STARTING 1 #define RUNNING 2 #define ENDING 3 #define MIN_X 60 #define MIN_Y 40 #define COUNTER_SIZE 32 #define EMPTY 0 #define BLUE 1 #define RED 2 #define DRAW 3 #define RED_OFFSET 0 #define BLUE_OFFSET (COUNTER_SIZE) #define BOARD_OFFSET (2*COUNTER_SIZE) #define MAX_X 7 #define MAX_Y 6 #define HORIZONTAL 1 #define VERTICAL 2 #define DIAGONAL1 4 #define DIAGONAL2 8 #define DROP_SPEED 1 #define DROP_ACCEL 1.2 #define FLASH_TIME 15 #define FLASH_OFF_TIME 10 u_long last_pad= 0; int left_abort=0; int right_abort=0; int flash_until= 0; int win_line; int move_x; int move_y; int not_quitting= 1; int game_status= TITLE; int current_frame= 0; int win_font; int output_buffer_index; GsOT world_ordering_table[2]; GsOT_TAG ordering_table[2][1<<1]; PACKET gpu_work_area[2][100000]; GsSPRITE counter_sprite; GsIMAGE tim; int winner; int current; int grid_count; int curr_x; int curr_y; int dropping_counter; int target_y; int drop_speed; float flt_drop_speed; short vab_voice; int grid[MAX_X][MAX_Y]; void dummy_fn (void) { } void load_tim (u_long *addr, GsIMAGE *tim) { RECT rect; addr ++; GsGetTimInfo (addr, tim); DrawSync (0); rect.x= tim->px; rect.y= tim->py; rect.w= tim->pw; rect.h= tim->ph; LoadImage (&rect, tim->pixel); DrawSync (0); if ((tim->pmode >> 3) & 0x01) { rect.x= tim->cx; rect.y= tim->cy; rect.w= tim->cw; rect.h= tim->ch; LoadImage (&rect, tim->clut); } DrawSync (0); } /* load tim data into sprites */ void load_sprite (GsSPRITE *spr, GsIMAGE *tim) { spr->attribute= (1<<24)|(1<<30)|(1<<29); spr->w= tim->pw*2; spr->h= tim->ph; spr->tpage= GetTPage (1,0,tim->px,tim->py); spr->u= 0; spr->v= 0; spr->cx= tim->cx; spr->cy= tim->cy; spr->r= 0x80; spr->g= 0x80; spr->b= 0x80; spr->mx= tim->pw; spr->my= tim->ph; spr->scalex= ONE; spr->scaley= ONE; spr->rotate= 0; } void reset_grid (void) { int i, j; for (i=0; i= 0; curr --) { if (grid[curr][y]==col) count ++; else break; if (curr==x-3) break; } count --; for (curr= x; curr < MAX_X; curr ++) { if (grid[curr][y]==col) count ++; else break; if (curr==x+3) break; } if (count >= 4) rv= HORIZONTAL; count= 0; for (curr= y; curr >= 0; curr --) { if (grid[x][curr]==col) count ++; else break; if (curr==y-3) break; } count --; for (curr= y; curr < MAX_Y; curr ++) { if (grid[x][curr]==col) count ++; else break; if (curr==y+3) break; } if (count >= 4) rv= rv|VERTICAL; count= 0; i= y; for (curr= x; curr >= 0; curr --) { if (grid[curr][i]==col) count ++; else break; if (curr==x-3 || i==0) break; i --; } count --; i= y; for (curr= x; curr < MAX_X; curr ++) { if (grid[curr][i]==col) count ++; else break; if (curr==x+3 || i==MAX_Y-1) break; i ++; } if (count >=4) rv= rv|DIAGONAL1; count= 0; i= y; for (curr= x; curr >= 0; curr --) { if (grid[curr][i]==col) count ++; else break; if (curr==x-3 || i==MAX_Y-1) break; i ++; } count --; i= y; for (curr= x; curr < MAX_X; curr ++) { if (grid[curr][i]==col) count ++; else break; if (curr==x+3 || i==0) break; i --; } if (count >=4) rv= rv|DIAGONAL2; return rv; } int find_y (int x) { int i= MAX_Y; int not_finished= 1; if (x<0 || x>=MAX_X) return MAX_Y; while (not_finished) { if (grid[x][i-1] == EMPTY) not_finished= 0; i--; if (i==0) { if (not_finished) i= MAX_Y; not_finished= 0; } } return i; } void display_grid (void) { int i, j; char buff[80]; if (left_abort) { sprintf (buff, "Abort requested by Red"); } if (right_abort) { sprintf (buff, "Abort requested by Blue"); } if (left_abort&&right_abort) { sprintf (buff, "Game aborted"); } if (left_abort||right_abort) { FntPrint (win_font, buff); FntFlush (win_font); } counter_sprite.v= BOARD_OFFSET; for (j= 0; j< MAX_Y; j ++) for (i= 0; i< MAX_X; i ++) { counter_sprite.x= MIN_X+COUNTER_SIZE*i; counter_sprite.y= MIN_Y+COUNTER_SIZE*j; GsSortFastSprite (&counter_sprite, &world_ordering_table[output_buffer_index], 0); } for (j= MAX_Y-1; j>=0; j--) { for (i= 0; i= 0; curr --) { if (grid[curr][y]==col) { xl[i]= curr; yl[i]= y; i++; } else break; if (curr==x-3) break; } for (curr= x; curr < MAX_X; curr ++) { if (grid[curr][y]==col) { xl[i]= curr; yl[i]= y; i ++; } else break; if (curr==x+3) break; } } if (win_line & VERTICAL) { for (curr= y; curr >= 0; curr --) { if (grid[x][curr]==col) { xl[i]= x; yl[i]= curr; i++; } else break; if (curr==y-3) break; } for (curr= y; curr < MAX_Y; curr ++) { if (grid[x][curr]==col) { xl[i]= x; yl[i]= curr; i ++; } else break; if (curr==y+3) break; } } if (win_line & DIAGONAL1) { ii= y; for (curr= x; curr >= 0; curr --) { if (grid[curr][ii]==col) { xl[i]= curr; yl[i]= ii; i ++; } else break; if (curr==x-3 || ii==0) break; ii --; } ii= y; for (curr= x; curr < MAX_X; curr ++) { if (grid[curr][ii]==col) { xl[i]= curr; yl[i]= ii; i ++; } else break; if (curr==x+3 || ii==MAX_Y-1) break; ii ++; } } if (win_line & DIAGONAL2) { ii= y; for (curr= x; curr >= 0; curr --) { if (grid[curr][ii]==col) { xl[i]= curr; yl[i]= ii; i ++; } else break; if (curr==x-3 || ii==MAX_Y-1) break; ii ++; } ii= y; for (curr= x; curr < MAX_X; curr ++) { if (grid[curr][ii]==col) { xl[i]= curr; yl[i]= ii; i ++; } else break; if (curr==x+3 || ii==0) break; ii --; } } i --; i_count= i; if (current_frame>=flash_until) { while (i>=0) { grid[xl[i]][yl[i]]= EMPTY; i --; } } if (current_frame>=flash_until+FLASH_OFF_TIME) flash_until= current_frame + FLASH_TIME; display_grid (); i= i_count; while (i>=0) { grid[xl[i]][yl[i]]= col; i --; } } void title_draw (void) { char buff[20]; buff[0]= NULL; if (winner==RED) sprintf (buff, "Red wins"); if (winner==BLUE) sprintf (buff, "Blue wins"); if (winner==DRAW) sprintf (buff, "Draw"); FntPrint (win_font, buff); FntFlush (win_font); if (flash_until0) { SsUtKeyOn (vab_voice, 0, 0, 60-OCTAVE_FACTOR, 0, 127,127); move_x --; curr_x -= COUNTER_SIZE; } } else if ((pad_status & this_right) && !(last_pad & this_right)) { if (move_x=target_y) { SsUtKeyOn (vab_voice, 1, 0, 60-OCTAVE_FACTOR, 0, 127,127); dropping_counter= 0; grid_count --; curr_y= MIN_Y - COUNTER_SIZE; if ((win_line= check_move (current, move_x, move_y))) { SsUtKeyOn (vab_voice, 2, 0, 60-OCTAVE_FACTOR, 0, 127, 127); winner= current; } else if (grid_count==0) { SsUtKeyOn (vab_voice, 2, 0, 60-OCTAVE_FACTOR, 0, 127, 127); winner= DRAW; } if (winner!=EMPTY) { game_status= ENDING; current= EMPTY; flash_until= current_frame + FLASH_TIME; } if (current==RED) current= BLUE; else if (current==BLUE) current= RED; } } last_pad= pad_status; } int main (void) { int count; PadInit (); SetVideoMode (MODE_PAL); ResetGraph (0); GsInitGraph (SCREEN_WIDTH, SCREEN_HEIGHT, GsOFSGPU, 0, 0); GsDefDispBuff (0, 0, 0, 256); GsDISPENV.screen.x= 0; GsDISPENV.screen.y= 18; GsDISPENV.screen.w= SCREEN_WIDTH; GsDISPENV.screen.h= SCREEN_HEIGHT; GsDRAWENV.r0= 0x00; GsDRAWENV.g0= 0x00; GsDRAWENV.b0= 0x00; GsDRAWENV.isbg= 1; for (count= 0; count<2; count ++) { world_ordering_table[count].length= 1; world_ordering_table[count].org= ordering_table[count]; GsClearOt (0, 0, &world_ordering_table[count]); } vab_voice= SsVabTransfer ((unsigned char *)VH_ADDR, (unsigned char *)VB_ADDR, 1, 1); load_tim ((u_long *) TIM_ADDR, &tim); load_sprite (&counter_sprite, &tim); counter_sprite.h= COUNTER_SIZE; FntLoad (960, 256); win_font= FntOpen (100, 10, SCREEN_WIDTH, 10, 0, 25); draw_func= title_draw; pad_func= title_pad; while (not_quitting) { current_frame ++; if (game_status==STARTING) { start_game (); draw_func= display_grid; pad_func= get_move; game_status= RUNNING; } else if (game_status==ENDING) { draw_func= title_draw; pad_func= title_pad; game_status= TITLE; } pad_func (); output_buffer_index= GsGetActiveBuff (); GsSetWorkBase ((PACKET *)gpu_work_area[output_buffer_index]); GsClearOt (0, 0, &world_ordering_table[output_buffer_index]); draw_func (); VSync (0); GsSwapDispBuff (); GsDrawOt (&world_ordering_table[output_buffer_index]); } SsUtAllKeyOff (0); SsVabClose (vab_voice); ResetGraph (1); return 0; }