//* screens.c - game intermission screens //* System library headers #include #include #include //* Application headers #include "main.h" #include "halloc.h" #include "pad.h" #include "procs.h" #include "vizfx.h" int sSync; //* Debug mode: holds slowest execution speed recorded so far #define NUM_LOGO_SPRITES (100) //*------------------------------------------------------------------------------------------ //* LogoScreen //*------------------------------------------------------------------------------------- void LogoScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() int frameCnt; struct SCTRL *NYtext; //* Create title screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_LOGO_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 7, NUM_LOGO_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_LOGO_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* First half of VC logo sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 150; sp->h = 72; sp->tpage = GetTPage(1, 0, timData[TIM_VC_LOGO1].px, timData[TIM_VC_LOGO1].py); sp->u = 0; sp->v = timData[TIM_VC_LOGO1].py; sp->cx = timData[TIM_VC_LOGO1].cx; sp->cy = timData[TIM_VC_LOGO1].cy; sp->mx = 150; sp->my = 36; sp->x = 10+150; sp->y = 40+36-5; scp->ICSALop = logoPly; AliveLinkIn(scp); //* Second half of VC logo sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 150; sp->h = 72; sp->tpage = GetTPage(1, 0, timData[TIM_VC_LOGO2].px, timData[TIM_VC_LOGO2].py); sp->u = 0; sp->v = timData[TIM_VC_LOGO2].py; sp->cx = timData[TIM_VC_LOGO1].cx; sp->cy = timData[TIM_VC_LOGO1].cy; sp->mx = 0; sp->my = 36; sp->x = 10+150; sp->y = 40+36-5; scp->ICSALop = logoPly; AliveLinkIn(scp); CentreText("A", 24-8, -3); CentreText("PRODUCTION", 120+8, -3); CentreText("FOR", 140+8, -3); CentreText("NET YAROZE", 160+8, -3); CentreText("@1998 CHRIS CHADWICK", 200+8, -3); //* Start with 2 seconds of white noise FX WhiteNoise(2*60); for (frameCnt=10*60; frameCnt; frameCnt--) { //* White noise FX interruptions if (frameCnt==595) WhiteNoise(5); else if (frameCnt==590) WhiteNoise(15); else if (frameCnt==580) WhiteNoise(10); else if (frameCnt==565) WhiteNoise(20); else if (frameCnt==545) WhiteNoise(5); //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* //* Add alive sprites to OT //* for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, 0); } //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(100, 0, 200, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); } //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_TV_Off(); } #define NUM_CLOUDS (10) #define NUM_COINS (450) //* Note: MUST be exactly divisible by 3 #define NUM_BOLTS (10) #define NUM_CHARS (10) #define NUM_TEXT (21+13) #define NUM_EXTRAS (50) #define NUM_SPRITES (NUM_CLOUDS+NUM_COINS+NUM_BOLTS+NUM_CHARS+NUM_TEXT+NUM_EXTRAS) #define HELMET_X (110) #define HELMET_Y (66) //*------------------------------------------------------------------------------------------ //* TitleScreen //*------------------------------------------------------------------------------------- void TitleScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() struct SCTRL *visorScp; //* Pointer to visor sprite struct SCTRL *helmetScp; //* Pointer to helmet sprite struct SCTRL *faceScp; //* Pointer to normal face sprite struct SCTRL *winkScp; //* Pointer to winking face sprite int winkCue=7*60+15; //* Vsync countdown until winking sequence activates struct SCTRL *charScp; //* Pointer to 1st character sprite in group int charCue=9*60+30; //* Vsync countdown until character sprites activate struct SCTRL *text1Scp; //* Pointer to 1st sprite in 'OPERATION: MONSTER MALL' group int text1Cue=charCue; //* Vsync countdown until text1 sprites activate struct SCTRL *text2Scp; //* Pointer to 1st sprite in 'PRESS START' group int text2Cue=text1Cue+6*60+40; //* Vsync countdown until text2 sprites activate struct SCTRL *boltScp; //* Pointer to 1st sprite in lightning bolt group struct SCTRL *boltScp2; //* Destructible copy of boltScp int boltCue=1*60; //* Vsync countdown until bolt sprites activate int frameCnt; //* Main loop counter used to cue clouds struct SCTRL *cloudScp; //* Pointer to 1st sprite in dust cloud group u_long pad, lastPad; //* Takes controller pad status //* Create title screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 7, NUM_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Initialize coin sprites (initially with DISPLAY_OFF) i = NUM_COINS/3; x = 0; for (scp=GetSprite(NUM_COINS); scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = 16; sp->h = 18; sp->tpage = GetTPage(0, 0, timData[TIM_COIN].px, timData[TIM_COIN].py); sp->u = 0; sp->v = timData[TIM_COIN].py; sp->cx = timData[TIM_COIN].cx; sp->cy = timData[TIM_COIN+x].cy; //* Set coin colour if (!--i) { //* Management to ensure an equal i = NUM_COINS/3; //* amount of the 3 coin colours x++; } sp->r = sp->g = sp->b = 32+(rand()%97); //* Random brightness (also OT priority) sp->x = -8 + (rand()%321); //* Random above-screen sp->y = -18 - (rand()%240); //* start coords scp->repsPerFrame = (rand()%4)+1; //* Random spinning speed scp->frameCount = scp->repsPerFrame; scp->accelY = (rand()%6)+1; //* Random falling speed scp->ICSALop = coinFall; AliveLinkIn(scp); } //* //* Initialize plasma effect 'BLITTER BOY' character sprites //* charScp = GetSprite(NUM_CHARS); //* The letter 'B' sp = (scp = charScp)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 0; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 25+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'L' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 50; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 75+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'I' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 100; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 110+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'T' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 150; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 137+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'T' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 150; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 180+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'E' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 0; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 230+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'R' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 50; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 280+7; sp->y = 50; AliveLinkIn(scp); //* The letter 'B' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 0; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 100+13; sp->y = 180-8; AliveLinkIn(scp); //* The letter 'O' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 100; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 150+13; sp->y = 180-8; AliveLinkIn(scp); //* The letter 'Y' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 150; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 198+13; sp->y = 180-8; AliveLinkIn(scp); //* //* Initialize helmet and related sprites //* //* Face sprite (initially with DISPLAY_OFF) sp = (faceScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 100; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = HELMET_Y+43; AliveLinkIn(scp); //* Winking face sprite (initially with DISPLAY_OFF) sp = (winkScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 100; sp->v = timData[TIM_HELMET].py+26; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = HELMET_Y+43; AliveLinkIn(scp); //* Visor sprite sp = (visorScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 142; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = -80+43; //* Off top of screen to start scp->ICSALop = helmetDrop; AliveLinkIn(scp); //* Helmet sprite sp = (helmetScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 100; sp->h = 78; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 0; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X; sp->y = -80; //* Off top of screen to start scp->ICSALop = helmetDropSFX; AliveLinkIn(scp); //* Lightning bolt sprites (initially with DISPLAY_OFF) for (scp=boltScp=boltScp2=GetSprite(i=NUM_BOLTS); scp; scp=scp->freeLink, i--) { sp = scp->spriteLink; if (scp->freeLink) { sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_OFF); sp->g = sp->b = 128-(i*10); } else sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 34; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 142; sp->v = timData[TIM_HELMET].py+26; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->mx = sp->my = 17; sp->x = -17; sp->y = 113; sp->scalex = ONE+10440; sp->scaley = ONE+10440; scp->currLock = 1<<(i-1); //* Cue in 1 frame apart AliveLinkIn(scp); } //* Dust cloud sprites (initially with DISPLAY_OFF) for (i=1, scp=cloudScp=GetSprite(NUM_CLOUDS); scp; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_ON + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_OFF); sp->w = sp->h = 16; sp->tpage = GetTPage(0, 1, timData[TIM_GUNSMOKE].px, timData[TIM_GUNSMOKE].py); sp->u = 0; sp->v = timData[TIM_GUNSMOKE].py; sp->cx = timData[TIM_GUNSMOKE].cx; sp->cy = timData[TIM_GUNSMOKE].cy; sp->mx = sp->my = 8; scp->frameLock = LOCK_ALTFRAMES; scp->currLock = RunThisTime(scp->frameLock); scp->ICSALop = dustCloud; //* Individual cloud initializations switch (i) { //* First bounce dust cloud sprites case 1: scp->currLock = 1; sp->scalex = sp->scaley = -ONE*3; //* Reversed sp->x = HELMET_X+40; sp->y = HELMET_Y+78; break; case 2: scp->currLock = 1<<2; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 90; sp->x = HELMET_X+75; sp->y = HELMET_Y+74; break; case 3: scp->currLock = 1; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 50; sp->x = HELMET_X+60; sp->y = HELMET_Y+60; break; case 4: scp->currLock = 1<<4; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 80; sp->x = HELMET_X+20; sp->y = HELMET_Y+55; break; //* Second bounce dust cloud sprites case 5: scp->currLock = 1; sp->scalex = sp->scaley = -ONE<<1; //* Reversed sp->x = HELMET_X+25; sp->y = HELMET_Y+60; break; case 6: scp->currLock = 1<<2; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 90; sp->x = HELMET_X+70; sp->y = HELMET_Y+80; break; case 7: scp->currLock = 1; sp->scalex = sp->scaley = ONE*3; sp->r = sp->g = sp->b = 50; sp->x = HELMET_X+60; sp->y = HELMET_Y+60; break; //* Third bounce dust cloud sprites case 8: scp->currLock = 1; sp->scalex = sp->scaley = ONE<<1; sp->x = HELMET_X+40; sp->y = HELMET_Y+78; break; case 9: scp->currLock = 1<<2; sp->scalex = sp->scaley = -ONE<<1; //* Reversed sp->r = sp->g = sp->b = 90; sp->x = HELMET_X+80; sp->y = HELMET_Y+70; break; case 10: scp->currLock = 1; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 50; sp->x = HELMET_X+20; sp->y = HELMET_Y+60; break; } } //* Create text sprites (initially with DISPLAY_OFF) text1Scp = CentreText("OPERATION: MONSTER MALL", 212, -3); for (scp=text1Scp; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); } text2Scp = CentreText("PRESS [ OR START BUTTON", 212, -3); for (scp=text2Scp; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); } hSync=VSync(0); frameCnt = 0; pad = 0; //********** Main loop start ********** while (gameStat==GAME_TITLE_SCREEN) { lastPad = pad; pad = ReadPadStat(); if (!boltCue) { //* Wait until text has finished displaying... if (((pad & PAD1_START) && !(lastPad & PAD1_START)) //* Valid START pressed... || ((pad & PAD1_CROSS) && !(lastPad &PAD1_CROSS))) { //* Valid X pressed... gameStat = GAME_MENU_SCREEN; } } // if (pad & PAD1_L2) // VSync(20); // while (pad & PAD1_L1){ // pad=ReadPadStat(); // if (pad & PAD1_R2) // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); // } //* Cue in dust clouds at exactly the required time if (++frameCnt==6) { for (i=4; i; i--) { //* 4 clouds on 1st landing bounce AliveLinkIn(cloudScp); cloudScp = cloudScp->freeLink; } } else if (frameCnt==31) { for (i=3; i; i--) { //* 3 clouds on 2nd landing bounce AliveLinkIn(cloudScp); cloudScp = cloudScp->freeLink; } } else if (frameCnt==50) { for (i=3; i; i--) { //* 3 clouds on 3rd landing bounce AliveLinkIn(cloudScp); cloudScp = cloudScp->freeLink; } } else if (frameCnt==600) { //* Cue in rocking helmet ICSAL proc AliveLinkOut(faceScp); AliveLinkOut(winkScp); helmetScp->ICSALop = visorScp->ICSALop = boltScp->ICSALop = helmetRock; } //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, 128-(sp->r-1)); } //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //* Cue in character sprites if (charCue) --charCue; else if (charScp) { charScp->ICSALop = charFade; charScp = charScp->freeLink; charCue = 3; } //* Cue in "OPERATION: MONSTER MALL" sprites if (text1Cue) --text1Cue; else if (text1Scp) { text1Scp->ICSALop = textSlide; text1Scp = text1Scp->freeLink; text1Cue = 1; } //* Cue in "PRESS START" sprites if (text2Cue) --text2Cue; else if (text2Scp) { text2Scp->ICSALop = textSlide; text2Scp = text2Scp->freeLink; text2Cue = 1; } //* Cue in lightning bolt sprites if (boltCue) --boltCue; else if (boltScp2) for (i=NUM_BOLTS; i; i--) { boltScp2->ICSALop = boltSpiral; boltScp2 = boltScp2->freeLink; } //* Cue in winking sequence if (winkCue>0) --winkCue; else if (!winkCue) { //* First destroy unrequired (NUM_BOLTS-1) bolt sprites while (scp=boltScp->freeLink) { AliveLinkOut(boltScp); boltScp = scp; } visorScp->ICSALop = visorMove; winkScp->ICSALop = faceWink; faceScp->spriteLink->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); winkCue = -1; } //if(hSync>sSync) // sSync=hSync; } //********** Main loop terminal *********** //printf("\nslowest=%d\n",sSync); SsUtAllKeyOff(0); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Spin_Smudge(); } #define NUM_CONTROL_SPRITES (NUM_SPRITES+20) //*------------------------------------------------------------------------------------------ //* ControlScreen //*------------------------------------------------------------------------------------- void ControlScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() struct SCTRL *text1Scp; //* Pointer to 1st sprite in 'OPERATION: MONSTER MALL' group struct SCTRL *text2Scp; //* Pointer to 1st sprite in 'PRESS START' group struct SCTRL *text3Scp; struct SCTRL *text4Scp; struct SCTRL *text5Scp; struct SCTRL *text6Scp; struct SCTRL *text7Scp; struct SCTRL *text8Scp; u_long pad, lastPad; //* Takes controller pad status struct SCTRL *visorScp; //* Create title screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_CONTROL_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 7, NUM_CONTROL_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_CONTROL_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Initialize coin sprites i = NUM_COINS/3; x = 0; for (scp=GetSprite(NUM_COINS); scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 16; sp->h = 18; sp->tpage = GetTPage(0, 0, timData[TIM_COIN].px, timData[TIM_COIN].py); sp->u = 0; sp->v = timData[TIM_COIN].py; sp->cx = timData[TIM_COIN].cx; sp->cy = timData[TIM_COIN+x].cy; //* Set coin colour if (!--i) { //* Management to ensure an equal i = NUM_COINS/3; //* amount of the 3 coin colours x++; } sp->r = sp->g = sp->b = 32+(rand()%97); //* Random brightness (also OT priority) sp->x = -8 + (rand()%321); //* Random above-screen sp->y = -18 - (rand()%240); //* start coords scp->repsPerFrame = (rand()%4)+1; //* Random spinning speed scp->frameCount = scp->repsPerFrame; scp->accelY = (rand()%6)+1; //* Random falling speed scp->ICSALop = coinFallC; AliveLinkIn(scp); } //* Visor sprite sp = (visorScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 142; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = -80+43; //* Off top of screen to start //scp->ICSALop = helmetDrop; AliveLinkIn(scp); //* Create text sprites text1Scp = CentreText("CONTROLS:", 12, 4); for (scp=text1Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text2Scp = CentreText("[ = FIRE FORWARD", 56-6, -3); for (scp=text2Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text3Scp = CentreText("R2 + [ = STRAFE FIRE", 56+28-6, -3); for (scp=text3Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text4Scp = CentreText("\\ = JUMP", 56+28+28-6, -3); for (scp=text4Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text5Scp = CentreText("DIRECTIONAL BUTTON + ] =", 56+28+28+28-6, -3); for (scp=text5Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text7Scp = CentreText("ENERGY SPURT ", 56+28+28+28+20-6, -3); for (scp=text7Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text6Scp = CentreText("PRESS [ OR START BUTTON", 212-20, -3); for (scp=text6Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 60; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } text8Scp = CentreText("TO RETURN TO MENU", 212, -3); for (scp=text8Scp; scp; scp=scp->freeLink) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 60; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } hSync=VSync(0); pad = 0; //********** Main loop start ********** while (gameStat==GAME_CONTROL_SCREEN) { lastPad = pad; pad = ReadPadStat(); if (!text8Scp->ICSALop) { //* Wait until text has finished displaying... if (((pad & PAD1_START) && !(lastPad & PAD1_START)) //* Valid START pressed... || ((pad & PAD1_CROSS) && !(lastPad &PAD1_CROSS))) { //* Valid X pressed... SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); gameStat = GAME_MENU_SCREEN; } } // if (pad & PAD1_L2) // VSync(20); // while (pad & PAD1_L1){ // pad=ReadPadStat(); // if (pad & PAD1_R2) // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); // } //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, 128-(sp->r-1)); } //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //if(hSync>sSync) // sSync=hSync; } //********** Main loop terminal *********** //printf("\nslowest=%d\n",sSync); //SsUtAllKeyOff(0); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Splice_Screen(FX_RIP2_SPLICE); } #define NUM_CLOUDS (10) #define NUM_LEV_COINS (266) #define NUM_LEV_TEXT (50) #define NUM_LEV_EXTRAS (50) #define NUM_LEV_SPRITES (NUM_CLOUDS+NUM_LEV_COINS+NUM_LEV_TEXT+NUM_LEV_EXTRAS) //*------------------------------------------------------------------------------------------ //* LevelEndScreen //*------------------------------------------------------------------------------------- void LevelEndScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() struct SCTRL *visorScp; //* Pointer to visor sprite struct SCTRL *helmetScp; //* Pointer to helmet sprite struct SCTRL *faceScp; //* Pointer to normal face sprite struct SCTRL *winkScp; //* Pointer to winking face sprite struct SCTRL *blinkScp; //* Pointer to blinking face sprite struct SCTRL *cloudScp; //* Pointer to 1st sprite in dust cloud group struct SCTRL *text1Scp; //* Pointer to 1st sprite in 'NICE WORK, KID!' group struct SCTRL *text2Scp; //* Pointer to 1st sprite in 'PRESS START' group struct SCTRL *text3Scp; //* Pointer to 1st sprite in 'READY TO GO AGAIN?' group int winkCue=1*60+30; //* Vsync countdown until winking sequence activates int text1Cue=winkCue; //* Vsync countdown until text1 sprites activate int text2Cue=4*60-30; //* Vsync countdown until text2 sprites activate int frameCnt; //* Main loop counter used to cue clouds u_long pad, lastPad; //* Takes controller pad status //* Create title screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_LEV_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 7, NUM_LEV_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_LEV_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Initialize BG coin sprites x = 0; for (scp=GetSprite(NUM_LEV_COINS); scp; scp=scp->freeLink, x+=20) { scp->ICSALop = scp->ICSALloopStart = animCoinL; scp->ICSALloopCount = winkCue; sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 16; sp->h = 18; sp->tpage = GetTPage(0, 0, timData[TIM_COIN].px, timData[TIM_COIN].py); sp->u = 0; sp->v = timData[TIM_COIN].py; sp->x = ((x%380)-60) + (((x/380)&0x01)*10); //* x+10 for alternate rows sp->y = ((x/380)*20) + 1; sp->cx = timData[TIM_COIN].cx; sp->cy = timData[TIM_COIN].cy; sp->r = sp->g = sp->b = 0; //* Ready for fade-up scp->ID = 127; //* Is OT priority! AliveLinkIn(scp); } //* Helmet trans halo sprite sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_ON + A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); sp->w = 100; sp->h = 100; sp->x = HELMET_X+50; sp->y = HELMET_Y+43; sp->mx = 50; sp->my = 50; sp->r = 96; sp->g = 255; sp->b = 0; sp->scalex = ONE*3; sp->scaley = ONE*3; sp->tpage = GetTPage(0, 2, timData[TIM_HALO].px, timData[TIM_HALO].py); sp->v = timData[TIM_HALO].py; sp->u = ((timData[TIM_HALO].px<<2) % 256); sp->cx = timData[TIM_HALO].cx; sp->cy = timData[TIM_HALO].cy; scp->ID = 126; //* Is OT priority! AliveLinkIn(scp); //* //* Initialize helmet and related sprites //* //* Face sprite (initially with DISPLAY_OFF) sp = (faceScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 100; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = HELMET_Y+43; scp->ID = 15; //* Is OT priority! AliveLinkIn(scp); //* Blinking face sprite (initially with DISPLAY_OFF) sp = (blinkScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 100; sp->v = timData[TIM_HELMET].py+52; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = HELMET_Y+43; scp->ID = 14; //* Is OT priority! AliveLinkIn(scp); //* Winking face sprite (initially with DISPLAY_OFF) sp = (winkScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 100; sp->v = timData[TIM_HELMET].py+26; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = HELMET_Y+43; scp->ID = 13; //* Is OT priority! AliveLinkIn(scp); //* Visor sprite sp = (visorScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 42; sp->h = 26; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 142; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+29; sp->y = -80+43; //* Off top of screen to start scp->ICSALop = helmetDrop; scp->ID = 12; //* Is OT priority! AliveLinkIn(scp); //* Helmet sprite sp = (helmetScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 100; sp->h = 78; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 0; sp->v = timData[TIM_HELMET].py; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X; sp->y = -80; //* Off top of screen to start scp->ICSALop = helmetDropSFX; scp->ID = 11; //* Is OT priority! AliveLinkIn(scp); //* Helmet lightning bolt sprite sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = sp->h = 34; sp->tpage = GetTPage(1, 0, timData[TIM_HELMET].px, timData[TIM_HELMET].py); sp->u = 142; sp->v = timData[TIM_HELMET].py+26; sp->cx = timData[TIM_HELMET].cx; sp->cy = timData[TIM_HELMET].cy; sp->x = HELMET_X+35; sp->y = -80+12; //* Off top of screen to start scp->ICSALop = helmetDrop; scp->ID = 10; //* Is OT priority! AliveLinkIn(scp); //* Dust cloud sprites (initially with DISPLAY_OFF) for (i=1, scp=cloudScp=GetSprite(NUM_CLOUDS); scp; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_4BIT_CLUT + A_BRIGHT_ON + A_ROTATE_ON + A_TRATE_2 + A_TRANS_ON + A_DISPLAY_OFF); sp->w = sp->h = 16; sp->tpage = GetTPage(0, 1, timData[TIM_GUNSMOKE].px, timData[TIM_GUNSMOKE].py); sp->u = 0; sp->v = timData[TIM_GUNSMOKE].py; sp->cx = timData[TIM_GUNSMOKE].cx; sp->cy = timData[TIM_GUNSMOKE].cy; sp->mx = sp->my = 8; scp->frameLock = LOCK_ALTFRAMES; scp->currLock = RunThisTime(scp->frameLock); scp->ICSALop = dustCloud; //* Individual cloud initializations switch (i) { //* First bounce dust cloud sprites case 1: scp->currLock = 1; sp->scalex = sp->scaley = -ONE*3; //* Reversed sp->x = HELMET_X+40; sp->y = HELMET_Y+78; scp->ID = 9; //* Is OT priority! break; case 2: scp->currLock = 1<<2; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 90; sp->x = HELMET_X+75; sp->y = HELMET_Y+74; scp->ID = 16; //* Is OT priority! break; case 3: scp->currLock = 1; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 50; sp->x = HELMET_X+60; sp->y = HELMET_Y+60; scp->ID = 16; //* Is OT priority! break; case 4: scp->currLock = 1<<4; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 80; sp->x = HELMET_X+20; sp->y = HELMET_Y+55; scp->ID = 16; //* Is OT priority! break; //* Second bounce dust cloud sprites case 5: scp->currLock = 1; sp->scalex = sp->scaley = -ONE<<1; //* Reversed sp->x = HELMET_X+25; sp->y = HELMET_Y+60; scp->ID = 9; //* Is OT priority! break; case 6: scp->currLock = 1<<2; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 90; sp->x = HELMET_X+70; sp->y = HELMET_Y+80; scp->ID = 16; //* Is OT priority! break; case 7: scp->currLock = 1; sp->scalex = sp->scaley = ONE*3; sp->r = sp->g = sp->b = 50; sp->x = HELMET_X+60; sp->y = HELMET_Y+60; scp->ID = 16; //* Is OT priority! break; //* Third bounce dust cloud sprites case 8: scp->currLock = 1; sp->scalex = sp->scaley = ONE<<1; sp->x = HELMET_X+40; sp->y = HELMET_Y+78; scp->ID = 9; //* Is OT priority! break; case 9: scp->currLock = 1<<2; sp->scalex = sp->scaley = -ONE<<1; //* Reversed sp->r = sp->g = sp->b = 90; sp->x = HELMET_X+80; sp->y = HELMET_Y+70; scp->ID = 16; //* Is OT priority! break; case 10: scp->currLock = 1; sp->scalex = sp->scaley = ONE<<1; sp->r = sp->g = sp->b = 50; sp->x = HELMET_X+20; sp->y = HELMET_Y+60; scp->ID = 16; //* Is OT priority! break; } } //* Create text sprites (initially with DISPLAY_OFF) text1Scp = CentreText("NICE WORK, KID!", 30, 1); for (scp=text1Scp; scp; scp=scp->freeLink) { scp->ID = 0; //* Is OT priority! sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->y -= 6; sp->w += 1; //* Hack to get full char width displayed! sp->scaley = ONE+3615; } //* Create text sprites (initially with DISPLAY_OFF) text3Scp = CentreText("READY TO GO AGAIN?", 170, 1); for (scp=text3Scp; scp; scp=scp->freeLink) { scp->ID = 0; //* Is OT priority! sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->y -= 6; sp->w += 1; //* Hack to get full char width displayed! sp->scaley = ONE+3615; } text2Scp = CentreText("PRESS [ OR START BUTTON", 212, -3); for (scp=text2Scp; scp; scp=scp->freeLink) { scp->ID = 0; //* Is OT priority! sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } hSync=VSync(0); frameCnt = 0; pad = 0; //********** Main loop start ********** while (gameStat==GAME_LEVEL_UP) { lastPad = pad; pad = ReadPadStat(); //if (pad & PAD1_L1) { //* pause/screen grab // while ((pad=ReadPadStat()) & PAD1_L1) // if(pad & PAD1_SELECT) { // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); // VSync(60); // } //} if (!text2Cue) { //* Wait until text has finished displaying... if (((pad & PAD1_START) && !(lastPad & PAD1_START)) //* Valid START pressed... || ((pad & PAD1_CROSS) && !(lastPad &PAD1_CROSS))) { //* Valid X pressed... SsUtKeyOn(0, SFX_LEV_SCREEN, 0, 58, 0, 127, 127); gameStat = GAME_ON; } } //if (pad & PAD1_L2) // VSync(20); //while (pad & PAD1_L1) // pad=ReadPadStat(); //* Cue in dust clouds at exactly the required time if (++frameCnt==6) for (i=4; i; i--) { //* 4 clouds on 1st landing bounce AliveLinkIn(cloudScp); cloudScp = cloudScp->freeLink; } else if (frameCnt==31) for (i=3; i; i--) { //* 3 clouds on 2nd landing bounce AliveLinkIn(cloudScp); cloudScp = cloudScp->freeLink; } else if (frameCnt==50) for (i=3; i; i--) { //* 3 clouds on 3rd landing bounce AliveLinkIn(cloudScp); cloudScp = cloudScp->freeLink; } //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, scp->ID); } //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //* Cue in text sprites if (text1Cue) --text1Cue; else { if (text1Scp) { text1Scp->ICSALop = textFromR; text1Scp = text1Scp->freeLink; text1Cue = 1; } if (text3Scp) { text3Scp->ICSALop = textFromR; text3Scp = text3Scp->freeLink; text1Cue = 1; } } //* Cue in "PRESS START" sprites if (text2Cue) --text2Cue; else if (text2Scp) { text2Scp->ICSALop = textFromR; text2Scp = text2Scp->freeLink; text2Cue = 1; } //* Cue in winking sequence if (winkCue>0) --winkCue; else if (!winkCue) { visorScp->ICSALop = visorOpen; blinkScp->ICSALop = faceBlink; faceScp->spriteLink->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); winkCue = -1; } //printf("%d...",hSync); //if(hSync>sSync) // sSync=hSync; } //********** Main loop terminal *********** //printf("\nslowest=%d\n",sSync); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Splice_Screen(FX_NORMAL_SPLICE); } #define HAND_PRI (1) #define CHAR_PRI (2) #define TEXT_PRI (3) #define OPTS_PRI (4) #define BOX_PRI (5) #define NUM_MENU_TEXT (50) #define NUM_MENU_SPRITES (NUM_COINS+NUM_CHARS+NUM_MENU_TEXT+NUM_EXTRAS) //*------------------------------------------------------------------------------------------ //* MenuScreen //*------------------------------------------------------------------------------------- void MenuScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure struct SCTRL *temp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() struct SCTRL *charScp; //* Pointer to 1st character sprite in group int charCue=1; //* Vsync countdown until character sprites activate int handCue=60*3+10; u_long pad, lastPad; //* Takes current/previous controller pad status struct SCTRL *handScp; struct SCTRL *optScp; struct SCTRL *textScp[5]; int option=0; GsBOXF box; //* Create menu screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_MENU_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 8, NUM_MENU_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_MENU_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Initialize transparent BG box box.attribute = (A_TRANS_ON + A_TRATE_1 + A_DISPLAY_ON); box.w = 260; box.h = 132; box.x = 30; box.y = 100; box.r = box.g = box.b = 0; //* Initialize coin sprites (initially with DISPLAY_OFF) i = NUM_COINS/3; x = 0; for (scp=GetSprite(NUM_COINS); scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 16; sp->h = 18; sp->tpage = GetTPage(0, 0, timData[TIM_COIN].px, timData[TIM_COIN].py); sp->u = 0; sp->v = timData[TIM_COIN].py; sp->cx = timData[TIM_COIN].cx; sp->cy = timData[TIM_COIN+x].cy; //* Set coin colour if (!--i) { //* Management to ensure an equal i = NUM_COINS/3; //* amount of the 3 coin colours x++; } sp->r = sp->g = sp->b = 32+(rand()%97); //* Random brightness (also OT priority) sp->x = -8 + (rand()%321); //* Random above-screen sp->y = -18 - (rand()%240); //* start coords scp->repsPerFrame = (rand()%4)+1; //* Random spinning speed scp->frameCount = scp->repsPerFrame; scp->accelY = (rand()%6)+1; //* Random falling speed scp->ICSALop = coinFall2; AliveLinkIn(scp); } //* //* Initialize plasma effect 'BLITTER BOY' character sprites //* charScp = GetSprite(NUM_CHARS); //* The letter 'B' sp = (scp = charScp)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 0; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 25+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'L' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 50; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 75+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'I' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 100; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 110+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'T' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 150; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 137+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'T' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 150; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 180+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'E' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 0; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 230+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'R' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 50; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 280+7; sp->y = 29; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'B' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 0; sp->v = timData[TIM_BB_CHARS].py; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 100+13; sp->y = 63+12; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'O' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 100; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 150+13; sp->y = 63+12; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* The letter 'Y' sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->w = sp->h = 50; sp->tpage = GetTPage(1, 0, timData[TIM_BB_CHARS].px, timData[TIM_BB_CHARS].py); sp->u = 150; sp->v = timData[TIM_BB_CHARS].py+50; sp->cx = timData[TIM_BB_CHARS].cx; sp->cy = timData[TIM_BB_CHARS].cy; sp->mx = sp->my = 25; sp->x = 198+13; sp->y = 63+12; scp->ID = CHAR_PRI; AliveLinkIn(scp); //* Create text sprites textScp[0] = LjustText("START GAME", 70, 116, 1); for (scp=textScp[0]; scp; scp=scp->freeLink) { scp->ID = TEXT_PRI; scp->ICSALop = textOnMenuR; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = 0; sp->g = 128; } if (gameType == MODE_MISSION) textScp[1] = LjustText("MODE: MISSION", 70, 116+20, 1); else textScp[1] = LjustText("MODE: SURVIVE", 70, 116+20, 1); for (scp=textScp[1]; scp; scp=scp->freeLink) { scp->ID = TEXT_PRI; scp->ICSALop = textOnMenuL; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x -= 320; //* Move off to left of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = 0; sp->g = 128; } textScp[2] = LjustText("MOVE SCREEN", 70, 116+40, 1); for (scp=textScp[2]; scp; scp=scp->freeLink) { scp->ID = TEXT_PRI; scp->ICSALop = textOnMenuR; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = 0; sp->g = 128; } textScp[3] = LjustText("HIGH SCORES", 70, 116+60, 1); for (scp=textScp[3]; scp; scp=scp->freeLink) { scp->ID = TEXT_PRI; scp->ICSALop = textOnMenuL; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x -= 320; //* Move off to left of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = 0; sp->g = 128; } textScp[4] = LjustText("CONTROLS", 70, 116+80, 1); for (scp=textScp[4]; scp; scp=scp->freeLink) { scp->ID = TEXT_PRI; scp->ICSALop = textOnMenuR; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = 0; sp->g = 128; } //* Hand sprite sp = (handScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 32; sp->h = 24; sp->tpage = GetTPage(0, 0, timData[TIM_HAND].px, timData[TIM_HAND].py); sp->u = ((timData[TIM_HAND].px<<2) % 256); sp->v = timData[TIM_HAND].py; sp->cx = timData[TIM_HAND].cx; sp->cy = timData[TIM_HAND].cy; sp->x = 28; sp->y = 115; scp->ICSALop = animHand; scp->ID = HAND_PRI; //* 'X SELECT' sprite sp = (optScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 52; sp->h = 11; sp->tpage = GetTPage(0, 0, timData[TIM_PSX_OPTS].px, timData[TIM_PSX_OPTS].py); sp->u = ((timData[TIM_PSX_OPTS].px<<2) % 256); sp->v = timData[TIM_PSX_OPTS].py; sp->cx = timData[TIM_PSX_OPTS].cx; sp->cy = timData[TIM_PSX_OPTS].cy; sp->x = 134; sp->y = 217; scp->ID = OPTS_PRI; hSync=VSync(0); pad = 0; //********** Main loop start ********** while (gameStat==GAME_MENU_SCREEN) { lastPad = pad; pad = ReadPadStat(); if (pad & PAD1_SELECT) gameStat = GAME_QUIT; if (pad & PAD1_L2) VSync(20); if (pad & PAD1_L1) { //* pause/screen grab while ((pad=ReadPadStat()) & PAD1_L1) if(pad & PAD1_SELECT) { StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); VSync(60); } } if (handScp->alive) { //* Only act on button presses when hand sprite is visible... if ((pad & PAD1_DOWN) && !(lastPad & PAD1_DOWN)) { //* Valid DOWN pressed... //* Reset hand sprite animation handScp->spriteLink->x = 28; handScp->ICSALop = animHand; //* Set the current menu option spinning for (scp=textScp[option]; scp; scp=scp->freeLink) { scp->ICSALop = menuSpin; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 0; sp->g = 128; } //* Move hand sprite to point at new option if (++option > 4) { option = 0; handScp->spriteLink->y = 115; } else { handScp->spriteLink->y += 20; } //* Make sure new option is not spinning for (scp=textScp[option]; scp; scp=scp->freeLink) { scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 96; //* Highlight new option sp->g = 128; } SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } else if ((pad & PAD1_UP) && !(lastPad & PAD1_UP)) { //* Valid UP pressed... //* Reset hand sprite animation handScp->spriteLink->x = 28; handScp->ICSALop = animHand; //* Set the current menu option spinning for (scp=textScp[option]; scp; scp=scp->freeLink) { scp->ICSALop = menuSpin; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 0; sp->g = 128; } //* Move hand sprite to point at new option if (--option < 0) { option = 4; handScp->spriteLink->y = 195; } else { handScp->spriteLink->y -= 20; } //* Make sure new option is not spinning for (scp=textScp[option]; scp; scp=scp->freeLink) { scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 96; //* Highlight new option sp->g = 128; } SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } if ((pad & PAD1_CROSS) && !(lastPad & PAD1_CROSS)) { //* Valid X pressed... //* Deal with selected option switch (option) { case 0: //* START GAME SsUtKeyOn(0, SFX_WOOHOO, 0, 60, 0, 127, 127); gameStat = GAME_START; break; case 1: //* MODE: MISSION/SURVIVE //* Kill all option text sprites for (scp=textScp[1]; scp; scp=temp) { temp = scp->freeLink; AliveLinkOut(scp); } //* Toggle game type & create new option text sprites if ((gameType^=1) == MODE_SURVIVE) textScp[1] = LjustText("MODE: SURVIVE", 70, 116+20, 1); else textScp[1] = LjustText("MODE: MISSION", 70, 116+20, 1); //* Alterations to new option text sprites for (scp=textScp[1]; scp; scp=scp->freeLink) { scp->ID = TEXT_PRI; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = 96; sp->g = 128; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; } SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); break; case 2: //* MOVE SCREEN SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); gameStat = GAME_MOVE_SCREEN; break; case 3: //* HIGH SCORES SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); gameStat = GAME_HISCORE_SCREEN; break; case 4: //* CONTROLS SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); gameStat = GAME_CONTROL_SCREEN; break; } } //* Program termination if((pad & PAD1_SELECT) && (pad & PAD1_START)) { gameStat = GAME_END; break; } } //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, (scp->ID ? scp->ID : 256-(sp->r-1))); } GsSortBoxFill(&box, currOT, BOX_PRI); //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //* Cue in BLITTER BOY character sprites if (charCue) --charCue; else if (charScp) { charScp->ICSALop = charFade2; charScp = charScp->freeLink; charCue = 10; } //* Cue in hand sprite etc... if (handCue) --handCue; else if (!handScp->alive) { for (scp=textScp[0]; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->r = sp->b = 96; //* Highlight 1st option text sprites } AliveLinkIn(handScp); //* Show hand sprite AliveLinkIn(optScp); //* Show 'X SELECT' sprite } //if(hSync>sSync) { // sSync=hSync; // printf("\nslowest=%d",sSync); //} } //********** Main loop terminal *********** // SsUtAllKeyOff(0); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment } #define NUM_MOVE_SPRITES (50) //*------------------------------------------------------------------------------------------ //* MoveScreen //*------------------------------------------------------------------------------------- void MoveScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() u_long pad, lastPad; //* Takes current/previous controller pad status struct SCTRL *text1Scp; GsBOXF box; int saveX, saveY; //* Create move screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_MOVE_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 8, NUM_MOVE_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_MOVE_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Init purple backgroung box box.attribute = (A_TRANS_OFF + A_DISPLAY_ON); box.w = 316; box.h = 236; box.x = 2; box.y = 2; box.r = 100; box.g = 0; box.b = 200; //* Create text sprites text1Scp = CentreText("POSITION SCREEN", 80, -1); for (scp=text1Scp; scp; scp=scp->freeLink) { scp->ICSALop = textFromR; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now } text1Scp = CentreText("USING THE", 112, -1); for (scp=text1Scp; scp; scp=scp->freeLink) { scp->ICSALop = textFromR; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now } text1Scp = CentreText("DIRECTIONAL BUTTON", 144, -1); for (scp=text1Scp; scp; scp=scp->freeLink) { scp->ICSALop = textFromR; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now } //* 'X SELECT' sprite sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 52; sp->h = 11; sp->tpage = GetTPage(0, 0, timData[TIM_PSX_OPTS].px, timData[TIM_PSX_OPTS].py); sp->u = ((timData[TIM_PSX_OPTS].px<<2) % 256); sp->v = timData[TIM_PSX_OPTS].py; sp->cx = timData[TIM_PSX_OPTS].cx; sp->cy = timData[TIM_PSX_OPTS].cy; sp->x = 104; sp->y = 217; AliveLinkIn(scp); //* BACK sprite sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 44; sp->h = 11; sp->tpage = GetTPage(0, 0, timData[TIM_PSX_OPTS].px, timData[TIM_PSX_OPTS].py); sp->u = ((timData[TIM_PSX_OPTS].px<<2) % 256); sp->v = timData[TIM_PSX_OPTS].py+11; sp->cx = timData[TIM_PSX_OPTS].cx; sp->cy = timData[TIM_PSX_OPTS].cy; sp->x = 172; sp->y = 217; AliveLinkIn(scp); pad = 0; saveX = GsDISPENV.screen.x; saveY = GsDISPENV.screen.y; //********** Main loop start ********** while (gameStat==GAME_MOVE_SCREEN) { lastPad = pad; pad = ReadPadStat(); if (!text1Scp->ICSALop) { //* Wait for text to finish displaying... if ((pad & PAD1_DOWN) && !(lastPad & PAD1_DOWN)) { //* Valid DOWN pressed... if (GsDISPENV.screen.y < 48) { ++GsDISPENV.screen.y; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 84, 0, 100, 100); } } else if ((pad & PAD1_UP) && !(lastPad & PAD1_UP)) { //* Valid UP pressed... if (GsDISPENV.screen.y > 0) { --GsDISPENV.screen.y; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 84, 0, 100, 100); } } else if ((pad & PAD1_LEFT) && !(lastPad & PAD1_LEFT)) { //* Valid LEFT pressed... if (GsDISPENV.screen.x > -11) { --GsDISPENV.screen.x; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 84, 0, 100, 100); } } else if ((pad & PAD1_RIGHT) && !(lastPad & PAD1_RIGHT)) { //* Valid RIGHT pressed... if (GsDISPENV.screen.x < 11) { ++GsDISPENV.screen.x; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 84, 0, 100, 100); } } if ((pad & PAD1_CROSS) && !(lastPad & PAD1_CROSS)) { //* Valid X pressed... gameStat = GAME_MENU_SCREEN; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); } else if ((pad & PAD1_TRIANGLE) && !(lastPad & PAD1_TRIANGLE)) { //* Valid tri pressed... GsDISPENV.screen.x = saveX; GsDISPENV.screen.y = saveY; gameStat = GAME_MENU_SCREEN; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); } } //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, 0); } GsSortBoxFill(&box, currOT, 1); DrawSync(0); //* Wait for GPU to finish drawing VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(255, 255, 255, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); } //********** Main loop terminal *********** // SsUtAllKeyOff(0); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Pixel_Out(0, 0, 0); } #define NUM_SCORE_SPRITES (70) #define NUM_HI_SPRITES (NUM_COINS+NUM_SCORE_SPRITES+200) //*------------------------------------------------------------------------------------------ //* HiscoreScreen //*------------------------------------------------------------------------------------- void HiscoreScreen(void) { int i, n, x, y; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp, *scp2; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() u_long pad, lastPad; //* Takes current/previous controller pad status struct SCTRL *text1Scp; GsBOXF box; char scrs[] = "1234567"; //* Holds sprintf() converted score chars char *strp; //* Destructible copy of scrs int wait; //* Create menu screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_HI_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 8, NUM_HI_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_HI_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Init box.attribute = (A_TRANS_ON + A_TRATE_1 + A_DISPLAY_ON); box.w = 256; box.h = 128; box.x = 32; box.y = 72; box.r = box.g = box.b = 0; //* Initialize coin sprites (initially with DISPLAY_OFF) i = NUM_COINS/3; x = 0; for (scp=GetSprite(NUM_COINS); scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 16; sp->h = 18; sp->tpage = GetTPage(0, 0, timData[TIM_COIN].px, timData[TIM_COIN].py); sp->u = 0; sp->v = timData[TIM_COIN].py; sp->cx = timData[TIM_COIN].cx; sp->cy = timData[TIM_COIN+x].cy; //* Set coin colour if (!--i) { //* Management to ensure an equal i = NUM_COINS/3; //* amount of the 3 coin colours x++; } sp->r = sp->g = sp->b = 32+(rand()%97); //* Random brightness (also OT priority) sp->x = -8 + (rand()%321); //* Random above-screen sp->y = -18 - (rand()%240); //* start coords scp->repsPerFrame = (rand()%4)+1; //* Random spinning speed scp->frameCount = scp->repsPerFrame; scp->accelY = (rand()%6)+1; //* Random falling speed scp->ICSALop = coinFallH; AliveLinkIn(scp); } //* Create text sprites text1Scp = CentreText("\"GOOD LITTLE EARNERS\"", 16, -1); for (i=1, scp=text1Scp; scp; scp=scp->freeLink, i+=4) { scp->ID = 1; scp->ICSALop = scp->ICSALloopStart = textOnHi; scp->ICSALloopCount = i; sp = scp->spriteLink; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->g = sp->b = 0; sp->r = 128; sp->scaley = ONE<<1; } text1Scp = CentreText("PRESS [ OR START BUTTON", 212, -3); for (i=1, scp=text1Scp; scp; scp=scp->freeLink, i++) { sp = scp->spriteLink; if (i!=6) { sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->b = 0; sp->g = 128; } sp->x += 320; //* Move off to right of screen for now scp->ID = 1; scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = 60; } //* 'THE RICH & FAMOUS ROLL OF HONOUR!' sprite sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 200; sp->h = 9; sp->tpage = GetTPage(0, 0, timData[TIM_BB_ROLL].px, timData[TIM_BB_ROLL].py); sp->u = ((timData[TIM_BB_ROLL].px<<2) % 256); sp->v = timData[TIM_BB_ROLL].py; sp->cx = timData[TIM_BB_ROLL].cx; sp->cy = timData[TIM_BB_ROLL].cy; sp->x = 60-320; sp->y = 52; scp->ICSALop = textFromL; scp->ID = 1; AliveLinkIn(scp); //* Initialize the 5 score and name sprites y = 80+240; wait = 1; for (n=0; n<5; n++, y+=24, wait+=8) { sprintf(scrs, "%7.7d", hiScore[n].score); strp = scrs; hiScore[n].sScp = GetSprite(10); x = 48; //* Initialize each score digit sprite... for (i=0, scp=hiScore[n].sScp; i<10; i++, scp=scp->freeLink) { sp = scp->spriteLink; scp->ICSALop = scp->ICSALloopStart = textSlideUp; scp->ICSALloopCount = wait; scp->ID = 1; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->y = y; sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_SCORESET].px, timData[TIM_SCORESET].py); sp->v = timData[TIM_SCORESET].py; sp->cx = timData[TIM_SCORESET].cx; sp->cy = timData[TIM_SCORESET].cy; switch (i) { case 0: //* 'millions' digit sp->x = x+17; sp->w = 16; sp->u = (*strp++ - '0')<<4; break; case 1: case 2: case 3: //* 'thousands' digits sp->x = x+((i+1)*17)+4; sp->w = 16; sp->u = (*strp++ - '0')<<4; break; case 4: case 5: case 6: //* 'hundreds' 'tens' 'units' digits sp->x = x+((i+1)*17)+8; sp->w = 16; sp->u = (*strp++ - '0')<<4; break; case 7: //* $ sign sp->x = x; sp->w = 16; sp->u = 160; break; case 8: //* 1st comma (5x7) sp->x = x+33; sp->y += 11; sp->w = 5; sp->h = 7; sp->v += 9; sp->u = 176; break; case 9: //* 2nd comma (5x7) sp->x = x+88; sp->y += 11; sp->w = 5; sp->h = 7; sp->v += 9; sp->u = 176; break; } AliveLinkIn(scp); } scp2 = hiScore[n].nScp = LjustText(hiScore[n].name, 204, y, 1); for (; scp2; scp2=scp2->freeLink) { scp2->ICSALop = scp2->ICSALloopStart = textSlideUp; scp2->ICSALloopCount = wait; scp2->ID = 1; } } hSync=VSync(0); sSync=1; pad = 0; //********** Main loop start ********** while (gameStat==GAME_HISCORE_SCREEN) { lastPad = pad; pad = ReadPadStat(); //if (pad & PAD1_L1) { //* pause/screen grab // while ((pad=ReadPadStat()) & PAD1_L1) // if(pad & PAD1_SELECT) { // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); // VSync(60); // } //} if (!text1Scp->ICSALop) { //* Only act on button presses when text has displayed... if (((pad & PAD1_START) && !(lastPad & PAD1_START)) //* Valid START pressed... || ((pad & PAD1_CROSS) && !(lastPad & PAD1_CROSS))) { //* Valid X pressed... gameStat = GAME_MENU_SCREEN; SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); } } //if (pad & PAD1_SELECT) // gameStat = GAME_QUIT; //if (pad & PAD1_L2) // VSync(20); //while (pad & PAD1_L1){ // pad=ReadPadStat(); //if (pad & PAD1_R2) // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); //} //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, (scp->ID ? scp->ID : 256-(sp->r-1))); } GsSortBoxFill(&box, currOT, 10); //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //if(hSync>sSync) { // sSync=hSync; // printf("\nslowest=%d",sSync); //} } //********** Main loop terminal *********** // SsUtAllKeyOff(0); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Pixel_Out(0, 0, 0); } #define NUM_ES_TEXT (69) #define NUM_ES_SPRITES (NUM_COINS+NUM_ES_TEXT+50) //*------------------------------------------------------------------------------------------ //* EnterScoreScreen //*------------------------------------------------------------------------------------- void EnterScoreScreen(void) { int i, n, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() int handCue=60+30; struct SCTRL *handScp; struct SCTRL *optScp; struct SCTRL *charScp[5][6]; struct SCTRL *scoreScp; u_long pad, lastPad; //* Takes controller pad status struct SCTRL *initialScp[4]; GsBOXF box; int pointRow, pointCol; int trueX; char scrs[] = "1234567"; //* Holds sprintf() converted score chars char *strp; //* Destructible copy of scrs char initials[] = "----"; int currInitial=0; //* Create title screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_ES_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 8, NUM_ES_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_ES_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Init box box.attribute = (A_TRANS_ON + A_TRATE_1 + A_DISPLAY_ON); box.w = 288; box.h = 142; box.x = 16; box.y = 84; box.r = box.g = box.b = 0; //* Initialize coin sprites i = NUM_COINS/3; x = 0; for (scp=GetSprite(NUM_COINS); scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 16; sp->h = 18; sp->tpage = GetTPage(0, 0, timData[TIM_COIN].px, timData[TIM_COIN].py); sp->u = 0; sp->v = timData[TIM_COIN].py; sp->cx = timData[TIM_COIN].cx; sp->cy = timData[TIM_COIN+x].cy; //* Set coin colour if (!--i) { //* Management to ensure an equal i = NUM_COINS/3; //* amount of the 3 coin colours x++; } sp->r = sp->g = sp->b = 32+(rand()%97); //* Random brightness (also OT priority) sp->x = -8 + (rand()%321); //* Random above-screen sp->y = -18 - (rand()%240); //* start coords scp->repsPerFrame = (rand()%4)+1; //* Random spinning speed scp->frameCount = scp->repsPerFrame; scp->accelY = (rand()%6)+1; //* Random falling speed scp->ICSALop = coinFallE; AliveLinkIn(scp); } //* Create text sprites scp = CentreText("WOW! YOU MADE", 16, 1); for (i=1; scp; scp=scp->freeLink, i+=4) { scp->ID = TEXT_PRI; scp->ICSALop = scp->ICSALloopStart = textOnHi; scp->ICSALloopCount = i; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->g = sp->b = 0; sp->r = 128; } scp = CentreText("ENTER YOUR INITIALS!", 16+40, 1); for (i=1; scp; scp=scp->freeLink, i+=4) { scp->ID = TEXT_PRI; scp->ICSALop = scp->ICSALloopStart = textOnHi; scp->ICSALloopCount = i; sp = scp->spriteLink; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->g = sp->b = 0; sp->r = 128; } scp = CentreText(initials, 16+68+4, 1); for (i=0; scp; scp=scp->freeLink, i++) { initialScp[i] = scp; scp->ID = TEXT_PRI; sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); } scp = LjustText("A B C D E F", 48, 116, 0); for (i=0; scp; scp=scp->freeLink, i++) { scp->ID = TEXT_PRI; charScp[0][i] = scp; scp->ICSALop = scp->ICSALloopStart = textSlideUp; scp->ICSALloopCount = 1; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->y += 240; //* Move off bottom of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->b = 0; sp->g = 128; } scp = LjustText("G H I J K L", 48, 136, 0); for (i=0; scp; scp=scp->freeLink, i++) { scp->ID = TEXT_PRI; charScp[1][i] = scp; scp->ICSALop = scp->ICSALloopStart = textSlideUp; scp->ICSALloopCount = 8; sp = scp->spriteLink; if (i==2) sp->x += 4; if (i>2) sp->x += 7; sp->mx = sp->my = 8; sp->y += 240; //* Move off bottom of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->b = 0; sp->g = 128; } scp = LjustText("M N O P Q R", 48, 156, 0); for (i=0; scp; scp=scp->freeLink, i++) { scp->ID = TEXT_PRI; charScp[2][i] = scp; scp->ICSALop = scp->ICSALloopStart = textSlideUp; scp->ICSALloopCount = 16; sp = scp->spriteLink; if (i==3) sp->x += 1; if (i>3) sp->x += 2; sp->mx = sp->my = 8; sp->y += 240; //* Move off bottom of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->b = 0; sp->g = 128; } scp = LjustText("S T U V W X", 48, 176, 0); for (i=0; scp; scp=scp->freeLink, i++) { scp->ID = TEXT_PRI; charScp[3][i] = scp; scp->ICSALop = scp->ICSALloopStart = textSlideUp; scp->ICSALloopCount = 24; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->y += 240; //* Move off bottom of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->b = 0; sp->g = 128; } scp = LjustText("Y Z ! . - #", 48, 196, 0); for (i=0; scp; scp=scp->freeLink, i++) { scp->ID = TEXT_PRI; charScp[4][i] = scp; scp->ICSALop = scp->ICSALloopStart = textSlideUp; scp->ICSALloopCount = 32; sp = scp->spriteLink; if (i==2) sp->x += 4; if (i==3) sp->x += 12; if (i==4) sp->x += 18; if (i==5) sp->x += 18; sp->mx = sp->my = 8; sp->y += 240; //* Move off bottom of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->b = 0; sp->g = 128; } //* Hand sprite sp = (handScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 32; sp->h = 24; sp->tpage = GetTPage(0, 0, timData[TIM_HAND].px, timData[TIM_HAND].py); sp->u = ((timData[TIM_HAND].px<<2) % 256); sp->v = timData[TIM_HAND].py; sp->cx = timData[TIM_HAND].cx; sp->cy = timData[TIM_HAND].cy; sp->x = trueX = 6; sp->y = 99+16; scp->ICSALop = animHand; scp->ID = HAND_PRI; //* 'X SELECT' sprite sp = (optScp = scp = GetSprite(2))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 52; sp->h = 11; sp->tpage = GetTPage(0, 0, timData[TIM_PSX_OPTS].px, timData[TIM_PSX_OPTS].py); sp->u = ((timData[TIM_PSX_OPTS].px<<2) % 256); sp->v = timData[TIM_PSX_OPTS].py; sp->cx = timData[TIM_PSX_OPTS].cx; sp->cy = timData[TIM_PSX_OPTS].cy; sp->x = 104; sp->y = 212; scp->ID = OPTS_PRI; //* BACK sprite sp = (scp = scp->freeLink)->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 44; sp->h = 11; sp->tpage = GetTPage(0, 0, timData[TIM_PSX_OPTS].px, timData[TIM_PSX_OPTS].py); sp->u = ((timData[TIM_PSX_OPTS].px<<2) % 256); sp->v = timData[TIM_PSX_OPTS].py+11; sp->cx = timData[TIM_PSX_OPTS].cx; sp->cy = timData[TIM_PSX_OPTS].cy; sp->x = 172; sp->y = 212; scp->ID = OPTS_PRI; //currScore = 1000001; //* Initialize each score digit sprite... sprintf(scrs, "%7.7d", currScore); strp = scrs; x = 89-320; for (i=0, scp=scoreScp=GetSprite(10); i<10; i++, scp=scp->freeLink) { sp = scp->spriteLink; scp->ICSALop = textFromL; scp->ID = TEXT_PRI; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->y = 36; sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_SCORESET].px, timData[TIM_SCORESET].py); sp->v = timData[TIM_SCORESET].py; sp->cx = timData[TIM_SCORESET].cx; sp->cy = timData[TIM_SCORESET].cy; switch (i) { case 0: //* 'millions' digit sp->x = x+17; sp->w = 16; sp->u = (*strp++ - '0')<<4; break; case 1: case 2: case 3: //* 'thousands' digits sp->x = x+((i+1)*17)+4; sp->w = 16; sp->u = (*strp++ - '0')<<4; break; case 4: case 5: case 6: //* 'hundreds' 'tens' 'units' digits sp->x = x+((i+1)*17)+8; sp->w = 16; sp->u = (*strp++ - '0')<<4; break; case 7: //* $ sign sp->x = x; sp->w = 16; sp->u = 160; break; case 8: //* 1st comma (5x7) sp->x = x+33; sp->y += 11; sp->w = 5; sp->h = 7; sp->v += 9; sp->u = 176; break; case 9: //* 2nd comma (5x7) sp->x = x+88; sp->y += 11; sp->w = 5; sp->h = 7; sp->v += 9; sp->u = 176; break; } AliveLinkIn(scp); } hSync=VSync(0); pad = 0; sSync = 1; pointRow = pointCol = 0; //********** Main loop start ********** while (gameStat==GAME_ENTER_SCORE_SCREEN) { lastPad = pad; pad = ReadPadStat(); if (handScp->alive) { //* Wait until hand is displaying... if ((pad & PAD1_DOWN) && !(lastPad & PAD1_DOWN)) { //* Valid DOWN pressed... //* Reset hand sprite animation handScp->spriteLink->x = trueX; handScp->ICSALop = animHand; //* Set the current char spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = menuSpin; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 0; sp->g = 128; //* Move hand sprite to point at new char if (++pointRow > 4) { pointRow = 0; handScp->spriteLink->y -= 80; } else { handScp->spriteLink->y += 20; } //* Make sure new option is not spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 96; //* Highlight new option sp->g = 128; SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } else if ((pad & PAD1_UP) && !(lastPad & PAD1_UP)) { //* Valid UP pressed... //* Reset hand sprite animation handScp->spriteLink->x = trueX; handScp->ICSALop = animHand; //* Set the current char spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = menuSpin; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 0; sp->g = 128; //* Move hand sprite to point at new char if (--pointRow < 0) { pointRow = 4; handScp->spriteLink->y += 80; } else { handScp->spriteLink->y -= 20; } //* Make sure new option is not spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 96; //* Highlight new option sp->g = 128; SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } else if ((pad & PAD1_RIGHT) && !(lastPad & PAD1_RIGHT)) { //* Valid RIGHT pressed... //* Set the current char spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = menuSpin; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 0; sp->g = 128; //* Move hand sprite to point at new char if (++pointCol > 5) { pointCol = 0; trueX = (handScp->spriteLink->x = trueX - 240); } else { trueX = (handScp->spriteLink->x = trueX + 48); } handScp->ICSALop = animHand; //* Make sure new option is not spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 96; //* Highlight new option sp->g = 128; SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } else if ((pad & PAD1_LEFT) && !(lastPad & PAD1_LEFT)) { //* Valid LEFT pressed... //* Set the current char spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = menuSpin; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 0; sp->g = 128; //* Move hand sprite to point at new char if (--pointCol < 0) { pointCol = 5; trueX = (handScp->spriteLink->x = trueX + 240); } else { trueX = (handScp->spriteLink->x = trueX - 48); } handScp->ICSALop = animHand; //* Make sure new option is not spinning scp = charScp[pointRow][pointCol]; scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->b = 96; //* Highlight new option sp->g = 128; SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } if ((pad & PAD1_CROSS) && !(lastPad &PAD1_CROSS)) { //* Valid X pressed... sp = initialScp[currInitial]->spriteLink; sp->u = charScp[pointRow][pointCol]->spriteLink->u; sp->v = charScp[pointRow][pointCol]->spriteLink->v; switch (i=((pointRow*6)+pointCol)) { case 26: i = '!'; break; case 27: i = '.'; break; case 28: i = '-'; break; case 29: i = initials[currInitial]; gameStat = GAME_MENU_SCREEN; break; default: i += 'A'; break; } initials[currInitial] = i; currInitial += (currInitial==3?0:1); SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); } else if ((pad & PAD1_TRIANGLE) && !(lastPad &PAD1_TRIANGLE)) {//* Valid ^ pressed... sp = initialScp[currInitial]->spriteLink; sp->u = charScp[4][4]->spriteLink->u; sp->v = charScp[4][4]->spriteLink->v; initials[currInitial] = '-'; currInitial -= (currInitial?1:0); SsUtKeyOn(0, SFX_COMPUTER, 0, 72, 0, 100, 100); } } // if (pad & PAD1_L2) // VSync(20); // while (pad & PAD1_L1){ // pad=ReadPadStat(); // if (pad & PAD1_R2) // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); // } //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, (scp->ID ? scp->ID : 256-(sp->r-1))); } GsSortBoxFill(&box, currOT, BOX_PRI); //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //* Cue in hand sprite etc... if (handCue) --handCue; else if (!handScp->alive) { sp = charScp[pointRow][pointCol]->spriteLink; sp->r = sp->b = 96; //* Highlight start char sprite AliveLinkIn(handScp); //* Show hand sprite AliveLinkIn(optScp); //* Show 'X SELECT' sprite AliveLinkIn(optScp->freeLink); //* Show BACK sprite for (i=0; i<4; i++) { sp = initialScp[i]->spriteLink; sp->attribute ^= A_DISPLAY_OFF; } } //if(hSync>sSync) { // sSync=hSync; // printf("\nslowest=%d\n",sSync); //} } //********** Main loop terminal *********** //printf("\n%s", initials); //SsUtAllKeyOff(0); for (i=0; i<5; i++) { if (currScore > hiScore[i].score) { for (n=4; n>i; n--) hiScore[n] = hiScore[n-1]; strcpy(hiScore[i].name, initials); hiScore[i].score = currScore; break; } } //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Splice_Screen(FX_MELT_SPLICE); } #define NUM_FLAGS (391) #define NUM_DEBRIEF_SPRITES (200+NUM_FLAGS) //*------------------------------------------------------------------------------------------ //* DebriefScreen //*------------------------------------------------------------------------------------- void DebriefScreen(void) { int i, x; //* Working variables int activeBuff; //* Current buffer index (toggles between 0 and 1) int hSync=0; //* Debug mode: holds execution speed in hsyncs GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure struct SCTRL *textScp; //* Pointer to 'PRESS A BUTTON' text GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() u_long pad, lastPad; //* Takes controller pad status int charShow; //* Used to set delay counter for each chars ICSAL int min, sec; GsBOXF box; char timeStr[] = "SURVIVE TIME ??????"; char flagStr[] = "FLAGS REACHED ?????"; char killStr[] = "MONSTER KILLS ?????"; char rateStr[] = "RATING ????????????"; char *ratingStr[] = { "UTTER PANTS!", "THUMB SUCKER", "SMALL FRY", "PRETTY BOY", "GOOD BOY", "MONSTER MASH", "BRAVE HEART", "WAR MONGER", "TOP GUN", "IMMORTAL!" }; //* Create title screen sprite & sprite control arrays OpenSpriteArray(&sprt, NUM_DEBRIEF_SPRITES, &sCtrl); //* Create an OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 2, NUM_DEBRIEF_SPRITES); //* Initialize free sprite linked list freeSprites = NULL; for (i=NUM_DEBRIEF_SPRITES-1; i>=0; i--) { PutSprite(&sCtrl[i]); } aliveSprites = NULL; //* Reset list plasRect.x = plasmaBase; //* Reset plasma CLUT to original MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Initialize flag sprites x = 0; for (scp=GetSprite(NUM_FLAGS); scp; scp=scp->freeLink, x+=16) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 16; sp->h = 14; sp->tpage = GetTPage(0, 0, timData[TIM_FLAG].px, timData[TIM_FLAG].py); sp->u = 0; sp->v = timData[TIM_FLAG].py; sp->x = ((x%368)-48) + (((x/368)&0x01)<<3); //* x+8 for alternate rows sp->y = ((x/368)<<4) + 1; sp->cx = timData[TIM_FLAG].cx; sp->cy = timData[TIM_FLAG].cy; sp->r = sp->g = sp->b = 128; scp->ID = 3; //* Is OT priority! scp->ICSALop = animFlagD; AliveLinkIn(scp); } //* Init box box.attribute = (A_TRANS_ON + A_TRATE_1 + A_DISPLAY_ON); box.w = 0; box.h = 184; box.x = 16; box.y = 16; box.r = box.g = box.b = 0; //* Complete info strings surviveFrames /= FRAMES_PER_SEC; sec = (surviveFrames-((min=surviveFrames/60)*60)); sprintf(&timeStr[13], "%d:%.2d", min, sec); sprintf(&flagStr[14], "%d", flagCnt); sprintf(&killStr[14], "%d", killCount); i = flagCnt>=180 ? 9 : flagCnt/20; strcpy(&rateStr[7], ratingStr[i]); //* Create text sprites (initially with DISPLAY_OFF) scp = CentreText("DEBRIEFING:", 24, 1); for (charShow=60; scp; scp=scp->freeLink, charShow+=4) { scp->ICSALop = scp->ICSALloopStart = textType; scp->ICSALloopCount = charShow; scp->ID = 1; //* Is OT priority! sp = scp->spriteLink; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->r = sp->b = 96; sp->g = 128; } scp = CentreText(timeStr, 60, -1); for (charShow+=20, i=0; scp; scp=scp->freeLink, charShow+=4, i++) { scp->ICSALop = scp->ICSALloopStart = textType; scp->ICSALloopCount = charShow; scp->ID = 1; //* Is OT priority! sp = scp->spriteLink; if (i>=11) { sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->y -= 6; sp->w += 1; //* Hack to get full char width displayed! sp->scaley = ONE+3615; } else { sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->r = sp->b = 0; sp->g = 128; } } scp = CentreText(flagStr, 96, -1); for (charShow+=20, i=0; scp; scp=scp->freeLink, charShow+=4, i++) { scp->ICSALop = scp->ICSALloopStart = textType; scp->ICSALloopCount = charShow; scp->ID = 1; //* Is OT priority! sp = scp->spriteLink; if (i>=12) { sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->y -= 6; sp->w += 1; //* Hack to get full char width displayed! sp->scaley = ONE+3615; } else { sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->r = sp->b = 0; sp->g = 128; } } scp = CentreText(killStr, 132, -1); for (charShow+=20, i=0; scp; scp=scp->freeLink, charShow+=4, i++) { scp->ICSALop = scp->ICSALloopStart = textType; scp->ICSALloopCount = charShow; scp->ID = 1; //* Is OT priority! sp = scp->spriteLink; if (i>=12) { sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->y -= 6; sp->w += 1; //* Hack to get full char width displayed! sp->scaley = ONE+3615; } else { sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->r = sp->b = 0; sp->g = 128; } } scp = CentreText(rateStr, 168, -1); for (charShow+=20, i=0; scp; scp=scp->freeLink, charShow+=4, i++) { scp->ICSALop = scp->ICSALloopStart = textType; scp->ICSALloopCount = charShow; scp->ID = 1; //* Is OT priority! sp = scp->spriteLink; if (i>=6) { sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->y -= 6; sp->w += 1; //* Hack to get full char width displayed! sp->scaley = ONE+3615; } else { sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->r = sp->b = 0; sp->g = 128; } } textScp = scp = CentreText("PRESS [ OR START BUTTON", 212, -3); for (charShow+=20, i=1; scp; scp=scp->freeLink, i++) { scp->ICSALop = scp->ICSALloopStart = controlText; scp->ICSALloopCount = charShow; scp->ID = 1; //* Is OT priority! sp = scp->spriteLink; if (i!=6) { sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->r = sp->g = 128; sp->b = 0; } sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); } VSync(0); hSync = sSync = 0; pad = 0; SsUtAllKeyOff(0); SsUtKeyOn(0, SFX_PEEL_SCREEN, 0, 91, 0, 127, 127); //********** Main loop start ********** while (gameStat==GAME_DEBRIEF_SCREEN) { lastPad = pad; pad = ReadPadStat(); if (!textScp->ICSALop) { //* Wait until text has finished displaying... if (((pad & PAD1_START) && !(lastPad & PAD1_START)) //* Valid START pressed... || ((pad & PAD1_CROSS) && !(lastPad &PAD1_CROSS))) { //* Valid X pressed... gameStat = GAME_TITLE_SCREEN; } } //* Open message box if (box.w < 288) box.w += 8; // if (pad & PAD1_L2) // VSync(20); // while (pad & PAD1_L1) // pad=ReadPadStat(); //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, scp->ID); } GsSortBoxFill(&box, currOT, 2); //* Rotate plasma clut entries if (++plasRect.x==(plasmaBase+224)) plasRect.x = plasmaBase; //* wrap-around MoveImage(&plasRect, plasmaX, plasmaY); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Register CLS in OT (last in, first out) GsSortClear(0, 0, 0, currOT); //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //if(hSync>sSync) // sSync=hSync; } //********** Main loop terminal *********** //printf("\nslowest=%d\n",sSync); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprt, sCtrl); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment FX_Pixel_Out(0, 0, 0); } #define CONTROL_ERROR_SPRITES (50) //*------------------------------------------------------------------------------------------ //* ControlErrorScreen //*------------------------------------------------------------------------------------- void ControlErrorScreen(void) { int i; //* Working variables GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure int activeBuff; //* Current buffer index (toggles between 0 and 1) GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() GsSPRITE *sprtCE; //* Pointer to control error sprites (separate from game) struct SCTRL *sCtrlCE; //* Pointer to control error sprite control structs struct SCTRL *trueAlive; struct SCTRL *trueFree; GsBOXF box; //* Save game sprite linked list heads trueAlive = aliveSprites; trueFree = freeSprites; //* Create new sprite pool for control error (CE) sprites OpenSpriteArray(&sprtCE, CONTROL_ERROR_SPRITES, &sCtrlCE); //* Create new OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 1, CONTROL_ERROR_SPRITES); //* Initialize CE free sprite linked list freeSprites = NULL; for (i=CONTROL_ERROR_SPRITES-1; i>=0; i--) { PutSprite(&sCtrlCE[i]); } aliveSprites = NULL; //* Reset CE alive sprite list //* Initialize BG transparent box box.attribute = (A_TRANS_ON + A_TRATE_1 + A_DISPLAY_ON); box.w = 320; box.h = 240; box.x = box.y = 0; box.r = box.g = box.b = 0; //* Initialize messsage text sprites scp = CentreText("PLEASE PLUG A", 92, -3); for (; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = sp->g = 128; } scp = CentreText("STANDARD OR ANALOG", 112, -3); for (; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = sp->g = 128; } scp = CentreText("CONTROLLER INTO PORT 1", 132, -3); for (; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->b = sp->g = 128; } DrawSync(0); //* Finish drawing current game scene //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Add alive sprites and BG box to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) GsSortFastSprite(scp->spriteLink, currOT, 0); GsSortBoxFill(&box, currOT, 0); GsDrawOt(currOT); //* Overlay CE screen onto newly rendered scene DrawSync(0); //* Wait for GPU to finish drawing VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprtCE, sCtrlCE); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment //* Re-install game sprite linked list heads aliveSprites = trueAlive; freeSprites = trueFree; } #define BUFF_SIZE (153600) //* (320*240)*2=153600 #define COPY_X (320) #define COPY_Y (0) //* VRAM coords of frame copy (top-left corner) #define QUIT_TEXT_PRI (0) #define PS_HAND_PRI (1) #define PS_TEXT_PRI (2) #define PS_OPTS_PRI (3) #define PS_BOX_PRI (4) #define PS_PAUSE_PRI (5) #define PS_FUZZ_PRI (6) #define PAUSE_SCREEN_SPRITES (200) //*------------------------------------------------------------------------------------------ //* PauseScreen //*------------------------------------------------------------------------------------- void PauseScreen(void) { register int i, x; //* Working variables //register u_long *imageBuffp; //* Heap mem address of stored Tpages int hSync=0; //* Debug mode: holds execution speed in hsyncs RECT tpRect; //* Texture page rectangle area u_long pad, lastPad; //* Takes controller pad status struct SCTRL *handScp; struct SCTRL *optScp; struct SCTRL *quitScp1; struct SCTRL *quitScp2; struct SCTRL *fuzzScp; int quitFlag=0; struct SCTRL *textScp[2]; int option=0; GsSPRITE *sp; //* Working pointer to a GsSPRITE object struct SCTRL *scp; //* Working pointer to a SCTRL structure int activeBuff; //* Current buffer index (toggles between 0 and 1) GsOT *currOT; //* Pointer to the current OT header PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; //* Pointers to the 2 OT headers - initialized by OpenOT() GsSPRITE *sprtPS; //* Pointer to pause acreen sprites (separate from game) struct SCTRL *sCtrlPS; //* Pointer to pause screen sprite control structs struct SCTRL *trueAlive; struct SCTRL *trueFree; u_long psdcntSave; int handCue=40; GsBOXF box; int vramX, vramY; int distX[] = { //* Horizontal distortion curve X offsets 26,23,20,19,17,16,14,13,12,11, 10,9,8,7,6,6,6,5,4,4, 3,3,2,2,2,2,1,1,1,1 }; psdcntSave = *psdcnt; //* Allocate enough heap mem to hold Tpage contents that //* will be over-written by frame copy // if ((imageBuffp = (u_long *) malloc(BUFF_SIZE))==NULL) { // printf("\nFailed to allocate memory to store frame buffer\n"); // return; // } // // //* Store original Tpage contents into heap buffer // tpRect.w = 320; // tpRect.h = 240; // tpRect.x = COPY_X; // tpRect.y = COPY_Y; // StoreImage(&tpRect, imageBuffp); // DrawSync(0); //* Make copy of new frame at COPY_X,COPY_Y in Tpages tpRect.x = 0; tpRect.w = 320; tpRect.h = 240; tpRect.y = *psdidx * 240; MoveImage(&tpRect, COPY_X, COPY_Y); DrawSync(0); //* Save game sprite linked list heads trueAlive = aliveSprites; trueFree = freeSprites; //* Create new sprite pool for pause screen (PS) sprites OpenSpriteArray(&sprtPS, PAUSE_SCREEN_SPRITES, &sCtrlPS); //* Create new OT environment: 2 OT headers, 2 OTs, 2 packet buffers OpenOT(OTs, buffs, 3, PAUSE_SCREEN_SPRITES); //* Initialize PS free sprite linked list freeSprites = NULL; for (i=PAUSE_SCREEN_SPRITES-1; i>=0; i--) { PutSprite(&sCtrlPS[i]); } aliveSprites = NULL; //* Reset PS alive sprite list //* Initialize transparent BG boxes box.attribute = (A_TRANS_ON + A_TRATE_1 + A_DISPLAY_ON); box.w = 210; box.h = 72; box.x = 55; box.y = 84; box.r = box.g = box.b = 0; //* Create MENU text sprites textScp[0] = LjustText("CONTINUE", 95, 100, 1); for (scp=textScp[0]; scp; scp=scp->freeLink) { scp->ID = PS_TEXT_PRI; scp->ICSALop = textFromR; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x += 320; //* Move off to right of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->g = 0; sp->b = 128; } textScp[1] = LjustText("QUIT GAME", 95, 120, 1); for (scp=textScp[1]; scp; scp=scp->freeLink) { scp->ID = PS_TEXT_PRI; scp->ICSALop = textFromL; sp = scp->spriteLink; sp->mx = sp->my = 8; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->x -= 320; //* Move off to left of screen for now sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->r = sp->g = 0; sp->b = 128; } //* Create QUIT? text sprites (DISPLAY_OFF for now) quitScp1 = CentreText("REALLY QUIT?", 102, 1); for (scp=quitScp1; scp; scp=scp->freeLink) { scp->ID = QUIT_TEXT_PRI; sp = scp->spriteLink; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); sp->g = sp->r = 0; sp->b = 128; } quitScp2 = CentreText("[YES ^NO", 102+20, 1); for (scp=quitScp2, i=1; scp; scp=scp->freeLink, i++) { scp->ID = QUIT_TEXT_PRI; sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_8BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_OFF); if (i==1 || i==5) //* Button sprites use original CLUT continue; sp->cx = timData[TIM_MASK256].cx; sp->cy = timData[TIM_MASK256].cy; sp->g = sp->r = 0; sp->b = 128; } //* Hand sprite sp = (handScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 32; sp->h = 24; sp->tpage = GetTPage(0, 0, timData[TIM_HAND].px, timData[TIM_HAND].py); sp->u = ((timData[TIM_HAND].px<<2) % 256); sp->v = timData[TIM_HAND].py; sp->cx = timData[TIM_HAND].cx; sp->cy = timData[TIM_HAND].cy; sp->x = 53; sp->y = 99; scp->ICSALop = animHand; scp->ID = PS_HAND_PRI; //* 'X SELECT' sprite sp = (optScp = scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 52; sp->h = 11; sp->tpage = GetTPage(0, 0, timData[TIM_PSX_OPTS].px, timData[TIM_PSX_OPTS].py); sp->u = ((timData[TIM_PSX_OPTS].px<<2) % 256); sp->v = timData[TIM_PSX_OPTS].py; sp->cx = timData[TIM_PSX_OPTS].cx; sp->cy = timData[TIM_PSX_OPTS].cy; sp->x = 134; sp->y = 141; scp->ID = PS_OPTS_PRI; //* PAUSE || sprite sp = (scp = GetSprite(1))->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp->w = 90; sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_PAUSE].px, timData[TIM_PAUSE].py); sp->u = ((timData[TIM_PAUSE].px<<2) % 256); sp->v = timData[TIM_PAUSE].py; sp->cx = timData[TIM_PAUSE].cx; sp->cy = timData[TIM_PAUSE].cy; sp->x = 115; sp->y = 34; scp->ID = PS_PAUSE_PRI; scp->ICSALop = flashPause; scp->frameLock = scp->currLock = 0x10001000; //* Flash every 16 frames AliveLinkIn(scp); //* White noise screen fuzz sprites vramX = ((timData[TIM_WNOISE].px<<2) % 256); //* .px<<2 because 4bit = 4 pixels per VRAM pixel vramY = (timData[TIM_WNOISE].py & 0xff); fuzzScp = GetSprite(100); for (scp=fuzzScp, i=0; i<20; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp->x = i<<4; sp->y = 16; sp->w = sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_WNOISE].px, timData[TIM_WNOISE].py); sp->cx = timData[TIM_WNOISE].cx; sp->cy = timData[TIM_WNOISE].cy; sp->r = sp->g = sp->b = 128; scp->ID = PS_FUZZ_PRI; scp->ICSALop = pauseFuzz; AliveLinkIn(scp); } for (i=0; i<20; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp->x = i<<4; sp->y = 32; sp->w = sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_WNOISE].px, timData[TIM_WNOISE].py); sp->cx = timData[TIM_WNOISE].cx; sp->cy = timData[TIM_WNOISE].cy; sp->r = sp->g = sp->b = 255; scp->ID = PS_FUZZ_PRI; scp->ICSALop = pauseFuzz; AliveLinkIn(scp); } for (i=0; i<20; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp->x = i<<4; sp->y = 48; sp->w = sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_WNOISE].px, timData[TIM_WNOISE].py); sp->cx = timData[TIM_WNOISE].cx; sp->cy = timData[TIM_WNOISE].cy; sp->r = sp->g = sp->b = 128; scp->ID = PS_FUZZ_PRI; scp->ICSALop = pauseFuzz; AliveLinkIn(scp); } for (i=0; i<20; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp->x = i<<4; sp->y = 64; sp->w = 16; sp->h = 8; sp->tpage = GetTPage(0, 0, timData[TIM_WNOISE].px, timData[TIM_WNOISE].py); sp->cx = timData[TIM_WNOISE].cx; sp->cy = timData[TIM_WNOISE].cy; sp->r = sp->g = sp->b = 100; scp->ID = PS_FUZZ_PRI; scp->ICSALop = pauseFuzz; AliveLinkIn(scp); } for (i=0; i<20; scp=scp->freeLink, i++) { sp = scp->spriteLink; sp->attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp->x = i<<4; sp->y = 184; sp->w = sp->h = 16; sp->tpage = GetTPage(0, 0, timData[TIM_WNOISE].px, timData[TIM_WNOISE].py); sp->cx = timData[TIM_WNOISE].cx; sp->cy = timData[TIM_WNOISE].cy; sp->r = sp->g = sp->b = 128; scp->ID = PS_FUZZ_PRI; scp->ICSALop = pauseFuzz; AliveLinkIn(scp); } hSync=VSync(0); sSync=1; pad = 0; SsUtAllKeyOff(0); //* Kill all game SFX SsUtKeyOn(0, SFX_CART, 0, 76, 0, 127, 127); //* Play PAUSE SFX //********** Main loop start ********** while (1) { lastPad = pad; pad = ReadPadStat(); //if (pad & PAD1_L1) { //* pause/screen grab // while ((pad=ReadPadStat()) & PAD1_L1) // if(pad & PAD1_SELECT) { // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); // VSync(60); // } //} if (handScp->alive) { //* Only act on button presses after hand sprite is cued in... if (quitFlag) { //* REALLY QUIT? option is showing... if ((pad & PAD1_TRIANGLE) && !(lastPad & PAD1_TRIANGLE)) { //* Valid ^ pressed... SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); //* Hide quit confirmation sprites for (scp=quitScp1; scp; scp=scp->freeLink) scp->spriteLink->attribute ^= A_DISPLAY_OFF; for (scp=quitScp2; scp; scp=scp->freeLink) scp->spriteLink->attribute ^= A_DISPLAY_OFF; //* Show menu sprites for (scp=textScp[0]; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute ^= A_DISPLAY_OFF; sp->r = sp->g = 96; //* Highlight 1st option text sp->b = 128; sp->scalex = sp->scaley = ONE; scp->ICSALop = NULL; } for (scp=textScp[1]; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->attribute ^= A_DISPLAY_OFF; sp->r = sp->g = 0; sp->b = 128; scp->ICSALop = NULL; } optScp->spriteLink->attribute ^= A_DISPLAY_OFF; handScp->spriteLink->attribute ^= A_DISPLAY_OFF; //* Reset hand sprite animation handScp->spriteLink->x = 53; handScp->spriteLink->y = 99; handScp->ICSALop = animHand; option = 0; quitFlag = 0; } else if ((pad & PAD1_CROSS) && !(lastPad & PAD1_CROSS)) { //* Valid X pressed... SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); gameStat = GAME_QUIT; break; } } else { //* Menu is showing only... //* Note: START always acts as UNPAUSE! if ((pad & PAD1_START) && !(lastPad & PAD1_START)) { //* Valid START pressed... SsUtKeyOn(0, SFX_CART, 0, 76, 0, 127, 127); break; } //* Note: only 2 options so UP and DOWN have same functionality! if (((pad & PAD1_DOWN) && !(lastPad & PAD1_DOWN)) //* Valid DOWN pressed... || ((pad & PAD1_UP) && !(lastPad & PAD1_UP))) { //* Valid UP pressed... //* Reset hand sprite animation handScp->spriteLink->x = 53; handScp->ICSALop = animHand; //* Set the current menu option spinning for (scp=textScp[option]; scp; scp=scp->freeLink) { scp->ICSALop = menuSpinB; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->g = 0; sp->b = 128; } //* Move hand sprite to point at new option option ^= 0x00000001; //* Toggle between 0 and 1 handScp->spriteLink->y = (option ? 119 : 99); //* Make sure new option is not spinning for (scp=textScp[option]; scp; scp=scp->freeLink) { scp->ICSALop = NULL; sp = scp->spriteLink; sp->scalex = sp->scaley = ONE; sp->r = sp->g = 96; //* Highlight new option sp->b = 128; } SsUtKeyOn(0, SFX_GUN_NORMAL, 0, 84, 0, 100, 100); SsUtKeyOn(0, SFX_EVAP, 0, 50, 0, 127, 127); } if ((pad & PAD1_CROSS) && !(lastPad & PAD1_CROSS)) { //* Valid X pressed... //* Deal with selected option if (option) { //* QUIT GAME selected... SsUtKeyOn(0, SFX_GUN_RAINBOW, 0, 72, 0, 100, 100); //* Hide menu sprites for (scp=textScp[0]; scp; scp=scp->freeLink) scp->spriteLink->attribute ^= A_DISPLAY_OFF; for (scp=textScp[1]; scp; scp=scp->freeLink) scp->spriteLink->attribute ^= A_DISPLAY_OFF; optScp->spriteLink->attribute ^= A_DISPLAY_OFF; handScp->spriteLink->attribute ^= A_DISPLAY_OFF; //* Show quit confirmation sprites for (scp=quitScp1; scp; scp=scp->freeLink) scp->spriteLink->attribute ^= A_DISPLAY_OFF; for (scp=quitScp2; scp; scp=scp->freeLink) scp->spriteLink->attribute ^= A_DISPLAY_OFF; quitFlag = 1; } else { //* CONTINUE selected... SsUtKeyOn(0, SFX_CART, 0, 76, 0, 127, 127); break; } } } } //if (pad & PAD1_SELECT) // gameStat = GAME_QUIT; //if (pad & PAD1_L2) // VSync(20); //while (pad & PAD1_L1) // pad=ReadPadStat(); //if (pad & PAD1_R2) // StoreScreen ((u_long *)0x80090000, 0, !*psdidx*240, 320, 240); //} //* Set pointer to current ordering table header currOT = OTs[activeBuff = GsGetActiveBuff()]; //* Set primitive creation area GsSetWorkBase(buffs[activeBuff]); //* Clear ordering table GsClearOt(0, 0, currOT); //* Service active, ICSAL-controlled sprites ServiceICSALsprites(); //* Set random u,v (within bounds of 64x64 tile) for white noise fuzz sprites for (scp=fuzzScp; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->u = vramX + (rand() % 48); sp->v = vramY + (rand() % 48); } //* Add alive sprites to OT for (scp=aliveSprites; scp; scp=scp->aliveLinkF) { sp = scp->spriteLink; //* Call GsSortSprite if sprite has rotation else call GsSortFastSprite (*primSort[!(sp->attribute & A_ROTATE_OFF)]) (sp, currOT, scp->ID); } GsSortBoxFill(&box, currOT, PS_BOX_PRI); DrawSync(0); //* Wait for GPU to finish drawing hSync = VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers //* Before drawing, copy stored BG frame to draw buffer //* Note: the copy destination Y coord is offset with a toggled //* value (0 or 2) to create an authentic VCR PAUSE screen wobble effect! tpRect.x = COPY_X; tpRect.y = COPY_Y; tpRect.w = 320; tpRect.h = 238; MoveImage(&tpRect, 0, psdofsy[*psdidx]+(*psdidx<<1)); //* Simulate horizontal distortion on alternate frames if (!*psdidx) { for (i=0; i<30; i++) { x = distX[i]; tpRect.x = COPY_X+x; tpRect.y = COPY_Y+200+i; tpRect.w = 320-x; tpRect.h = 1; MoveImage(&tpRect, 0, psdofsy[0]+200+i); } } //* Set GPU to start drawing primitives registered in OT GsDrawOt(currOT); //* Cue in hand sprite etc... if (handCue) --handCue; else if (!handScp->alive) { for (scp=textScp[0]; scp; scp=scp->freeLink) { sp = scp->spriteLink; sp->r = sp->g = 96; //* Highlight 1st option text sprites } AliveLinkIn(handScp); //* Show hand sprite AliveLinkIn(optScp); //* Show 'X SELECT' sprite } //if(hSync>sSync) // sSync=hSync; //printf("%d.", hSync); } //********** Main loop terminal *********** //printf("\nslowest=%d\n",sSync); //* Return final pad status to PadActions() so START wont cause an immediate pause pStat = pad; //* Return stored frame to draw buffer tpRect.x = COPY_X; tpRect.y = COPY_Y; tpRect.w = 320; tpRect.h = 240; MoveImage(&tpRect, 0, psdofsy[*psdidx]); //* Restore original Tpage contents from mem // tpRect.x = COPY_X; // tpRect.y = COPY_Y; // tpRect.w = 320; // tpRect.h = 240; // LoadImage(&tpRect, imageBuffp); // DrawSync(0); // // //* Free Tpage buffer memory // free(imageBuffp); //* Housekeeping: DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sprtPS, sCtrlPS); //* Free memory used by sprite & sprite control arrays CloseOT(OTs[0], buffs[0]); //* Free memory used by OT environment //* Re-install game sprite linked list heads aliveSprites = trueAlive; freeSprites = trueFree; //* Report to rest of system that no game time has elapsed *psdcnt = psdcntSave; //* Restart TV SFX loop if it was playing when PAUSE was pressed if (tvVoice) { tvVoice = SsUtKeyOn(0, SFX_TELEVATOR, 0, 60, 0, 100, 100); } }