/* 19/10/99 22/10/99 */ #include #include #include /* pad reading stuff */ #include "pad.h" /* callbacks */ typedef void (*callbackFN) (void); callbackFN draw_func; callbackFN pad_func; callbackFN work_func; /* defines */ #define VH_ADDR (0x80096000) #define VB_ADDR (0x80150000) #define TIM1_ADDR (0x80090000) #define TIM2_ADDR (0x80091000) #define TIM3_ADDR (0x80092000) #define TIM4_ADDR (0x80093000) #define TIM5_ADDR (0x80094000) #define TIM6_ADDR (0x80095000) #define MAX_DIFFICULTY 1000 #define OCTAVE_FACTOR 24 #define SOUND_CHANGE_GAP 50 #define VOL_RANGE 64.0 #define VOL_MIN 63 #define VOL_MAX 127 #define BAWL_TIME 75 #define STAR_NUM 200 #define STAR_WAIT 5000 #define STAR_PAUSE 5 /* daaaaah daaaaaaaaaah, da-da-da daaaah daaaaaaaah. erm, sorry */ #define FIDDLE_DROP 10 #define NUM_LIVES 3 #define EXTRA_LIFE 1000 #define BOX_SCORE_TIME 100 #define BOX_Y 14 #define BOX_FRAME_TIME 10 #define INVINCIBLE_TIME 100 #define INVINCIBLE_FLASH 10 #define DEATH_TIME 10 #define MAX_BANJO_BULLET 500 #define FIRST_START_HEIGHT 30 #define MAX_START_HEIGHT 110 #define START_X 20 #define X_GAP 20 #define Y_GAP 20 #define RESET_HEIGHT_AMOUNT (Y_GAP*6) #define NUM_X 8 #define NUM_Y 5 #define LEFT 1 #define RIGHT 2 #define DOWN 3 #define ALIVE 1 #define DYING 2 #define DEAD 0 #define BOX_MIN 20 #define BOX_MAX 360 #define MIN_X 40 #define MAX_X 340 #define MIN_Y 5 #define MAX_Y 240 #define SCREEN_WIDTH 384 #define SCREEN_HEIGHT 256 #define BULLET_STEP 1 #define MAIN_BULLET_STEP 4 #define BANJO_STEP 8 #define TITLE 0 #define STARTING 1 #define RUNNING 2 #define ENDING 3 #define START_PAUSE 40 #define MAIN_DIE_TIME 25 #define EASY 0 #define MEDIUM 1 #define HARD 2 #define IMPOSSIBLE 3 #define EASY_START 1 #define MEDIUM_START 10 #define HARD_START 20 #define IMPOSSIBLE_START 500 #define EASY_CHANGE 2 #define MEDIUM_CHANGE 5 #define HARD_CHANGE 10 #define IMPOSSIBLE_CHANGE 100 /* types */ typedef struct { char status; int v; int x; int y; int death_frame; char bottom_most; int next_up; int score; } banjo; typedef struct { int x; int y; int frame; int next_frame; int frame_pause; } star; star star_list[STAR_NUM]; typedef struct { int x; int y; } bullet; /* globals */ int difficulty_level; int difficulty_start; int difficulty_change; int next_note= 60; int current_frame= 0; char current_direction; char last_direction; char next_direction; int direction_count; int banjo_step; int not_quitting= 1; int game_status= TITLE; int wait_until_frame= 0; int current_pause; int hit_bottom= 0; int player_lives; int player_score= 0; int difficulty; int high_score= 0; int invincible_until; int invincible_flash; int no_bombs_until; int player_hit; int bawl_until; int bawl_frame; int violin_drop; short VAB; int total_banjo_pos; short box_voice; banjo banjos[NUM_X*NUM_Y]; bullet banjo_bullets[MAX_BANJO_BULLET]; int bullet_count; char bullet_status; int left_to_die; int start_height; int drop_count; int score_font; int game_over_font; int press_start_font; int diff_font; /* sprites */ GsSPRITE banjo_sprite; GsSPRITE banjo_bullet; GsSPRITE main_bullet_sprite; GsSPRITE main_sprite; GsSPRITE box_sprite; GsSPRITE star_sprite; int output_buffer_index; GsOT world_ordering_table[2]; GsOT_TAG ordering_table[2][1<<1]; PACKET gpu_work_area[2][100000]; GsIMAGE tim1; GsIMAGE tim2; GsIMAGE tim3; GsIMAGE tim4; GsIMAGE tim5; GsIMAGE tim6; /* bawl v offset order */ int bawl_anim[2]= { 48, 60 }; int bawl_frame_wait; /* star v offset order */ int star_anim[7]= { 0, 8, 16, 24, 32, 40, 48 }; /* player top half v offset order */ int player_top_anim[5]= { 0, 12, 24, 12, 0 }; /* player bottom half v offset order */ int player_bottom_anim[10]= { 0, 6, 12, 6, 0, 18, 24, 30, 24, 18 }; int player_top_frame; int player_bottom_frame; int player_moving; /* box v offset order */ int box_anim[4]= { 0, 16, 32, 16 }; /* corresponding collision width for each frame */ int box_width[4]= { 8, 12, 16, 12 }; int box_frame; int box_speed; int box_active; int box_next_frame; int box_speed_count; int box_counter; int box_score; int box_dead; int box_score_offset; int extra_given; /* load tim data */ 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; } /* get right speaker volume for x pos */ int get_right_vol (int x) { int right_vol; right_vol= VOL_RANGE*(x-MIN_X)/(MAX_X-MIN_X); if (right_vol<0) right_vol= 0; if (right_vol>VOL_RANGE) right_vol= VOL_RANGE; return right_vol; } /* called at the start of each game */ void start_game (void) { int i; for (i= 0; iMAX_DIFFICULTY) difficulty= MAX_DIFFICULTY; } /* called at the start of each level */ void init_level (void) { int x, y; int i,j; int this= 0; int score; /* reset banjo positions */ x= START_X; for (i=0; i0) { star_list[i].frame_pause --; if (star_list[i].frame_pause==0) { star_list[i].frame ++; star_list[i].frame_pause= STAR_PAUSE; if (star_list[i].frame==7) { star_list[i].frame= 0; star_list[i].next_frame= rand () %STAR_WAIT+ current_frame; } } } else if (star_list[i].next_frame high_score) high_score= player_score; sprintf (scr, " %6d %6d", player_score, high_score); FntPrint (score_font, scr); FntFlush (score_font); /* draw remaining lives */ life_pos= MIN_X; i= 1; x= main_sprite.x; y= main_sprite.y; main_sprite.v= player_top_anim[0]; while (i0) { player_top_frame ++; if (player_top_frame==5) player_top_frame= 0; } /* draw player */ if (player_hit) { if (violin_drop>0) { /* dropping fiddle */ main_sprite.u= 15; /* fiddle */ main_sprite.v= 36; main_sprite.y += FIDDLE_DROP - violin_drop; GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); main_sprite.y -= FIDDLE_DROP - violin_drop; main_sprite.u= 0; main_sprite.v= 36; /* no fiddle in hands */ GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); violin_drop --; if (violin_drop==0) { int right_vol; right_vol= get_right_vol (main_sprite.x); SsUtKeyOn (VAB, 6, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); SsUtKeyOn (VAB, 7, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); bawl_until= current_frame + BAWL_TIME; no_bombs_until= bawl_until; bawl_frame= 0; bawl_frame_wait= 5; } } else { /* bawling */ main_sprite.u= 15; /* broken fiddle */ main_sprite.v= 48; main_sprite.y += FIDDLE_DROP; GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); main_sprite.y -= FIDDLE_DROP; main_sprite.u= 0; main_sprite.v= bawl_anim[bawl_frame]; GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); bawl_frame_wait --; if (bawl_frame_wait==0) { bawl_frame ++; if (bawl_frame==2) bawl_frame= 0; bawl_frame_wait= 5; } } /* draw legs */ main_sprite.y += 11; main_sprite.u= 17; main_sprite.v= player_bottom_anim[0]; main_sprite.h= 5; GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); main_sprite.y -= 11; } else if (game_status!=ENDING && ((invincible_until <= current_frame) || (invincible_flash <= current_frame))) { GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); main_sprite.y += 11; main_sprite.u= 17; main_sprite.v= player_bottom_anim[player_bottom_frame]; main_sprite.h= 5; GsSortFastSprite (&main_sprite, &world_ordering_table[output_buffer_index], 0); main_sprite.y -= 11; } if (player_moving) { player_bottom_frame ++; if (player_bottom_frame==10) player_bottom_frame= 0; } if ((invincible_until > current_frame) && (invincible_flash <= (current_frame - INVINCIBLE_FLASH))) invincible_flash= current_frame + INVINCIBLE_FLASH; if (bullet_status) { /* draw player bullet */ GsSortFastSprite (&main_bullet_sprite, &world_ordering_table[output_buffer_index], 0); } total_banjo_pos= 0; for (i= 0; i=BOX_MAX) box_active= 0; else { if (box_next_frame <= current_frame) { int right_vol; right_vol= get_right_vol (box_sprite.x); if (box_frame==0) { SsUtKeyOff (box_voice, VAB, 3, 0, 60 - OCTAVE_FACTOR); box_voice= SsUtKeyOn (VAB, 2, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); } if (box_frame==2) { SsUtKeyOff (box_voice, VAB, 2, 0, 60 - OCTAVE_FACTOR); box_voice= SsUtKeyOn (VAB, 3, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); } box_frame++; if (box_frame>3) box_frame= 0; box_sprite.v= box_anim[box_frame]; box_next_frame= current_frame + BOX_FRAME_TIME; } GsSortFastSprite (&box_sprite, &world_ordering_table[output_buffer_index], 0); } } else if (box_dead) { if (current_frame<=box_frame) { GsSortFastSprite (&box_sprite, &world_ordering_table[output_buffer_index], 0); } else { box_dead= 0; } } else if (rand()%256==1) { box_active= 1; box_frame= 0; box_next_frame= current_frame; box_sprite.v= box_anim[0]; box_sprite.y= BOX_Y; if (rand()%255<100) { box_speed= 1; box_speed_count= 2; box_counter= 2; box_score= 10; box_score_offset= 48; } else if (rand()%255<128) { box_speed= 1; box_speed_count= 1; box_counter= 1; box_score= 50; box_score_offset= 64; } else { box_speed= 2; box_speed_count= 1; box_counter= 1; box_score= 100; box_score_offset= 80; } if (rand()%255<128) { box_sprite.x= BOX_MAX-1; box_speed *= -1; } else { box_sprite.x= BOX_MIN+1; } } draw_stars (); } void move_banjos (void) { int i; next_direction= current_direction; if (wait_until_frame<=current_frame) { int right_vol; right_vol= get_right_vol (total_banjo_pos); SsUtKeyOn (VAB, 0, 0, next_note - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); next_note ++; if (next_note>61) next_note= 60; } if (wait_until_frame<=current_frame && current_direction==DOWN) { drop_count -= banjo_step; if (drop_count<0) { next_direction= last_direction; } } for (i=0; i= (main_sprite.y-12) && banjos[i].status==ALIVE) { if (banjos[i].x >= (main_sprite.x-14) && banjos[i].x <= (main_sprite.x+14)) hit_bottom= 1; } if (wait_until_frame <= current_frame && banjos[i].status==ALIVE) { /* change sprite frame */ if (banjos[i].v==0) banjos[i].v= 16; else if (banjos[i].v==16) banjos[i].v= 0; if (current_direction==RIGHT) { banjos[i].x += banjo_step; if (banjos[i].x>=MAX_X) { next_direction= DOWN; last_direction= LEFT; drop_count= Y_GAP/2; } } else if (current_direction==LEFT) { banjos[i].x -= banjo_step; if (banjos[i].x<=MIN_X) { next_direction= DOWN; last_direction= RIGHT; drop_count= Y_GAP/2; } } else { /* DOWN */ banjos[i].y += banjo_step; if (banjos[i].y >= main_sprite.y) hit_bottom= 1; } } else { if (banjos[i].status==DYING) { if (banjos[i].death_frame <= current_frame) { banjos[i].status= DEAD; if (banjos[i].bottom_most) { int next_up= i; while (banjos[next_up].status != ALIVE && banjos[next_up].next_up != -1) { next_up= banjos[next_up].next_up; } if (banjos[next_up].status==ALIVE) banjos[next_up].bottom_most= 1; } left_to_die --; if (left_to_die%2==0) current_pause -= 2; if (current_pause<0) current_pause= 0; } } } } if (wait_until_frame<=current_frame) { current_direction= next_direction; wait_until_frame= current_frame+current_pause; } } void move_bullets (void) { int i; if (bullet_status) { main_bullet_sprite.y -= MAIN_BULLET_STEP; if (main_bullet_sprite.y <= MIN_Y) bullet_status= 0; } for (i=0; i= MAX_Y) { banjo_bullets[i]= banjo_bullets[bullet_count-1]; bullet_count --; i --; } } } void title_draw (void) { char buff[100]; sprintf (buff, " %6d %6d", player_score, high_score); FntPrint (score_font, buff); sprintf (buff, "GAME OVER"); FntPrint (game_over_font, buff); sprintf (buff, "Press start"); FntPrint (press_start_font, buff); switch (difficulty_level) { case EASY: sprintf (buff, "Difficulty: EASY"); break; case MEDIUM: sprintf (buff, "Difficulty: MEDIUM"); break; case HARD: sprintf (buff, "Difficulty: HARD"); break; default: sprintf (buff, "Difficulty: IMPOSSIBLE"); } FntPrint (diff_font, buff); FntFlush (score_font); FntFlush (game_over_font); FntFlush (press_start_font); FntFlush (diff_font); } u_long last_pad; void title_pad (void) { u_long pad_status; pad_status= PadRead (); if ((pad_status & PADLleft) && !(last_pad & PADLleft)) { SsUtKeyOn (VAB, 5, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX, VOL_MAX); if (difficulty_level==EASY) difficulty_level= IMPOSSIBLE; else difficulty_level --; } if ((pad_status & PADLright) && !(last_pad & PADLright)) { SsUtKeyOn (VAB, 5, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX, VOL_MAX); if (difficulty_level==IMPOSSIBLE) difficulty_level= EASY; else difficulty_level ++; } switch (difficulty_level) { case EASY: difficulty_start= EASY_START; difficulty_change= EASY_CHANGE; break; case MEDIUM: difficulty_start= MEDIUM_START; difficulty_change= MEDIUM_CHANGE; break; case HARD: difficulty_start= HARD_START; difficulty_change= HARD_CHANGE; break; default: difficulty_start= IMPOSSIBLE_START; difficulty_change= IMPOSSIBLE_CHANGE; } last_pad= pad_status; if (pad_status & PADstart) { if (pad_status & PADselect) not_quitting= 0; else { game_status= STARTING; } } } void get_move (void) { u_long pad_status; pad_status= PadRead (); if ((pad_status & PADstart) && (pad_status & PADselect)) not_quitting= 0; if (pad_status & PADLleft) { if (main_sprite.x > MIN_X) { main_sprite.x --; if (!player_moving) { player_moving= 1; player_bottom_frame= 1; } } } else if (pad_status & PADLright) { if (main_sprite.x < MAX_X) { main_sprite.x ++; if (!player_moving) { player_moving= 1; player_bottom_frame= 1; } } } else { player_moving= 0; player_bottom_frame= 0; } if (pad_status & PADRdown) { if (!bullet_status) { int right_vol; right_vol= get_right_vol (main_sprite.x); SsUtKeyOn (VAB, 5, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); player_top_frame= 1; bullet_status= 1; main_bullet_sprite.x= main_sprite.x+4; main_bullet_sprite.y= main_sprite.y; } } } void loose_life (void); void collide_bullets (void) { int i; /* player bullet with banjos */ if (bullet_status) { for (i=0; i=(banjos[i].x+2)) && (main_bullet_sprite.y<=(banjos[i].y+10)) && ((main_bullet_sprite.y+3)>=(banjos[i].y+1))) { int right_vol; right_vol= get_right_vol (banjos[i].x); banjos[i].v= 32; /* set explode sprite frame */ SsUtKeyOn (VAB, 1, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); banjos[i].status= DYING; player_score += banjos[i].score; banjos[i].death_frame= current_frame + DEATH_TIME; bullet_status= 0; } } } /* player bullet with box */ if (box_active) { if (main_bullet_sprite.x<=(box_sprite.x+14+box_width[box_frame]) && main_bullet_sprite.x>=(box_sprite.x+14-box_width[box_frame]) && main_bullet_sprite.y>=(box_sprite.y-3) && main_bullet_sprite.y<=(box_sprite.y+13)) { int right_vol; right_vol= get_right_vol (box_sprite.x); SsUtKeyOff (box_voice, VAB, 2, 0, 60 - OCTAVE_FACTOR); SsUtKeyOff (box_voice, VAB, 3, 0, 60 - OCTAVE_FACTOR); SsUtKeyOn (VAB, 4, 0, 60 - OCTAVE_FACTOR, 0, VOL_MAX-right_vol, VOL_MIN+right_vol); box_active= 0; player_score += box_score; bullet_status= 0; box_dead= 1; box_sprite.v= box_score_offset; box_frame= current_frame+BOX_SCORE_TIME; } } } if (player_score > high_score) high_score= player_score; if (player_score>=EXTRA_LIFE && !extra_given) { player_lives ++; extra_given= 1; } /* alien bullets with player and player bullet */ for (i=0; i=main_sprite.x) && (banjo_bullets[i].y<=(main_sprite.y+15)) && ((banjo_bullets[i].y+3)>=main_sprite.y)) { /* player hit */ if (!player_hit) loose_life (); /* delete this bullet */ banjo_bullets[i]= banjo_bullets[bullet_count-1]; bullet_count --; i --; } if (bullet_status) { if ((main_bullet_sprite.x<=(banjo_bullets[i].x+1)) && ((main_bullet_sprite.x+5)>=banjo_bullets[i].x) && (main_bullet_sprite.y<=(banjo_bullets[i].y+3)) && ((main_bullet_sprite.y+3)>=banjo_bullets[i].y)) { banjo_bullets[i]= banjo_bullets[bullet_count-1]; bullet_count --; i --; bullet_status= 0; } } } } void do_work (void) { move_banjos (); move_bullets (); collide_bullets (); if (player_score>=EXTRA_LIFE && !extra_given) { player_lives ++; extra_given= 1; } if (hit_bottom) { /* loose a live and reset remaining aliens */ int i; loose_life (); hit_bottom= 0; for (i=0; i