// Bouncer II - main control routine v1 // Coded by Scott Evans 1/6/97 // Last modified 28/6/97 // Header files for my various routines #include #include #include <2dgfx.h> #include #include #include #include #include // Contains #defines for this file #include "header.h" // Set up a block which has been hit by bloke // Make it transparent and spin it off screen void DestroyBlock(SpriteBG *b,_word r,_word c,_word blkid,SprImgOff *offsets,_byte *rtable,SprINFO *sprinfo) { static _byte blkno=0; // Replace block with bit of the background _SetBlockId(b,r,c,BACKBLKS); // Maximum number of rotating blocks on screen at same time is NDBLKS blkno++; blkno%=NDBLKS; // Set up a sprite in place of block sprinfo->spr[BLOCKspr+blkno].x=(c<<4)+8; sprinfo->spr[BLOCKspr+blkno].y=(r<<4)+8; sprinfo->spr[BLOCKspr+blkno].u=offsets[blkid].u; sprinfo->spr[BLOCKspr+blkno].v=offsets[blkid].v; sprinfo[BLOCKspr+blkno].on=1; // Use random lookup table for horizontal speed sprinfo[BLOCKspr+blkno].xspd=(_GetRand(rtable,RANDTABLESIZE)%4)+4; sprinfo->spr[BLOCKspr+blkno].rotate=0; sprinfo->spr[BLOCKspr+blkno].scalex=ONE; sprinfo->spr[BLOCKspr+blkno].scaley=ONE; // Set movement of sprite if(sprinfo[BLOKEspr].xspd<0) sprinfo[BLOCKspr+blkno].xspd=-sprinfo[BLOCKspr+blkno].xspd; sprinfo[BLOCKspr+blkno].yspd=-((_GetRand(rtable,RANDTABLESIZE)%8)+2); } SprHeader *sprhdr=(SprHeader *)SPRITEBANK; LevelHeader *lvlhdr=(LevelHeader *)LEVELBANK; GsSPRITE sprites[MAXspr]; SprINFO sprinfo[MAXspr],*info; // Animation string for sprites _byte animations[]={38,39,40,41,42,43,44,45,46,47,48}; SpriteBG bg; RECT r1; GsGLINE line,line1; void main(void) { // Set up an ordering table and packet buffer GsOT *mainOT=InitOT(OTLENGTH); PACKET *packetBuff=InitPktBuff(MAXPKTS); if(mainOT && packetBuff) { _byte currentBuff,stop=0,fctr=0,flag=1,blkno=0,*rtable,clrblk=0,side; GsOT *ot; GsSPRITE *batspr=&sprites[BATspr],*blokespr=&sprites[BLOKEspr]; PACKET *pktbuff; _word animdelay,i,padmask,nospr,tpage,n,r,c; __word tx=TPAGEx,ty=TPAGEy,x,y,blokey,tmphgt=10,blkid; SprImgOff offsets[_GetNoSpr(sprhdr)]; __byte bmaxyspd=10; SprPblk *pblk; LevelPblk *lvlpblk=_GetLevelPblks(lvlhdr); _word px,py,bx,by; // Set up graphics system InitGraphics(MODE_PAL,SCRW,SCRH,GsOFSGPU|GsNONINTER,0,0); // Set up controllers _InitControllers; // Load sprites palette Load4bitCLUT(sprhdr,CLUTx,CLUTy); // Load sprites LoadSprites(_GetSprPblks(sprhdr),_GetNoSpr(sprhdr),&tx,&ty,offsets); // Set up a table of random numbers rtable=InitRandLookup(RANDTABLESIZE); RandOffset=rand(); // Set up various sprite information _SetSprINFO(&sprinfo[BLOKEspr],animations+BMVING,5,43,ON,OFF,0,BLOKExspd,0,&sprites[BLOKEspr]); _SetSprINFO(&sprinfo[BATspr],0,0,BATfrm,ON,OFF,0,BATxspd,0,&sprites[BATspr]); _SetSprINFO(&sprinfo[STARTspr],0,0,STARTsprImg,ON,OFF,0,0,0,&sprites[STARTspr]); _SetSPRITE(&sprites[STARTspr],noEffects,(_GetRand(rtable,RANDTABLESIZE)<<1)%(SCRW-16),BottomScrLimit-16,16,16,tpage=GetTPage(0,0,tx,ty),offsets[STARTsprImg].u, offsets[STARTsprImg].v,CLUTx,_GetSprCLUTy(sprhdr,STARTsprImg,CLUTy),0x80,0x80,0x80, 0,0,ONE,ONE,0); pblk=_GetSprPblk(sprhdr,(n=sprinfo[BLOKEspr].currfrm)); _SetSPRITE(&sprites[BLOKEspr],noEffects,sprites[STARTspr].x,(sprites[STARTspr].y-pblk->h)<w,pblk->h, tpage,offsets[n].u,offsets[n].v,CLUTx,_GetSprCLUTy(sprhdr,n,CLUTy), 0x80,0x80,0x80,0,0,ONE,ONE,0); pblk=_GetSprPblk(sprhdr,(n=sprinfo[BATspr].currfrm)); _SetSPRITE(&sprites[BATspr],noEffects,SCRW>>1,BottomScrLimit-pblk->h-1,pblk->w,pblk->h, tpage,offsets[n].u,offsets[n].v,CLUTx,_GetSprCLUTy(sprhdr,n,CLUTy),0x80,0x80,0x80, 0,0,ONE,ONE,0); blokey=sprites[BLOKEspr].y; // Set up background stuff setRECT(&r1,BGx,BGy,BGw,BGh); InitSpriteBG(&bg,sprhdr,tpage,&r1,CLUTx,CLUTy); // Load the first level LoadLevel(lvlhdr,&bg,0); // Set up sprites used to destroy blocks for(i=0;i>1,BottomScrLimit,90,90,90,255,255,255); _SetGLINE(&line1,noEffects,SCRW>>1,BottomScrLimit,SCRW,BottomScrLimit,255,255,255,90,90,90); while(!stop) { // Add one to the timer every 50th (PAL) or 60th (NTSC) of a second _IncTIMER; // Get controller info. padmask=_PadStatus(pad1); // Set the ordering table and packet buffer for current screen _SetOTpktBuff(ot,mainOT,pktbuff,packetBuff,PKTOFFSET); GsSetWorkBase(pktbuff); GsClearOt(0,0,ot); // Update all active sprites for(i=0,info=sprinfo;ion) { // Register sprite in OT GsSortSprite(info->spr,ot,0); // Get sprite coordinates x=info->spr->x; y=info->spr->y; // Do stuff related to specific sprites // The sprites used to destroy blocks if(i>=BLOCKspr && i<=BLOCKspr+(NDBLKS-1)) { // Is sprite still on screen if(xRightScrLimit || yBottomScrLimit) info->on=0; // Update sprite position x=x+info->xspd; y=y+info->yspd; if(info->yspd<10) info->yspd++; // Rotate the sprite info->spr->rotate+=(ONE*info->xspd)<<2; // Shrink sprite //info->spr->scalex-=50; //info->spr->scaley-=50; } switch(i) { // The starting block sprite case STARTspr: // When START pressed on pad set bloke off if(!(padmask&PADstart)) { // Turn start block off info->on=OFF; // Set bloke movement parameters sprinfo[BLOKEspr].yspd=-10; sprinfo[BLOKEspr].animon=ON; if(x>batspr->x) sprinfo[BLOKEspr].xspd=-BLOKExspd; else sprinfo[BLOKEspr].xspd=BLOKExspd; } break; // Sort out bloke case BLOKEspr: // Frame delay for animation animdelay=5; side=0; // Check if bloke has hit a block py=blokey>>VSCR; px=x+(blokespr->w>>1); by=(r=py>>4)<<4; bx=(c=px>>4)<<4; // Hit bottom of block if((blkid=_GetBlockId(&bg,r,c))=by+ZONE) side|=BOTBLK,DestroyBlock(&bg,r,c,blkid,offsets,rtable,sprinfo); py=(blokey>>VSCR)+blokespr->h; px=x+(blokespr->w>>1); by=(r=py>>4)<<4; bx=(c=px>>4)<<4; // Hit top of block if(pyh) if((blkid=_GetBlockId(&bg,r,c))=by && py<=by+ZONE) side|=TOPBLK,DestroyBlock(&bg,r,c,blkid,offsets,rtable,sprinfo);; py=(blokey>>VSCR)+(blokespr->h>>1); px=x+3; by=(r=py>>4)<<4; bx=(c=px>>4)<<4; // Hit right of block if((blkid=_GetBlockId(&bg,r,c))=bx+ZONE) side|=RGTBLK,DestroyBlock(&bg,r,c,blkid,offsets,rtable,sprinfo); py=(blokey>>VSCR)+(blokespr->h>>1); px=x+blokespr->w-3; by=(r=py>>4)<<4; bx=(c=px>>4)<<4; // Hit left of block if((blkid=_GetBlockId(&bg,r,c))=bx && px<=bx+ZONE) side|=LFTBLK,DestroyBlock(&bg,r,c,blkid,offsets,rtable,sprinfo); if(side) { // Decide which way to rebound bloke info->yspd=(side&TOPBLK ? -3 : (side&BOTBLK ? 3 : info->yspd)); info->xspd=(side&LFTBLK ? -BLOKExspd : (side&RGTBLK ? BLOKExspd : info->xspd)); } // If the bloke is not dying and not on the start block test for collision with bat if(!info->dying && !sprinfo[STARTspr].on) { // Update y position of bloke blokey+=info->yspd; if(info->yspdyspd++; // Has bloke hit a part of the bat if(blokey>(batspr->y-3)<batspr->x-8 && x+blokespr->w-6x+15+8) { if(sprinfo[BATspr].currfrm==BATfrm) info->dying=1,info->animstr=animations+BDYING,info->currfrm=0,info->maxfrms=6; else { batspr->u=offsets[BATfrm].u,batspr->v=offsets[BATfrm].v; sprinfo[BATspr].currfrm=BATfrm; x=batspr->x+32; info->xspd=-BLOKExspd; if(bmaxyspd<=25) bmaxyspd+=3; blokey=(batspr->y-3)<yspd=-bmaxyspd; tmphgt=12; } } else // Right bit of bat if(x+6>batspr->x+31-8 && x+blokespr->w-6x+46+8) { if(sprinfo[BATspr].currfrm==BATfrm+1) info->dying=1,info->animstr=animations+BDYING,info->currfrm=0,info->maxfrms=6; else { batspr->u=offsets[BATfrm+1].u,batspr->v=offsets[BATfrm+1].v; sprinfo[BATspr].currfrm=BATfrm+1; x=batspr->x+1; info->xspd=BLOKExspd; if(bmaxyspd<=25) bmaxyspd+=3; blokey=(batspr->y-3)<yspd=-bmaxyspd; tmphgt=12; } } else // Hit middle of bat if(x+6>batspr->x && x+blokespr->w-6x+batspr->w) info->dying=1,info->animstr=animations+BDYING,info->currfrm=0,info->maxfrms=6; } // Has bloek hit bottom of screen // Reduce height each time if(blokey>(BottomScrLimit-blokespr->h)<h)<yspd=-tmphgt; bmaxyspd=10; if(tmphgt>0) tmphgt-=2; else info->dying=1,info->animstr=animations+BDYING,info->currfrm=0,info->maxfrms=6; } // Horizontal movement for bloke // Rebound of eadges of screen x+=info->xspd; if(x>RightScrLimit-blokespr->w) x=RightScrLimit-blokespr->w,info->xspd=-info->xspd; if(xxspd=-info->xspd; } // Is bloke dead yet // Once bloke is dead reset start block if(info->dying && info->animstr[info->currfrm]==48) { RandOffset=rand(); info->animon=0,info->dying=0,info->on=OFF; _SetSprINFO(&sprinfo[BLOKEspr],animations+BMVING,5,43,ON,OFF,0,BLOKExspd,0,&sprites[BLOKEspr]); _SetSprINFO(&sprinfo[STARTspr],0,0,STARTsprImg,ON,OFF,0,0,0,&sprites[STARTspr]); _SetSPRITE(&sprites[STARTspr],noEffects,(_GetRand(rtable,RANDTABLESIZE)<<1)%(SCRW-16),BottomScrLimit-16,16,16,tpage,offsets[STARTsprImg].u, offsets[STARTsprImg].v,CLUTx,_GetSprCLUTy(sprhdr,STARTsprImg,CLUTy),0x80,0x80,0x80, 0,0,ONE,ONE,0); pblk=_GetSprPblk(sprhdr,(n=sprinfo[BLOKEspr].currfrm)); _SetSPRITE(&sprites[BLOKEspr],noEffects,x=sprites[STARTspr].x,(sprites[STARTspr].y-pblk->h)<w,pblk->h, tpage=GetTPage(0,0,tx,ty),offsets[n].u,offsets[n].v,CLUTx,_GetSprCLUTy(sprhdr,n,CLUTy), 0x80,0x80,0x80,0,0,ONE,ONE,0); blokey=info->spr->y; bmaxyspd=10; tmphgt=12; } break; case BATspr: if(!sprinfo[BLOKEspr].dying) { // Switch bat around when X pressed if(!(padmask&PADcross) && flag) { flag=0; if(sprinfo[BATspr].currfrm==BATfrm) batspr->u=offsets[BATfrm+1].u,batspr->v=offsets[BATfrm+1].v,sprinfo[BATspr].currfrm=BATfrm+1; else batspr->u=offsets[BATfrm].u,batspr->v=offsets[BATfrm].v,sprinfo[BATspr].currfrm=BATfrm; } if(padmask&PADcross) flag=1; // If square button held down increase speed of bat fctr=(!(padmask&PADsquare) ? 1 : 0); // Move bat with controller if(!(padmask&PADleft)) x=((x-=(info->xspd<LeftScrLimit ? x : LeftScrLimit); if(!(padmask&PADright)) x=((x+=(info->xspd<w ? x : RightScrLimit-batspr->w); /*if(!(padmask&PADup)) blokey--; if(!(padmask&PADdown)) blokey++; if(!(padmask&PADleft)) sprites[BLOKEspr].x--; if(!(padmask&PADright)) sprites[BLOKEspr].x++;*/ } break; } // Update sprite coordinates // Bloke coordinates are in virtual screen, to get screen coordinates divide by VSCR (size // of virtual screen in powers of 2) info->spr->x=x; (i==BLOKEspr ? (blokespr->y=blokey>>VSCR) : (info->spr->y=y)); // Animate the sprite if(info->animon) AnimateSprite(info,offsets,animdelay); } } // Register background in ot GsSortSpriteBG(&bg,ot,1); // Register lines in ot GsSortGLine(&line,ot,0); GsSortGLine(&line1,ot,0); // Wait for drawing to finish, wait for vsync, swap screens and draw screen DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0,0,0,ot); GsDrawOt(ot); // Quit program by pressing select if(!(padmask&PADselect)) stop=1; } // Free memory used by OT, packet buffer and random lookup table KillOT(mainOT); KillPktBuff(packetBuff); _KillRandLookup(rtable); } else puts("ERROR : cannot allocate ordering table/packet buffer"); exit(0); }