/******************* step14.c *******************/ #include #include "step14.h" #include "addrs.h" extern u_short BankId; extern char worldGroundData[GROUNDMAX_Z][GROUNDMAX_X]; extern char WorldOverlayData[GROUNDMAX_Z][GROUNDMAX_X]; extern long gEnemiesKilled; // This function associates a model with our player datastructure void InitialisePlayerModel(PlayerStruct *thePlayer, int nX, int nY, int nZ, unsigned long *lModelAddress, int bx1, int bx2, int by1, int by2, int bz1, int bz2) { //increment the pointer to past the model id. lModelAddress++; // map tmd data to its actual address GsMapModelingData(lModelAddress); // initialise the players coordinate system - set to be that of the //world GsInitCoordinate2(WORLD, &thePlayer->Model.Object_Coord); // increment pointer twice more - to point to top of model data lModelAddress++; lModelAddress++; // link the model (tmd) with the players object handler GsLinkObject4((u_long)lModelAddress, &thePlayer->Model.Object_Handler,0); // Assign the coordinates of the object model to the Object Handler thePlayer->Model.Object_Handler.coord2 = &thePlayer->Model.Object_Coord; // Set the initial position of the object thePlayer->Model.Object_Coord.coord.t[0]=nX; // X thePlayer->Model.Object_Coord.coord.t[1]=nY; // Y thePlayer->Model.Object_Coord.coord.t[2]=nZ; // Z // setting the players Object_Coord.flg to 0 indicates it is to be // drawn thePlayer->Direction.vx=0; thePlayer->Direction.vy=0; thePlayer->Direction.vz=ONE; thePlayer->Model.Object_Coord.flg = 0; SetBoundingBox(thePlayer->Range,thePlayer->Model.Object_Coord.coord.t[0], thePlayer->Model.Object_Coord.coord.t[1], thePlayer->Model.Object_Coord.coord.t[2], bx1, bx2, by1, by2, bz1, bz2); //-300,300,-600,0,-300,300); } // This function deals with setting up matrices needed for rendering // and sends the object to the ordering table so it is drawn void DrawPlayer(PlayerStruct *thePlayer) { MATRIX tmpls, tmplw; //Get the local world and screen coordinates, needed for light // calculations GsGetLws(thePlayer->Model.Object_Handler.coord2, &tmplw, &tmpls); // Set the resulting light source matrix GsSetLightMatrix(&tmplw); // Set the local screen matrix for the GTE (so it works out // perspective etc) GsSetLsMatrix(&tmpls); // Send Object To Ordering Table GsSortObject4(&thePlayer->Model.Object_Handler,&OTable_Header[CurrentBuffer],PLAYER_PRECISION, (u_long*)getScratchAddr(0)); } // This function deals with setting up matrices needed for rendering // and sends the object to the ordering table so it will be drawn void DrawModel(ModelStruct *theModel, GsOT *OTable_Header, int precision) { MATRIX tmpls, tmplw; //Get the local world and screen coordinates, needed for light calculations GsGetLws(theModel->Object_Handler.coord2, &tmplw, &tmpls); // Set the resulting light source matrix GsSetLightMatrix(&tmplw); // Set the local screen matrix for the GTE (so it works out perspective etc) GsSetLsMatrix(&tmpls); // Send Object To Ordering Table GsSortObject4( &theModel->Object_Handler,OTable_Header,precision,(u_long *)getScratchAddr(0)); } void InitialiseALight(GsF_LIGHT *flLight, int nLight, int nX, int nY, int nZ, int nRed, int nGreen, int nBlue) { // Set the direction in which light travels flLight->vx = nX;flLight->vy = nY; flLight->vz = nZ; // Set the colour flLight->r = nRed; flLight->g = nGreen; flLight->b = nBlue; // Activate light GsSetFlatLight(nLight, flLight); } // this function initialises the graphics system void Initialise3DGraphics() { // Initialise The Graphics System to PAL as opposed to NTSC SetVideoMode(MODE_PAL); // Set the Actual Size of the Video memory GsInitGraph(SCREEN_WIDTH, SCREEN_HEIGHT, GsNONINTER|GsOFSGPU, 1, 0); // Set the Top Left Coordinates Of The Two Buffers in video memory GsDefDispBuff(0, 0, 0, SCREEN_HEIGHT); // Initialise the 3D Graphics... GsInit3D(); // Before we can use the ordering table headers, // we need to... // 1. Set them to the right length OTable_Header[0].length = ORDERING_TABLE_LENGTH; OTable_Header[1].length = ORDERING_TABLE_LENGTH; // 2. Associate them with an actual ordering table OTable_Header[0].org = OTable_Array[0]; OTable_Header[1].org = OTable_Array[1]; // 3. initialise the World Ordering Table Headers and Arrays GsClearOt(0,0,&OTable_Header[0]); GsClearOt(0,0,&OTable_Header[1]); } void InitialiseView(GsRVIEW2 *view, int nProjDist, int nRZ, int nVPX, int nVPY, int nVPZ, int nVRX, int nVRY, int nVRZ) { // This is the distance between the eye // and the imaginary projection screen GsSetProjection(nProjDist); // Set the eye position or center of projection view->vpx = nVPX; view->vpy = nVPY; view->vpz = nVPZ; // Set the look at position view->vrx = nVRX; view->vry = nVRY; view->vrz = nVRZ; // Set which way is up view->rz=-nRZ; // Set the origin of the coord system in this case the world view->super = WORLD; //&TheCar.Object_Coord ; // Activate view GsSetRefView2(view); } void InitialiseLights() { InitialiseALight(&LightSource[0], 0, -100, -100, -100, 255,255,255); InitialiseALight(&LightSource[1], 1, 1000, 1000, 1000, 255,255,255); GsSetAmbient(0,0,0); GsSetLightMode(0); } /************** beginning of code taken form the SCEI mirror in directory ROTATE ***/ /* s—ñŠÖ˜A Programmed by Co Nazca SOFTWARE 1996-1997 */ //¡³‹K‰» (‡•x,y,zàONE ‹ß–T‚Ì‚Ý) long NormalScale(long x,long y,long z){ long nx,ny,nz,n; nx=(x+(1<<8))>>9; ny=(y+(1<<8))>>9; nz=(z+(1<<8))>>9; n=(nx*nx+ny*ny+nz*nz+(1<<3))>>4; if(n<(1<<26)){ n*=10; n+=9<<26; n/=19; } else { n*=10; n+=11<<26; n/=21; } n=(n+(1<<13))>>14; // if(!n) n=1; return n; } // The lines beginning with // have been commented out to make the function consider // whole matrix each time ... Its very quick // if you want it to run faster uncomment these lines and get slight distortion. Peter. //¡Šî’ês—ñ‚̕Ⳡvoid AdjustCoordinate2(GsCOORDINATE2 *coord){ MATRIX *mp=&coord->coord; long x,y,z,n; #define ax mp->m[0][0] #define ay mp->m[0][1] #define az mp->m[0][2] #define bx mp->m[1][0] #define by mp->m[1][1] #define bz mp->m[1][2] #define cx mp->m[2][0] #define cy mp->m[2][1] #define cz mp->m[2][2] // switch(PSDCNT%3){ //ŒvŽZ•p“x‚Í—v’²® (Œ»Ý‚Í–ˆ‰ñ1/3‚ÂÂ) //case 0: x=by*cz-bz*cy; y=bz*cx-bx*cz; z=bx*cy-by*cx; n=NormalScale(x,y,z); x/=n; y/=n; z/=n; if(ax!=x || ay!=y || az!=z){ ax=x; ay=y; az=z; coord->flg=0; } // break; //case 1: x=cy*az-cz*ay; y=cz*ax-cx*az; z=cx*ay-cy*ax; n=NormalScale(x,y,z); x/=n; y/=n; z/=n; if(bx!=x || by!=y || bz!=z){ bx=x; by=y; bz=z; coord->flg=0; } // break; // case 2: x=ay*bz-az*by; y=az*bx-ax*bz; z=ax*by-ay*bx; n=NormalScale(x,y,z); x/=n; y/=n; z/=n; if(cx!=x || cy!=y || cz!=z){ cx=x; cy=y; cz=z; coord->flg=0; } // break; // } } /******** end of adjustCoordinate2 code ********/ void InitialiseStaticView(GsRVIEW2 *view, int nProjDist, int nRZ, int nVPX, int nVPY, int nVPZ, int nVRX, int nVRY, int nVRZ) { // This is the distance between the eye // and the imaginary projection screen GsSetProjection(nProjDist); // Set the eye position or center of projection view->vpx = nVPX; view->vpy = nVPY; view->vpz = nVPZ; // Set the look at position view->vrx = nVRX; view->vry = nVRY; view->vrz = nVRZ; // Set which way is up view->rz=-nRZ; // Set the origin of the coord system in this case the world view->super = WORLD; //&TheCar.Object_Coord ; // Activate view GsSetRefView2(view); } void InitialiseTrackerView(GsRVIEW2 *view, int nProjDist, int nRZ, int nVPX, int nVPY, int nVPZ, int nVRX, int nVRY, int nVRZ,GsCOORDINATE2 *Object_Coord) { // This is the distance between the eye // and the imaginary projection screen GsSetProjection(nProjDist); // Set the eye position or center of projection view->vpx = nVPX; view->vpy = nVPY; view->vpz = nVPZ; // Set the look at position view->vrx = nVRX; view->vry = nVRY; view->vrz = nVRZ; // Set which way is up view->rz=-nRZ; // Set the origin of the coord system in this case the world view->super = Object_Coord ; // Activate view GsSetRefView2(view); } void InitialiseMaps() {int tmpz,tmpx; for (tmpz = 0; tmpz < GROUNDMAX_Z; tmpz++ ){ for (tmpx = 0; tmpx < GROUNDMAX_X; tmpx++ ){ WorldGround.ModelMap[tmpz][tmpx]=worldGroundData[tmpz][tmpx]; WorldOverlay.ModelMap[tmpz][tmpx]=WorldOverlayData[tmpz][tmpx]; } } } void InitialiseWorld () { int tmpx,tmpz; char c; // initialise world ground maps InitialiseMaps(); // then for each element of the worldGroundData array if we find a 1 // then place an instance of square.tmd at the appropriate position // in the world. for (tmpz = 0; tmpz < GROUNDMAX_Z; tmpz++ ){ for (tmpx = 0; tmpx < GROUNDMAX_X; tmpx++ ){ c= WorldGround.ModelMap[tmpz][tmpx];//worldGroundData[tmpz][tmpx]; // if(c == 'g') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)SQUARE_TMD); } if(c == '1') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)GROUND1_TMD); } if(c == '2') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)GROUND2_TMD); } if(c == '3') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)GROUND3_TMD); } if(c == '4') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)GROUND4_TMD); } if(c == '5') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)GRASS_TMD); } if(c == '6') { InitialiseModel(&WorldGround.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)GRASS_TMD); } c= WorldOverlay.ModelMap[tmpz][tmpx]; if(c == '1') { InitialiseModel(&WorldOverlay.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)OAK_TMD); SetBoundingBox(WorldOverlay.Range[tmpz][tmpx],tmpz * GROUNDSIZE,0,tmpx * GROUNDSIZE,-100,100,-300,0,-100,100 ); } if(c == '2') { InitialiseModel(&WorldOverlay.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)FIR_TMD); SetBoundingBox(WorldOverlay.Range[tmpz][tmpx],tmpz * GROUNDSIZE,0,tmpx * GROUNDSIZE,-100,100,-300,0,-100,100 ); } if(c == '3') { InitialiseModel(&WorldOverlay.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)BLOCK_TMD); SetBoundingBox(WorldOverlay.Range[tmpz][tmpx],tmpz * GROUNDSIZE,0,tmpx * GROUNDSIZE,-600,600,-600,0,-600,600 ); } if(c == '4') { InitialiseModel(&WorldOverlay.Model[tmpz][tmpx], (tmpz * GROUNDSIZE),(0), (tmpx * GROUNDSIZE), (u_long *)BLOCK1_TMD); SetBoundingBox(WorldOverlay.Range[tmpz][tmpx],tmpz * GROUNDSIZE,0,tmpx * GROUNDSIZE,-600,600,-2000,0,-600,600 ); } } } } void InitialiseModel(ModelStruct *theModel, int nX, int nY, int nZ, unsigned long *lModelAddress) { //increment the pointer to move past the model id. (weird huh?) lModelAddress++; // map tmd data to its actual address GsMapModelingData(lModelAddress); // Initialise the players coordinate system - set to be that of the world GsInitCoordinate2(WORLD, &theModel->Object_Coord); // increment pointer twice more - to point to top of model data (beats me!) lModelAddress++; lModelAddress++; // link the model (tmd) with the players object handler GsLinkObject4((u_long)lModelAddress, &theModel->Object_Handler,0); // Assign the coordinates of the object model to the Object Handler theModel->Object_Handler.coord2 = &theModel->Object_Coord; // Set polygon subdivision flag to lowest possible value theModel->Object_Handler.attribute = (1<<9); // Set the Initialiseial position of the object theModel->Object_Coord.coord.t[0]=nX; // X theModel->Object_Coord.coord.t[1]=nY; // Y theModel->Object_Coord.coord.t[2]=nZ; // Z // setting the models flg to 0 to indicate it is to be drawn theModel->Object_Coord.flg = 0; } void DrawWorld(WorldLayerStruct *world, int precision) { int tmpz,tmpx; for (tmpz = ClipZStart; tmpz < ClipZEnd; tmpz++ ) { for (tmpx = ClipXStart; tmpx < ClipXEnd; tmpx++ ){ if(world->ModelMap[tmpz][tmpx]!='0'){ DrawModel(&world->Model[tmpz][tmpx],&OTable_Header[CurrentBuffer],precision); } } } } void ClipWorld(int x, int z) { x=(x+GROUNDSIZEDIV2)/GROUNDSIZE; z=(z+GROUNDSIZEDIV2)/GROUNDSIZE; ClipZStart=MAX(x-CLIPXWIDTH,0); ClipZEnd=MIN(x+CLIPXWIDTH,GROUNDMAX_X); ClipXStart=MAX(z-CLIPZWIDTH,0); ClipXEnd =MIN(z+CLIPZWIDTH,GROUNDMAX_Z); } void SetBoundingBox(VECTOR Range[2],int mx,int my, int mz, int xmin, int xmax,int ymin, int ymax,int zmin,int zmax) { Range[0].vx=xmin+mx; Range[0].vy=ymin+my; Range[0].vz=zmin+mz; Range[1].vx=xmax+mx; Range[1].vy=ymax+my; Range[1].vz=zmax+mz; } int CollisionDetect(VECTOR v1[2], VECTOR v2[2]) { if( v1[0].vz>v2[1].vz || v2[0].vz>v1[1].vz || v1[0].vy>v2[1].vy || v2[0].vy>v1[1].vy || v1[0].vx>v2[1].vx || v2[0].vx>v1[1].vx) return(FALSE); else return(TRUE); } void InitialiseBullet(BulletStruct *theBullet, int nX, int nY, int nZ, unsigned long *lModelAddress) { InitialiseModel(&theBullet->Model, nX, nY,nZ,(unsigned long *) lModelAddress); theBullet->Model.Object_Handler.attribute= theBullet->Model.Object_Handler.attribute|(1<<31); theBullet->active=0; } void DrawBullet(BulletStruct *theBullet,int precision) { DrawModel(&theBullet->Model,&OTable_Header[CurrentBuffer],precision); } void SetBulletVector(GsCOORDINATE2 *gsObjectCoord,VECTOR currentDirection, BulletStruct *theBullet) { if(theBullet->active==1){ theBullet->Direction.vx= currentDirection.vx; theBullet->Direction.vy= currentDirection.vy; theBullet->Direction.vz= currentDirection.vz; theBullet->Model.Object_Coord.coord.t[0] = gsObjectCoord->coord.t[0]; theBullet->Model.Object_Coord.coord.t[1] = gsObjectCoord->coord.t[1]; theBullet->Model.Object_Coord.coord.t[2] = gsObjectCoord->coord.t[2]; theBullet->active=1; } } void AdvanceBullet(BulletStruct *theBullet) { #define STEPS (ONE)/256 static int life=16; int loop; // if the bullet is active move it forward if(theBullet->active==1){ theBullet->Model.Object_Coord.coord.t[0] += theBullet->Direction.vx / 16; theBullet->Model.Object_Coord.coord.t[1] += theBullet->Direction.vy / 16; theBullet->Model.Object_Coord.coord.t[2] += theBullet->Direction.vz / 16; SetBoundingBox(theBullet->Range,theBullet->Model.Object_Coord.coord.t[0], theBullet->Model.Object_Coord.coord.t[1], theBullet->Model.Object_Coord.coord.t[2], -25,25,-25,25,-25,25 ); life--; // check if bullet has hit enemy and reset enemy if it has for(loop = 0; loop < NUM_ENEMIES; loop++) { if ( CollisionDetect(theBullet->Range, enemies[loop].player_data.Range) ) { PlaySound(BankId, 1, 0, 60); FntPrint("Pixie killed!\n"); gEnemiesKilled ++; InitialisePlayerModel(&enemies[loop].player_data, ENEMY_START_X, ENEMY_START_Y, ENEMY_START_Z, (u_long*)MAN_TMD, -50,50,-150,0,-50,50); } } // if bullet life is over set it inactive and set attribute bit // to stop it being drawn if(life==0){ theBullet->active=0; life=STEPS; theBullet->Model.Object_Handler.attribute= theBullet->Model.Object_Handler.attribute|(1<<31); } theBullet->Model.Object_Coord.flg = 0; } }