main.cKhP:I,main.c"NHhdB@LLLPTEXTCWIEKh:I,// Flood // David Johnston - Programming, Level design, Concept, Graphics // 8/5/99 // v1.0 #include #include #include #include #include #include "pad.h" #include "asssert.h" #include "dump.h" #include "message.h" #define MAINSPRS_ADDRESS 0x80090000 #define YOUSPRS_ADDRESS 0x80093000 #define VANISHSPRS_ADDRESS 0x80094000 #define FONTSPRS_ADDRESS 0x80097000 #define DIGITSPRS_ADDRESS 0x80099000 #define LEVELS_ADDRESS 0x800D0000 #define CODES_ADDRESS 0x800D0C80 #define PAL 1 // 0 - NTSC mode, 1 - PAL mode #define PACKETMAX 2048 /* Max GPU packets */ #define PACKETMAX2 (PACKETMAX*24) #define OT_LENGTH 5 static GsOT Wot[2]; /* Handler of OT */ static GsOT_TAG wtags[2][1<>1) & 8128),(cy) & 7936); \ sprite.u = ((cx) % 128); \ sprite.v = ((cy) % 256) #define CalcSprPos2(sprite,cx,cy) \ sprite->tpage = GetTPage(1,0,(((cx)>>1) & 8128),(cy) & 7936); \ sprite->u = ((cx) % 128); \ sprite->v = ((cy) % 256) // What parts of each tile in the game are solid u_char coldata[16][16][4] = { {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}, {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{0,1,0,1},{0,0,0,0},{1,0,1,0},{0,0,0,0}, {0,1,0,1},{0,0,0,0},{1,0,1,0},{0,0,0,0}, {0,1,0,1},{0,0,0,0},{1,0,1,0},{0,0,0,0}, {0,1,0,1},{0,0,0,0},{1,0,1,0},{0,0,0,0}}, {{0,1,0,1},{0,1,0,1},{0,1,0,1},{0,1,0,1}, {0,1,0,1},{0,1,0,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{1,0,0,0},{1,0,0,0},{1,1,0,0},{1,1,0,0}, {1,1,1,0},{1,1,1,0},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {1,0,0,0},{1,0,0,0},{1,1,0,0},{1,1,0,0}, {1,1,1,0},{1,1,1,0},{1,1,1,1},{1,1,1,1}}, {{0,0,0,1},{0,0,0,1},{0,0,1,1},{0,0,1,1}, {0,1,1,1},{0,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,1},{0,0,0,1},{0,0,1,1},{0,0,1,1}, {0,1,1,1},{0,1,1,1},{1,1,1,1},{1,1,1,1}}, {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{1,1,1,0},{0,0,0,0},{0,1,1,1},{0,0,0,0}, {1,1,1,0},{0,0,0,0},{0,1,1,1},{0,0,0,0}, {1,1,1,0},{0,0,0,0},{0,1,1,1},{0,0,0,0}, {1,1,1,0},{0,0,0,0},{0,1,1,1},{0,0,0,0}}, {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}, {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}, {{2,2,2,2},{2,2,2,2},{2,2,2,2},{2,2,2,2}, {2,2,2,2},{2,2,2,2},{2,2,2,2},{2,2,2,2}, {2,2,2,2},{2,2,2,2},{2,2,2,2},{2,2,2,2}, {2,2,2,2},{2,2,2,2},{2,2,2,2},{2,2,2,2}}, {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}, {{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}, {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}} }; // Collision map off every square on the screen. u_char colmap[80][256]; // Avert your eyes. char* passmess[10] = { "well done password for level 2 is 5812", "well done password for level 3 is 1932", "well done password for level 4 is 1554", "well done password for level 5 is 8521", "well done password for level 6 is 9364", "well done password for level 7 is 7496", "well done password for level 8 is 0460", "well done password for level 9 is 6892", "well done password for level 10 is 5814", "congratulations"}; int codes[9][4] = {{5,8,1,2},{1,9,3,2},{1,5,5,4},{8,5,2,1}, {9,3,6,4},{7,4,9,6},{0,4,6,0},{6,8,9,2},{5,8,1,4}}; // Global vars extern DISPENV GsDISPENV; int side; u_char level = 0; u_char quit, done, fail, reset; u_char map[20][16]; //The current map u_char state; // 0 - Normal // 1 - Vanishing u_char youx,youy,youdirn; char youxdis,youydis; u_char youstep,youstepdel,moving; int target, watercoll; u_long water[1024][2]; /**************************************************************************** prototypes ****************************************************************************/ void main (void); void ShowLevelMess (void); void BuildCollisionMap(void); void MoveWater (void); void PlotWater (void); void FindWater (void); void MoveBloke (void); void PlotBloke (void); void PlotMap (void); void SetUpMap (u_char map_no); void DealWithControllerPad (void); void EnterCode (void); void PlotCode (void); void EntCodePad (int* entcodeptr); u_char Shoveable (u_char tile); u_char Solid (u_char tile); void WaterFlowingPad (void); void InitialiseAll (void); /**************************************************************************** functions ****************************************************************************/ void main (void) { int hsync; int nytitledel = 320; int scrsize = 0; u_char levelmess; InitialiseAll(); side = GsGetActiveBuff(); quit = 0; done = 0; while (level<10 && quit==0) { SetUpMap(level); levelmess = done = reset = 0; // Main game loop hsync = VSync(0); while(quit==0 && done==0 && reset==0) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); PlotMap(); PlotBloke(); PlotMessage(&Wot[side]); MoveBloke(); if (Message() && !levelmess) {levelmess = 1; ShowLevelMess();} DealWithControllerPad(); hsync = VSync(0); ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } BuildCollisionMap(); FindWater(); done = 0; fail = 0; // Water flowing loop while(quit==0 && done<2 && fail==0 && reset==0) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); PlotMap(); PlotWater(); PlotMessage(&Wot[side]); MoveWater(); // Check if goal has been reached if (watercoll>=target*64 && done==0) {done = 1; StartMessage(passmess[level]);} if (Message() && done==1) done = 2; WaterFlowingPad(); hsync = VSync(0); if (hsync > 312) { MoveWater(); if (Message() && done==1) done = 2; } ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } if (done==2) level++; } if (level==10) printf("Good ending huh?\n"); ResetGraph(3); } char* messgs[6] = { "shove the blocks to create a path for the water", "the brown stuff disappears when hit from above with water", "only you can pass through the yellow mesh", "the blue block is ice it will turn into water", "you can push ice blocks", "last level good luck" }; void ShowLevelMess() { // Display appropriate message explaining what new stuff does int showmessage = -1; switch (level) { case 0: showmessage = 0; break; case 1: showmessage = 1; break; case 3: showmessage = 2; break; case 4: showmessage = 3; break; case 7: showmessage = 4; break; case 9: showmessage = 5; break; } if (showmessage!=-1) StartMessage(messgs[showmessage]); } void BuildCollisionMap() { /* Build a collision map for the whole screen using the * collision data for each tile on the current map. */ int x,y,x2,y2; u_char tile; for (y=0;y<16;y++) { for (x=0;x<20;x++) { tile = map[x][y]; for (y2=0;y2<16;y2++) { for (x2=0;x2<4;x2++) { if (tile==255) colmap[x*4 + x2][y*16 + y2] = 0; else colmap[x*4 + x2][y*16 + y2] = coldata[tile][y2][x2]; } } } } } asm void MoveWater() { // s0 - water .set reorder addiu sp,sp,-24 sw s0,4(sp) sw s1,8(sp) sw s2,12(sp) sw s3,16(sp) sw s4,20(sp) sw ra,24(sp) la s0,water li t8,0 li t9,1 movewaterlp: lw t0,0(s0) // water x beq t0,255,skipwater lw t1,4(s0) // water y sll t2,t0,8 // Get pointer to entry in collision map add t2,t2,t1 // the water drop is at. la t3,colmap add t2,t2,t3 beq t1,255,collected // Check if water has dropped // off bottom of screen lb t3,1(t2) // Check area below droplet beq t3,1,notdown // If solid then can't move down sb t8,0(t2) // Move.. add t1,t1,1 // ..droplet.. sw t1,4(s0) // ..down sb t9,1(t2) bne t3,2,skipwater srl t4,t0,2 srl t5,t1,4 sll t4,t4,4 add t4,t5,t4 la t5,map add t4,t5,t4 lb t5,0(t4) beq t5,-1,skipwater bgt t5,13,notcomplete li t5,15 notcomplete: sub t5,t5,15 and t6,t0,3 li t7,1 sllv t6,t7,t6 or t5,t5,t6 add t5,t5,15 bne t5,30,notempty li t5,255 notempty: sb t5,0(t4) b skipwater notdown: jal rand // Move left or right? and t4,v0,1 beqz t4,waterleft lb t3,256(t2) // Check area right of droplet bne t3,0,skipwater // If solid then can't move right sb t8,0(t2) // Move.. add t0,t0,1 // ..droplet.. sw t0,0(s0) // ..right sb t9,256(t2) b skipwater waterleft: lb t3,-256(t2) // Check area right of droplet bne t3,0,skipwater // If solid then can't move left sb t8,0(t2) // Move.. sub t0,t0,1 // ..droplet.. sw t0,0(s0) // ..left sb t9,-256(t2) skipwater: add s0,s0,2*sizeof(long) // Loop back if there are more droplets la t0,water add t0,t0,2048*sizeof(u_long) blt s0,t0,movewaterlp lw s0,4(sp) lw s1,8(sp) lw s2,12(sp) lw s3,16(sp) lw s4,20(sp) lw ra,24(sp) addiu sp,sp,24 jr ra collected: sb t8,0(t2) li t0,255 sw t0,0(s0) lw t4,watercoll add t4,t4,1 sw t4,watercoll b skipwater } void PlotWater () { // Plot each little droplet of water GsLINE drop; int i; drop.attribute = 0; drop.r = 0; drop.g = 0; drop.b = 255; for (i=0;i<1024;i++) { if (water[i][0]!=255) { // Find values for start and end of line used to draw droplet drop.x0 = water[i][0]*4; drop.x1 = drop.x0 + 3; drop.y0 = drop.y1 = water[i][1]; GsSortLine(&drop, &Wot[side], 7); } } } void FindWater () { // Look through current map and build up // information about where the water is. u_int waterptr = 0; int x,x2,y,y2; for (y=0;y<16;y++) { for (x=0;x<20;x++) { if (map[x][y] == 0 || map[x][y] == 14) { // Add entry in water array for each 4 pixel block for (y2=0;y2<16;y2++) { for (x2=0;x2<4;x2++) { water[waterptr][0]=(x*4)+x2; water[waterptr][1]=(y*16)+y2; waterptr++; assert(waterptr<=1024); } } map[x][y] = 255; } if (map[x][y] == 12) map[x][y] = 255; } } } void MoveBloke () { switch (state) { case 0: if (moving) { // Move his feet if ((youstepdel--) == 0) { youstepdel = 5; youstep^=1; } // Keep moving the bloke in his current direction switch (youdirn) { case 0: if ((youydis-=2) < 0) {youydis+=16; youy--;} break; case 1: if ((youxdis+=2) == 16) {youxdis-=16; youx++;} break; case 2: if ((youydis+=2) == 16) {youydis-=16; youy++;} break; case 3: if ((youxdis-=2) < 0) {youxdis+=16; youx--;} break; } // Stop bloke if he aligns with map tiles if (youxdis==0 && youydis==0) moving = 0; } break; case 1: // Vanishing if (youstepdel-- == 0) { youstepdel = 2; if (youstep-- == 0) done = 1; } break; case 2: // Appearing if (youstepdel-- == 0) { youstepdel = 2; if (++youstep == 32) {state = 0; youstep = 0;} } break; } } void PlotBloke () { GsSPRITE youspr; InitGsSprite(&youspr); youspr.x = youx*16 + youxdis; youspr.y = youy*16 + youydis; switch (state) { case 0: // Normal CalcSprPos(youspr, 640+(youdirn*2 + youstep)*16, 16); break; case 1: case 2: // Vanishing, Appearing CalcSprPos(youspr, 640+(youstep % 16)*16, 32+16*(youstep/16)); break; } GsSortFastSprite(&youspr, &Wot[side], 11); } void PlotMap () { // Plot each tile of the map int x,y,tile; GsSPRITE tilespr; InitGsSprite(&tilespr); for (y=0;y<16;y++) { for (x=0;x<20;x++) { tile = map[x][y]; if (tile!=255) { // Plot tile if it's not black CalcSprPos(tilespr,640+(tile*16),0); tilespr.x = x*16; tilespr.y = y*16; GsSortFastSprite(&tilespr, &Wot[side], 10); } } } } void SetUpMap (u_char map_no) { u_char x,y; static char* mess = "collect xx units of water"; u_char* baseaddr = (u_char*)LEVELS_ADDRESS+(320*map_no); u_char* stuffaddr = (u_char*)CODES_ADDRESS+(4*map_no); // Copy map from main memory to map array. for (y=0;y<16;y++) { for (x=0;x<20;x++) { map[x][y] = *(baseaddr+(y*20)+x); } } // Set position of bloke. youx = *(stuffaddr); youy = *(stuffaddr+1); youxdis = youydis = youstep = youstepdel = moving = watercoll = 0; youdirn = state = 2; // Find target amount of water. target = *(stuffaddr+2)-1; // Insert target numbers into message and start. *(mess+8)=48+(target / 10); *(mess+9)=48+(target % 10); StartMessage(mess); } void DealWithControllerPad (void) { u_char storemove = 0; long pad; u_char tile, tile2; pad = PadRead(); if (state==0) { if (pad & PADRleft) reset = 1; if (pad & PADRup) EnterCode(); if (pad & PADRdown) {state=1; youstep=31; youstepdel=2;} // Start vanishing if (pad & PADLleft && !moving) { // Move left tile = map[youx-1][youy]; if (youx==1) tile2 = 0; else tile2 = map[youx-2][youy]; if (Shoveable(tile) && !Solid(tile2)) { // Move shoveable block map[youx-2][youy] = tile; map[youx-1][youy] = 255; } if (!Solid(tile) || tile==10) { youdirn = 3; moving = 1; } } if (pad & PADLright && !moving) { // Move right tile = map[youx+1][youy]; if (youx==18) tile2 = 0; else tile2 = map[youx+2][youy]; if (Shoveable(tile) && !Solid(tile2)) { // Move shoveable block map[youx+2][youy] = tile; map[youx+1][youy] = 255; } if (!Solid(tile) || tile==10) { youdirn = 1; moving = 1; } } if (pad & PADLup && !moving) { // Move up tile = map[youx][youy-1]; if (youy==1) tile2 = 0; else tile2 = map[youx][youy-2]; if (Shoveable(tile) && !Solid(tile2)) { // Move shoveable block map[youx][youy-2] = tile; map[youx][youy-1] = 255; } if (!Solid(tile) || tile==10) { youdirn = 0; moving = 1; } } if (pad & PADLdown && !moving) { // Move down tile = map[youx][youy+1]; if (youy==14) tile2 = 0; else tile2 = map[youx][youy+2]; if (Shoveable(tile) && !Solid(tile2)) { // Move shoveable block map[youx][youy+2] = tile; map[youx][youy+1] = 255; } if (!Solid(tile) || tile==10) { youdirn = 2; moving = 1; } } } // quit program if (pad & PADselect) { while (pad & PADselect) pad = PadRead(); quit = 1; } // pause if (pad & PADstart) { while (pad & PADstart) { pad = PadRead(); } while (!(pad & PADstart)) { pad = PadRead(); } while (pad & PADstart) { pad = PadRead(); } VSync(0); } } int code[4]; int selectedlet; void EnterCode (void) { int entcode = 0; int hsync, i, lev; selectedlet = 0; side = GsGetActiveBuff(); while(entcode==0) { GsSetWorkBase((PACKET*)packetArea[side]); GsClearOt(0,0,&Wot[side]); PlotMap(); PlotBloke(); PlotMessage(&Wot[side]); PlotCode(); EntCodePad(&entcode); hsync = VSync(0); ResetGraph(1); GsSwapDispBuff(); GsSortClear(0,0,4,&Wot[side]); GsDrawOt(&Wot[side]); side ^= 1; FntFlush(-1); } if (entcode==1) { // Try and find code lev = -1; for (i=0;i<10;i++) { if (codes[i][0]==code[0] && codes[i][1]==code[1] && codes[i][2]==code[2] && codes[i][3]==code[3]) lev = i; } if (lev!=-1) {level = lev+1; reset = 1;} } } void PlotCode() { GsBOXF border; GsSPRITE digit; int i; static int flashdel = 0; border.attribute = 0; border.x = 96; border.y = 112; border.w = 128; border.h = 32; border.r = border.g = 0; border.b = 220; GsSortBoxFill(&border, &Wot[side], 2); border.x = 100; border.y = 116; border.w = 120; border.h = 24; border.b = 32; GsSortBoxFill(&border, &Wot[side], 1); if ((flashdel--) == 0) flashdel = 31; InitGsSprite(&digit); digit.x = 116; digit.y = 120; for (i=0;i<4;i++) { CalcLetterPos(&digit, (char)(code[i]+48)); if (selectedlet!=i || flashdel<24) GsSortSprite(&digit, &Wot[side], 0); digit.x+=24; } } void EntCodePad (int* entcodeptr) { long pad; static int pressed = 0; pad = PadRead(); if (pad & PADRdown) { while (pad & PADRdown) pad = PadRead(); *(entcodeptr) = 1; } if (pad & PADselect || pad & PADRleft) { while (pad & PADselect || pad & PADRleft) pad = PadRead(); *(entcodeptr) = 2; } if (pressed==0) { if (pad & PADLleft && selectedlet>0) {pressed = 1; selectedlet--;} if (pad & PADLright && selectedlet<3) {pressed = 1; selectedlet++;} if (pad & PADLup && code[selectedlet]<9) {pressed = 1; code[selectedlet]++;} if (pad & PADLdown && code[selectedlet]>0) {pressed = 1; code[selectedlet]--;} } else if (!(pad & PADLup) && !(pad & PADLdown) && !(pad & PADLleft) && !(pad & PADLright)) pressed = 0; } u_char Shoveable (u_char tile) { // Returns true if tile is shoveable. if (tile==11 || tile==14) return 1; else return 0; } u_char Solid (u_char tile) { // Returns true if tile is solid. if (tile==0 || tile==255 || tile==15) return 0; else return 1; } void WaterFlowingPad (void) { long pad; pad = PadRead(); if (pad & PADRleft) fail = 1; // Restart. // quit program if (pad & PADselect) { while (pad & PADselect) pad = PadRead(); quit = 1; } // pause if (pad & PADstart) { while (pad & PADstart) { pad = PadRead(); } while (!(pad & PADstart)) { pad = PadRead(); } while (pad & PADstart) { pad = PadRead(); } VSync(0); } } void InitialiseAll() { if (PAL) { SetVideoMode(MODE_PAL); GsInitGraph(320,256,GsOFSGPU,0,0); GsDefDispBuff(0,0,0,256); GsDISPENV.screen.x = 5; GsDISPENV.screen.y = 20; GsDISPENV.screen.h = 256; } else { SetVideoMode(MODE_NTSC); GsInitGraph(320,240,GsOFSGPU,0,0); GsDefDispBuff(0,0,0,240); GsDISPENV.screen.x = 5; GsDISPENV.screen.y = 10; GsDISPENV.screen.h = 240; } Wot[0].length=OT_LENGTH; Wot[0].org=wtags[0]; Wot[1].length=OT_LENGTH; Wot[1].org=wtags[1]; GsClearOt(0,0,&Wot[0]); GsClearOt(0,0,&Wot[1]); InitSpr(MAINSPRS_ADDRESS); InitSpr(YOUSPRS_ADDRESS); InitSpr(VANISHSPRS_ADDRESS); InitSpr(FONTSPRS_ADDRESS); InitSpr(DIGITSPRS_ADDRESS); PadInit(); } ZZRmain.crrior IDE PrefszentallerATEXTCWIE*6:IKh@M8ݲM8prefApprH Monaco;A`;A`*GhGhZZR6ZRMPSRMWBB*LR