#include #include "MyPad.h" #include "Tmd.h" #include "Object.h" #include "Arena.h" #include "Sprite.h" #define TEXTURE_IMAGE_ADDRESS 0x80090000 #define TEXT_IMAGE_ADDRESS 0x80092020 #define NUMBERS_IMAGE_ADDRESS 0x80092460 #define CRAFT_ADDRESS 0x80092ce0 #define ARENA_DATA_ADDRESS 0x800931b0 #define TEXTURE_DATA_ADDRESS 0x800951b0 #define CRAFT_COL_ADDRESS 0x800955f0 #define TMD_DYNAMIC_START 0x80095784 #define OT_LENGTH 12 #define PACKETMAX 8192 #define PACKETMAX2 (PACKETMAX * 24) #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 256 #define Greater(a, b) ( (a) = ((a) < (b)) ? (b) : (a) ) #define Less(a, b) ( (a) = ((a) > (b)) ? (b) : (a) ) #define Abs(a) ( ((a) > 0) ? (a) : (-(a)) ) #define LimitRange(a, b, c) ( ((a)<(b)) ? (b) : ((a)>(c) ? (c) : (a)) ) #define CalculateLight(_or, _og, _ob) \ Greater(dis, 1), \ tr = (_or) + ((r<<10)*rad/dis), \ tg = (_og) + ((g<<10)*rad/dis), \ tb = (_ob) + ((b<<10)*rad/dis), \ Greater(tr, 0), \ Less(tr, 255), \ Greater(tg, 0), \ Less(tg, 255), \ Greater(tb, 0), \ Less(tb, 255) typedef struct { u_char r0, g0, b0; u_char r1, g1, b1; u_char r2, g2, b2; u_char r3, g3, b3; } Colour; Colour arenaCol[MAX_X][MAX_Z]; ArenaType arena; BlockType arenaData[MAX_X][MAX_Z]; GsOT WorldOT[2]; GsOT_TAG OTTags[2][1<> 8; viewz = (craft.pos.vz + (craft.vel.vz<<4)) >> 8; view.vpx += (viewx - view.vpx)>>3; view.vpz += (viewz - view.vpz)>>3; view.vrx = view.vpx; view.vrz = view.vpz; // Draw the arena GsSetRefView2(&view); DrawArena(activeBuff, (view.vrx+32)>>6, (view.vrz+16)>>6); // Draw the ship GsGetLws(craft.handler.coord2, &lw, &ls); GsSetLightMatrix(&lw); GsSetLsMatrix(&ls); GsSortObject4(&craft.handler, &WorldOT[activeBuff], 3, getScratchAddr(0)); // Display the lap times DrawTimes(&lapTime, &bigNum, &smallNum, &WorldOT[activeBuff], craft.bestTime, craft.time, lapTimes); // Do we want motion blurring or not? if (BLUR) { leftSprite.tpage = GetTPage(2,0,0,activeBuff<<8); rightSprite.tpage = GetTPage(2,0,256,activeBuff<<8); GsSortSprite(&leftSprite, &WorldOT[activeBuff], 0); GsSortSprite(&rightSprite, &WorldOT[activeBuff], 0); } DrawSync(0); vSync = VSync(0); GsSwapDispBuff(); // if (!BLUR) { GsSortClear(0, 0, 0, &WorldOT[activeBuff]); // } GsDrawOt(&WorldOT[activeBuff]); if (vSync> maxVSync) maxVSync = vSync; FntPrint(0,"%d\n%d\n",vSync,maxVSync); FntFlush(-1); } while (!GAMEOVER); } void InitGame(void) { int i, tx, ty; // General setting up SetVideoMode(MODE_PAL); GsInitGraph(SCREEN_WIDTH, SCREEN_HEIGHT, GsINTER|GsOFSGPU, 1, 0); GsDefDispBuff(0, 0, 0, SCREEN_HEIGHT); GsInit3D(); // Center the screen for my TV (sorry) GsDISPENV.screen.x = 7; GsDISPENV.screen.y = 16; GsDISPENV.screen.h = 255; GsSetOrign(160,128); GetPadBuf(&bb0, &bb1); for (i = 0; i < 2; i++) { WorldOT[i].length = OT_LENGTH; WorldOT[i].org = OTTags[i]; GsClearOt(0,0,&WorldOT[i]); } BuildBlockData(); InitLights(); // Setup craft craft.pos.vx = 21*64<<8; craft.pos.vz = 2*64<<8; tx = craft.pos.vx >> 14; ty = craft.pos.vz >> 14; craft.pos.vy = Blend(tx, ty, arenaData[tx][ty].y0, arenaData[tx][ty].y1, arenaData[tx][ty].y3, arenaData[tx][ty].y2)<<8; craft.vel.vx = 0; craft.vel.vy = 0; craft.vel.vz = 0; craft.flag = 0; craft.coord.coord.t[0] = craft.pos.vx >> 8; craft.coord.coord.t[1] = craft.pos.vy >> 8; craft.coord.coord.t[2] = craft.pos.vz >> 8; craft.check = 0; craft.time = 0; craft.bestTime = 0; // Setup camera GsSetProjection(256); view.vpy = 360; view.vry = 0; view.vpx = view.vrx = craft.pos.vx>>8; view.vpz = view.vrz = craft.pos.vz>>8; view.rz = 0; view.super = WORLD; GsSetRefView2(&view); // Setup light lights[0].vx = 0; lights[0].vy = -ONE; lights[0].vz = 0; GsSetAmbient(32, 32, 32); } void AddBlockToArena(ArenaType *arena, int x, int y, int z, u_long *address) { int index = arena->totalBlocks; arena->pointer[index] = address; // Skip model id arena->pointer[index]++; GsMapModelingData(arena->pointer[index]); GsInitCoordinate2(WORLD, &arena->coord[index]); // Top of model data arena->pointer[index] += 2; GsLinkObject4((u_long )arena->pointer[index], &arena->handler[index], 0); arena->handler[index].attribute = 0;//1<<9; arena->handler[index].coord2 = &arena->coord[index]; arena->coord[index].coord.t[0] = x; arena->coord[index].coord.t[1] = y; arena->coord[index].coord.t[2] = z; arena->coord[index].flg = 0; arena->totalBlocks++; } void BuildArena(void) { int i, j, k, a, b, r, g; u_long *pointer; char *tex; u_long address = TMD_DYNAMIC_START; u_char vCount; VERTEX v[8]; COLOUR rgb[12]; TEXTURE txt[4]; //Work out textures and check-points tex = (char *)TEXTURE_DATA_ADDRESS; k=0; for (j=0; j 3) { checkPoint[i][j] = 1 << (textureNum[i][j]+48-97); textureNum[i][j] = 1; } } k+=2; } arena.totalBlocks = 0; SetTexture(&txt[0], 320, 0, 351, 0, 320, 31, 351, 31, 2, 0, 0); SetTexture(&txt[1], 352, 0, 383, 0, 352, 31, 383, 31, 2, 0, 0); SetTexture(&txt[2], 320, 32, 351, 32, 320, 63, 351, 63, 2, 0, 0); SetTexture(&txt[3], 352, 32, 383, 32, 352, 63, 383, 63, 2, 0, 0); // And now the hard part... for (i=0; i0 && (arenaData[i][j].y0 != arenaData[i-1][j].y1 || arenaData[i][j].y3 != arenaData[i-1][j].y2)) { r = arenaCol[i-1][j].r1>>1; g = arenaCol[i-1][j].g1>>1; b = arenaCol[i-1][j].b1>>1; SetColour(&rgb[vCount], r, g, b); r = arenaCol[i-1][j].r2>>1; g = arenaCol[i-1][j].g2>>1; b = arenaCol[i-1][j].b2>>1; SetColour(&rgb[vCount+1], r, g, b); r = arenaCol[i][j].r0>>1; g = arenaCol[i][j].g0>>1; b = arenaCol[i][j].b0>>1; SetColour(&rgb[vCount+2], r, g, b); r = arenaCol[i][j].r3>>1; g = arenaCol[i][j].g3>>1; b = arenaCol[i][j].b3>>1; SetColour(&rgb[vCount+3], r, g, b); // Work out which way round the side should face SetVertex(&v[vCount], 0+i*64, arenaData[i-1][j].y1, 0+j*64); SetVertex(&v[vCount+1], 0+i*64, arenaData[i-1][j].y2, 65+j*64); a = arenaData[i][j].y0 - arenaData[i-1][j].y1; b = arenaData[i][j].y3 - arenaData[i-1][j].y2; if (a<0) a = -a; if (b<0) b = -b; if (a>b) SetTX_NS_GP_QUAD(1, 0, vCount, vCount+1, vCount+2, vCount+3, vCount, vCount+1, 0); else SetTX_NS_GP_QUAD(vCount+1, vCount, 0, 1, vCount+1, vCount, vCount+3, vCount+2, 0); vCount += 2; } // Add side if needed if (j<(MAX_Z-1) && (arenaData[i][j].y3 != arenaData[i][j+1].y0 || arenaData[i][j].y2 != arenaData[i][j+1].y1)) { r = arenaCol[i][j+1].r0>>1; g = arenaCol[i][j+1].g0>>1; b = arenaCol[i][j+1].b0>>1; SetColour(&rgb[vCount], r, g, b); r = arenaCol[i][j+1].r1>>1; g = arenaCol[i][j+1].g1>>1; b = arenaCol[i][j+1].b1>>1; SetColour(&rgb[vCount+1], r, g, b); r = arenaCol[i][j].r2>>1; g = arenaCol[i][j].g2>>1; b = arenaCol[i][j].b2>>1; SetColour(&rgb[vCount+2], r, g, b); r = arenaCol[i][j].r3>>1; g = arenaCol[i][j].g3>>1; b = arenaCol[i][j].b3>>1; SetColour(&rgb[vCount+3], r, g, b); // Work out which way round the side should face SetVertex(&v[vCount], 0+i*64, arenaData[i][j+1].y0, 65+j*64); SetVertex(&v[vCount+1], 65+i*64, arenaData[i][j+1].y1, 65+j*64); a = arenaData[i][j].y3 - arenaData[i][j+1].y0; b = arenaData[i][j].y2 - arenaData[i][j+1].y1; if (a<0) a = -a; if (b<0) b = -b; if (a>b) SetTX_NS_GP_QUAD(0, 3, vCount, vCount+1, vCount+3, vCount+2, vCount, vCount+1, 0); else SetTX_NS_GP_QUAD(vCount+1, vCount, 3, 0, vCount+1, vCount, vCount+2, vCount+3, 0); vCount += 2; } pointer = (u_long *)FinishTMD(); AddBlockToArena(&arena, 0, 0, 0, pointer); address = 0; } } } void DrawArena(int activeBuff, int x, int z) { MATRIX ls, lw; int si, sj, ei, ej, i, j, index; // Work out how many blocks should be drawn, saves drawing whole arena ei = x+4; ej = z+3; si = x-4; sj = z-3; Less(ei, (MAX_X-1)); Less(ej, (MAX_Z-1)); Greater(si, 0); Greater(sj, 0); // Draw part of arena GsGetLws(arena.handler[0].coord2, &lw, &ls); GsSetLsMatrix(&ls); for (j=sj; j<=ej; j++) { for (i=si; i<=ei; i++) { index = j+i*MAX_Z; if (craft.pos.vy+1024 > minHeight[i][j]) GsSortObject4(&arena.handler[index], &WorldOT[activeBuff], 2, getScratchAddr(0)); else GsSortObject4(&arena.handler[index], &WorldOT[activeBuff], 4, getScratchAddr(0)); } } } void BuildBlockData(void) { int i, j, k=0; short *pointer = (short *)ARENA_DATA_ADDRESS; long min; // Convert raw data into structure for (j=0; j>1), 32, 255); col1 = LimitRange(16+(arenaData[i][j].y1>>1), 32, 255); col2 = LimitRange(16+(arenaData[i][j].y2>>1), 32, 255); col3 = LimitRange(16+(arenaData[i][j].y3>>1), 32, 255); arenaCol[i][j].r0 = col0; arenaCol[i][j].g0 = col0; arenaCol[i][j].b0 = col0; arenaCol[i][j].r1 = col1; arenaCol[i][j].g1 = col1; arenaCol[i][j].b1 = col1; arenaCol[i][j].r2 = col2; arenaCol[i][j].g2 = col2; arenaCol[i][j].b2 = col2; arenaCol[i][j].r3 = col3; arenaCol[i][j].g3 = col3; arenaCol[i][j].b3 = col3; } } } void AddLights(void) { // Add a plethora of coloured lights AddLight(12, 2, 6, 255, 255, 255); AddLight(2, 2 , 6, 255, 0, 0); AddLight(2, 23 , 6, 0, 255, 0); AddLight(7, 23 , 6, 0, 0, 255); AddLight(7, 16 , 5, 255, 255, 255); AddLight(7, 5 , 5, 255, 0, 0); AddLight(5, 5 , 5, 0, 255, 0); AddLight(5, 14 , 6, 0, 255, 255); AddLight(13, 12 , 5, 255, 255, 255); AddLight(17, 14 , 6, 255, 0, 255); AddLight(17, 8 , 6, 255, 255, 0); AddLight(13, 8 , 6, 0, 0, 255); AddLight(13, 27 , 6, 255, 0, 0); AddLight(2, 27 , 5, 0, 255, 255); AddLight(2, 30 , 5, 255, 255, 0); AddLight(20, 30 , 5, 255, 0, 255); AddLight(20, 28 , 5, 0, 255, 0); AddLight(17, 28 , 5, 0, 0, 255); AddLight(17, 20 , 6, 0, 255, 0); AddLight(24, 20 , 6, 255, 0, 0); AddLight(24, 26 , 5, 255, 255, 0); AddLight(21, 26 , 5, 0, 255, 255); AddLight(21, 20, 5, 255, 255, 255); AddLight(21, 12, 5, 0, 0, 255); AddLight(24, 12, 5, 0, 255, 0); AddLight(24, 17, 5, 255, 0, 255); AddLight(27, 17, 5, 255, 255, 0); AddLight(27, 30, 6, 0, 255, 255); AddLight(30, 30, 6, 255, 0, 0); AddLight(30, 24, 6, 0, 255, 255); AddLight(30, 16, 6, 255, 0, 255); AddLight(30, 9, 6, 255, 255, 0); AddLight(30, 2, 6, 0, 255, 0); AddLight(21, 2, 6, 0, 0, 255); } void AddLight(int x, int z, int rad, int r, int g, int b) { int dis; int dx, dz; int tr, tg, tb; int i, j; x = x<<6; z = z<<6; // Work out poly tints for each light for (j=0; j> 5; craft.vel.vz = (craft.vel.vz * 31) >> 5; } if (pad & PADLselect) BLUR = 1-BLUR; // Sort out that dodgy drifting thing if (craft.vel.vx <0) craft.vel.vx = -(((-craft.vel.vx) * 31) >> 5); else craft.vel.vx = (craft.vel.vx * 31) >> 5; if (craft.vel.vz <0) craft.vel.vz = -(((-craft.vel.vz) * 31) >> 5); else craft.vel.vz = (craft.vel.vz * 31) >> 5; if ((pad == PADLstart+PADLselect) || (pad == PADRselect+PADRstart)) GAMEOVER = 1; } // Highly dodgy collision routine void MoveCraft(void) { int tx[9], ty[9], tz[9]; int tx2[9], ty2[9], tz2[9]; int i, dx, dz; u_char crashedX=0, crashedZ=0; // Work out craft data before it is moved for (i=0; i<9; i++) { dx = checkX[i]<<8; dz = checkZ[i]<<8; tx[i] = (craft.pos.vx+dx) >> 14; tz[i] = (craft.pos.vz+dz) >> 14; ty[i] = Blend((craft.pos.vx+dx)>>8, (craft.pos.vz+dz)>>8, arenaData[tx[i]][tz[i]].y0, arenaData[tx[i]][tz[i]].y1, arenaData[tx[i]][tz[i]].y3, arenaData[tx[i]][tz[i]].y2)<<8; } // If in air, fall if (craft.flag == 1) { craft.vel.vy -= 1<<7; craft.pos.vy += craft.vel.vy; } // Otherwise slide according to block gradient else { craft.vel.vx += (arenaData[tx[8]][tz[8]].y0 - arenaData[tx[8]][tz[8]].y1) >> 2; craft.vel.vz += (arenaData[tx[8]][tz[8]].y1 - arenaData[tx[8]][tz[8]].y2) >> 2; } // Move! craft.pos.vx += craft.vel.vx; craft.pos.vz += craft.vel.vz; // Boundary check if ((craft.pos.vx<0) || (craft.pos.vx>>8)>=(MAX_X*64)) { craft.pos.vx -= craft.vel.vx; craft.vel.vx = -craft.vel.vx; } if ((craft.pos.vz<0) || (craft.pos.vz>>8)>=(MAX_Z*64)) { craft.pos.vz -= craft.vel.vz; craft.vel.vz = -craft.vel.vz; } // Work out new craft data for (i=0; i<9; i++) { dx = checkX[i]<<8; dz = checkZ[i]<<8; tx2[i] = (craft.pos.vx+dx) >> 14; tz2[i] = (craft.pos.vz+dz) >> 14; ty2[i] = Blend((craft.pos.vx+dx)>>8, (craft.pos.vz+dz)>>8, arenaData[tx2[i]][tz2[i]].y0, arenaData[tx2[i]][tz2[i]].y1, arenaData[tx2[i]][tz2[i]].y3, arenaData[tx2[i]][tz2[i]].y2)<<8; } // More complicated collision detection for (i=0; i<9; i++) { if (craft.pos.vy < ty2[i]) { if ((crashedX==0) && (tx2[i] arenaData[tx[i]][tz[i]].y0) || (arenaData[tx2[i]][tz[i]].y2 > arenaData[tx[i]][tz[i]].y3)) { craft.pos.vx -= craft.vel.vx; craft.vel.vx = -craft.vel.vx; crashedX = 1; } } if ((crashedX==0) && (tx2[i]>tx[i])) { if ((arenaData[tx2[i]][tz[i]].y0 > arenaData[tx[i]][tz[i]].y1) || (arenaData[tx2[i]][tz[i]].y3 > arenaData[tx[i]][tz[i]].y2)) { craft.pos.vx -= craft.vel.vx; craft.vel.vx = -craft.vel.vx; crashedX = 1; } } if ((crashedZ==0) && (tz2[i] arenaData[tx[i]][tz[i]].y0) || (arenaData[tx[i]][tz2[i]].y2 > arenaData[tx[i]][tz[i]].y1)) { craft.pos.vz -= craft.vel.vz; craft.vel.vz = -craft.vel.vz; crashedZ = 1; } } if ((crashedZ==0) && (tz2[i]>tz[i])) { if ((arenaData[tx[i]][tz2[i]].y0 > arenaData[tx[i]][tz[i]].y3) || (arenaData[tx[i]][tz2[i]].y1 > arenaData[tx[i]][tz[i]].y2)) { craft.pos.vz -= craft.vel.vz; craft.vel.vz = -craft.vel.vz; crashedZ = 1; } } } } for (i=0; i<9; i++) { dx = checkX[i]<<8; dz = checkZ[i]<<8; tx2[i] = (craft.pos.vx+dx) >> 14; tz2[i] = (craft.pos.vz+dz) >> 14; ty2[i] = Blend((craft.pos.vx+dx)>>8, (craft.pos.vz+dz)>>8, arenaData[tx2[i]][tz2[i]].y0, arenaData[tx2[i]][tz2[i]].y1, arenaData[tx2[i]][tz2[i]].y3, arenaData[tx2[i]][tz2[i]].y2)<<8; } // Don't let craft below ground craft.flag = 1; for (i=0; i<9; i++) { if (craft.pos.vy <= ty2[i]) { craft.flag = 0; craft.vel.vy = ty2[i]-ty[i]; craft.pos.vy = ty2[i]; } } // Complete bodge to fix the weird 'jump in the air' bug if (craft.vel.vy > 4000) { craft.flag = 0; } // Deal with lap times craft.check |= checkPoint[tx2[8]][tz2[8]]; craft.time += 2; if (craft.check == 63 && (textureNum[tx2[8]][tz2[8]] == 2 || textureNum[tx2[8]][tz2[8]] == 3)) { for (i=4; i>0; i--) lapTimes[i] = lapTimes[i-1]; lapTimes[0] = craft.time; if (craft.bestTime == 0) { craft.bestTime = craft.time; craft.time = 0; craft.check = 0; } else { if (craft.time < craft.bestTime) craft.bestTime = craft.time; craft.time = 0; craft.check = 0; } } craft.coord.flg = 0; craft.coord.coord.t[0] = craft.pos.vx >> 8; craft.coord.coord.t[1] = craft.pos.vy >> 8; craft.coord.coord.t[2] = craft.pos.vz >> 8; // Find offset heights for the front and back of object // HeightToFront = ty2[4]; // HeightToBack = ty2[0]; // Find offset heights for the left and right of the object // HeightToRight = ty2[2]; // HeightToLeft = ty2[6]; //Set Objects X Rotation Vector // Rotation2.vx = FindRotation(HeightToFront,HeightToBack,32); // Rotation2.vy = Rotation2.vz = 0; //Set Objects Z Rotation Vector. // Rotation3.vz = FindRotation(HeightToLeft,HeightToRight,32); // Rotation3.vy = Rotation3.vx = 0; // Set Objects Y Rotation Vector. // Rotation1.vy = theObject->yAngle; // Rotation1.vx = Rotation1.vz = 0; ResetMatrix(craft.coord.coord.m); RotMatrixY(craft.rot.vy, &craft.coord.coord); Greater(ty2[4], craft.pos.vy-(15<<8)); Greater(ty2[0], craft.pos.vy-(15<<8)); Greater(ty2[2], craft.pos.vy-(15<<8)); Greater(ty2[6], craft.pos.vy-(15<<8)); // if (!craft.flag) { craft.rot.vx = FindRotation(ty2[4], ty2[0], 32<<8); craft.rot.vz = FindRotation(ty2[2], ty2[6], 32<<8); // } RotMatrixX(craft.rot.vx, &craft.coord.coord); RotMatrixZ(craft.rot.vz, &craft.coord.coord); // Set light according to block tint lights[0].r = Blend(craft.pos.vx>>8, craft.pos.vz>>8, arenaCol[tx2[8]][tz2[8]].r0, arenaCol[tx2[8]][tz2[8]].r1, arenaCol[tx2[8]][tz2[8]].r3, arenaCol[tx2[8]][tz2[8]].r2); lights[0].g = Blend(craft.pos.vx>>8, craft.pos.vz>>8, arenaCol[tx2[8]][tz2[8]].g0, arenaCol[tx2[8]][tz2[8]].g1, arenaCol[tx2[8]][tz2[8]].g3, arenaCol[tx2[8]][tz2[8]].g2); lights[0].b = Blend(craft.pos.vx>>8, craft.pos.vz>>8, arenaCol[tx2[8]][tz2[8]].b0, arenaCol[tx2[8]][tz2[8]].b1, arenaCol[tx2[8]][tz2[8]].b3, arenaCol[tx2[8]][tz2[8]].b2); GsSetFlatLight(0, &lights[0]); } long FindRotation(long height1, long height2, long length) { register int delta, delta2; // If heights the same exit as there is no slope if(height1==height2) return(0); // If front higher then the back if(height1 > height2) { // first delta is the difference between the heights. delta= (height1 - height2); //uses advanced atan function which is very fast delta2=rinvtan(length, delta); return ((long)(delta2 & 4095)); } // If the front is lower then the back else { delta= (height2 - height1); delta2=rinvtan(length, delta); return ((long)4096-(delta2 & 4095)); } } // returns inverse tangent from x and y values // return value is of form 4096 = 360 degrees // where x = y = 0 and the result is undefined the function returns 0 long rinvtan(long x, long y) { long t; if (x == 0 && y == 0) return 0; if (Abs(x) > Abs(y)) { t = (y << 8) / x; if (t >= 0) return Tinvtan[t & 255] + (x < 0 ? 2048 : 0); return (x < 0 ? 2048 : 4096) - Tinvtan[(-t) & 255]; } t = (x << 8) / y; if (t >= 0) return (y < 0 ? 3072 : 1024) - Tinvtan[t & 255]; return Tinvtan[(-t) & 255] + (y < 0 ? 3072 : 1024); } u_long ReadPad(void) { return(~(*(bb0+3) | *(bb0+2) << 8 | *(bb1+3) << 16 | *(bb1+2) << 24)); }