//Helper function for recursing procedural cracked screen lines void DrawCrackedScreenExt(int x0, int y0, int x1, int y1, int remaining) { //basically, draw this line, then if remaining>0, draw two more lines branching off from it Color col = RGBColor(255 * (remaining + 6) / 8,255 * (remaining + 6) / 8,255 * (remaining + 6) / 8,0); DrawLine(x0, y0, x1, y1, col); if (remaining>0) { int i, x2, y2; float angle, distance; //two lines for (i=0; i<2; i++) { if (x0==x1) { if (y0<y1) { angle = PI; } else { angle= - PI; } } else { //get angle via arctan angle = qatan((float)(y0-y1)/(float)(x1-x0)); //add or subtract up to a quarter turn depending on first or second line angle += Random(0, PI/2.0) * (i==0?1.0:-1.0); if (x0 > x1) { //correct for quadrant angle += PI; } } //pick a distance distance = Random(10,40); //get new positions x2 = x1 + distance * qcos(angle); y2 = y1 - distance * qsin(angle); //recurse into new set of lines DrawCrackedScreenExt(x1, y1, x2, y2, remaining-1); } } }
void init_3band_state(EQSTATE* es, int lowfreq, int highfreq, int mixfreq) { // Clear state memset(es,0,sizeof(EQSTATE)); // Set Low/Mid/High gains to unity es->lg = 1.0; es->mg = 1.0; es->hg = 1.0; // Calculate filter cutoff frequencies es->lf = qmul(Q2, qsin(qmul(QPI, qdiv(int2q(lowfreq), int2q(mixfreq))))); es->hf = qmul(Q2, qsin(qmul(QPI, qdiv(int2q(highfreq), int2q(mixfreq))))); }
//Place the tank somewhere suitable - not too easy, not too close, not too far away, not straight ahead void PlaceTank(Point3d cameraPosition, Point3d cameraAngle) { world.objects[tankObjectIndex]=tank; RotateObjectYAxis(&(world.objects[tankObjectIndex]), Random(-PI/2.0, PI/2.0)); double distance = Random(50.0, 100.0); //At least 50 from us, at most 100 double angle = Random(45.0 / 360.0 * 2 * PI, 315.0 / 360.0 * 2.0 * PI); //45-315 degrees Point3d tankPos = CreatePoint(cameraPosition.x + distance * qsin(angle + cameraAngle.y), 0, cameraPosition.z + distance * qcos(angle + cameraAngle.y)); MoveObject(&(world.objects[tankObjectIndex]), tankPos); if (world.objects[tankObjectIndex].centre.z<0) { //behind us - face away RotateObjectYAxis(&(world.objects[tankObjectIndex]),PI); } }
ft_int16_t qsin(ft_uint16_t a) { ft_uint8_t f; ft_int16_t s0,s1; if (a & 32768) return -qsin(a & 32767); if (a & 16384) a = 32768 - a; f = a & 127; s0 = ft_pgm_read_word(sintab + (a >> 7)); s1 = ft_pgm_read_word(sintab + (a >> 7) + 1); return (s0 + ((ft_int32_t)f * (s1 - s0) >> 7)); }
//Draw a cracked screen when you've been hit void DrawCrackedScreen() { int i, x0, y0, x1, y1; float angle, distance; //Pick a centre reasonably close to screen centre x0 = Random(50, 110); y0 = Random(40, 80); //Cycle through 5 angles approximately spread out for (i=0; i<5; i++) { //Pick an angle and a distance and recurse some more lines out from there angle = i * 2.0 * PI / 5 + Random(-0.5, 0.5); distance = Random(10, 50); x1 = x0 + distance * qcos(angle); y1 = y0 - distance * qsin(angle); //begin recursion, each of these five lines will fork a couple more times DrawCrackedScreenExt(x0, y0, x1, y1, 2); } }
//Draw an explosion in the centre where your shell hit void DrawExplosion() { iPoint boom[16]; int i; double angle, distance; //Define a poly star with some random peaks for (i=0; i<16; i++) { if (i % 2 == 1) distance = 8; else //Random star points to stop all explosions being identical distance = Random(12.0, 24.0); angle = PI * 2 * i / 16.0; boom[i].x = 80.0 - distance * qsin(angle); boom[i].y = 60 + distance * qcos(angle); } DrawPoly(16, boom, YELLOW); }
/* cos funtion */ ft_int16_t qcos(ft_uint16_t a) { return (qsin(a + 16384)); }
//Calculate new angle and position given starting angle and position when timer started, elapsed time and keystate when last changed. void MoveCamera(Point3d *cameraPos, Point3d *cameraAngle, Point3d baselinePos, float baselineAngle, unsigned int elapsed, int keys) { float distance; if(blocked) SetMotors(0,0); switch (keys & (KEY_RIGHT_BACK+KEY_RIGHT_FORWARD+KEY_LEFT_BACK+KEY_LEFT_FORWARD)) { case KEY_RIGHT_BACK+KEY_LEFT_FORWARD: { //rotate right if (blocked) { blocked=false; CloseMotors(); } cameraAngle->y=baselineAngle + (PI * 2.0 * elapsed) / rotateSleep; } break; case KEY_RIGHT_FORWARD+KEY_LEFT_BACK: { //rotate left if (blocked) { blocked=false; CloseMotors(); } cameraAngle->y=baselineAngle - (PI * 2.0 * elapsed) / rotateSleep; } break; case KEY_RIGHT_FORWARD: { //one wheel rotate left if (blocked) { blocked=false; CloseMotors(); } cameraAngle->y=baselineAngle - (PI * elapsed) / rotateSleep; } break; case KEY_LEFT_FORWARD: { //one wheel rotate right if (blocked) { blocked=false; CloseMotors(); } cameraAngle->y=baselineAngle + (PI * elapsed) / rotateSleep; } break; case KEY_RIGHT_BACK: { //one wheel rotate left if (blocked) { blocked=false; CloseMotors(); } cameraAngle->y=baselineAngle + (PI * elapsed) / rotateSleep; } break; case KEY_LEFT_BACK: { //one wheel rotate left if (blocked) { blocked=false; CloseMotors(); } cameraAngle->y=baselineAngle - (PI * elapsed) / rotateSleep; } break; case KEY_RIGHT_FORWARD+KEY_LEFT_FORWARD: { //forward //First, check if anything is in our way int ob = LineHitsObject(*cameraPos, *cameraAngle); if (ob != 0) { //something's in the way, calculate the distance to it Point3d offset = SubtractPoint(world.objects[ob].centre, *cameraPos); distance = qsqrt(offset.x * offset.x + offset.z * offset.z); //if we're too close, stop engines and refuse to proceed if (distance < 30 && !blocked) { if (world.objects[ob].colour.R==255 && world.objects[ob].colour.G==0 && world.objects[ob].colour.B==0) { //it's a barrel - red barrels always explode in FPSs! LoseLife("Beware barrels!"); } else { OpenMotors(); SetMotors(0,0); PlaySound(SOUND_HIT); blocked=true; } break; } } if (blocked) { blocked=false; CloseMotors(); } distance=(20.0 * elapsed)/FORWARDSLEEP; cameraPos->x=baselinePos.x + (distance * qsin(baselineAngle)); cameraPos->z=baselinePos.z + (distance * qcos(baselineAngle)); }; break; case KEY_RIGHT_BACK+KEY_LEFT_BACK: { //backwards //First, check if anything is in our way Point3d dir=*cameraAngle; dir.y=ClipAngle(dir.y+PI); int ob = LineHitsObject(*cameraPos, dir); if (ob != 0) { //something's in the way, calculate the distance to it Point3d offset = SubtractPoint(world.objects[ob].centre, *cameraPos); distance = qsqrt(offset.x * offset.x + offset.z * offset.z); //if we're too close, stop engines and refuse to proceed if (distance < 30 && !blocked) { if (world.objects[ob].colour.R==255 && world.objects[ob].colour.G==0 && world.objects[ob].colour.B==0) { //it's a barrel - red barrels always explode in FPSs! LoseLife("Beware barrel!s"); } else { OpenMotors(); SetMotors(0,0); PlaySound(SOUND_HIT); blocked=true; } break; } } if (blocked) { blocked=false; CloseMotors(); } distance=(20.0 * elapsed)/FORWARDSLEEP; cameraPos->x=baselinePos.x - (distance * qsin(baselineAngle)); cameraPos->z=baselinePos.z - (distance * qcos(baselineAngle)); }; } //normalise ret to 0..2PI cameraAngle->y = ClipAngle(cameraAngle->y); }
//Handle tank movement void MoveTank() { Point3d playerOffset = SubtractPoint(cameraPos, world.objects[tankObjectIndex].centre); double angleToPlayer; if (playerOffset.x == 0.0) { angleToPlayer = ((playerOffset.z < 0.0) ? PI / 2.0 : 0.0); } else { angleToPlayer = qatan((double)playerOffset.x / (double)playerOffset.z); if (playerOffset.x < 0.0) angleToPlayer += PI; } angleToPlayer = ClipAngle(angleToPlayer); double distanceToPlayer = qsqrt(playerOffset.x * playerOffset.x + playerOffset.z * playerOffset.z); double angleOffset = ClipAngle(world.objects[tankObjectIndex].heading.y - angleToPlayer); /* DrawText(5,35,"X:%d, Z:%d",(int)(playerOffset.x),(int)(playerOffset.z)); DrawText(5,50,"AO:%d, AP:%d",(int)(180.0/PI*angleOffset),(int)(180.0/PI*angleToPlayer)); DrawText(5,65,"DI:%d, Atan:%d",(int)(distanceToPlayer),(int)(1000.0 * qatan((double)playerOffset.x / (double)playerOffset.z))); */ switch(behaviourType) { case 0: { //move forward MoveObject(&(world.objects[tankObjectIndex]), CreatePoint(2.0 * qsin(world.objects[tankObjectIndex].heading.y), 0.0, 2.0 * qcos(world.objects[tankObjectIndex].heading.y))); } break; case 1: { //rotate right RotateObjectYAxis(&(world.objects[tankObjectIndex]), 5.0 * PI * 2.0 /360.0); } break; case 2: { //rotate left RotateObjectYAxis(&(world.objects[tankObjectIndex]), -5.0 * PI * 2.0 /360.0); } break; case 3: { //hunt! if (angleOffset > PI/4.0 && angleOffset < 7.0 * PI / 4.0) { //if not pointing roughly at player, turn towards player RotateObjectYAxis(&(world.objects[tankObjectIndex]), PI / 180.0 * (angleOffset < PI ? -5.0 : 5.0)); } else if (distanceToPlayer > 75.0) { //if pointing roughly at player but far away, move forward MoveObject(&(world.objects[tankObjectIndex]), CreatePoint(2.0 * qsin(world.objects[tankObjectIndex].heading.y), 0.0, 2.0 * qcos(world.objects[tankObjectIndex].heading.y))); } else if (angleOffset < PI / 180.0 * 5.0 || angleOffset > PI / 180.0 * 355.0) { //turn more finely RotateObjectYAxis(&(world.objects[tankObjectIndex]), PI / 180.0 * (angleOffset < PI ? -1.0 : 1.0)); } else { //if pointing roughly at player and close, turn towards player RotateObjectYAxis(&(world.objects[tankObjectIndex]), PI / 180.0 * (angleOffset < PI ? -5.0 : 5.0)); } } } playerOffset = SubtractPoint(cameraPos, world.objects[tankObjectIndex].centre); if (playerOffset.x == 0.0) { angleToPlayer = ((playerOffset.z < 0.0) ? PI / 2.0 : 0.0); } else { angleToPlayer = qatan((double)playerOffset.x / (double)playerOffset.z); if (playerOffset.x < 0.0) angleToPlayer += PI; } angleToPlayer = ClipAngle(angleToPlayer); distanceToPlayer = qsqrt(playerOffset.x * playerOffset.x + playerOffset.z * playerOffset.z); angleOffset = ClipAngle(world.objects[tankObjectIndex].heading.y - angleToPlayer); if (angleOffset < PI / 180.0 * 5.0 || angleOffset > PI / 180.0 * 355.0) { //if pointing at player, fire PlaySound(SOUND_SHOOT); //Hit if close enough angle if (angleOffset < PI / 180.0 * 2.0 || angleOffset > PI / 180.0 * 358.0) { LoseLife("You got shot!"); } else { //Missed - pick a new behaviour ChooseBehaviour(); } } }