//Draw radar dots on HUD void DrawRadarDots(bool clear) { int i; int x, y; Point3d transformed; SetLineWidth(3); //only the tank is largest for(i=1; i<=world.numObjects; i++) { transformed=TransformPoint(world.objects[i].centre, cameraPos, cameraAngle); if (i==2) //rest of objects a little smaller SetLineWidth(2); //draw transformed point on radar x = (int)(transformed.x / 200.0 * 20.0); y = (int)(transformed.z / 200.0 * 20.0); if (qsqrt(x * x + y * y) < 20) { //if within circle Plot(x + radarX, radarY - y, (clear ? BLACK : world.objects[i].colour)); } } SetLineWidth(1); }
main() { char s[80]; double fabs(), floor(); #if EXPSCALE || EXPSC2 double exp(); #endif double sqrt(); /* required to compute rms error */ int i, j, k; long m, n; dprec(); /* set up floating point coprocessor */ merror = 0; /*aiconf = -1;*/ /* configure Airy function */ x = 1.0; z = x * x; qclear( qmax ); qtoasc( qmax, strmax, 4 ); qclear( qrmsa ); qclear( qave ); #if 1 printf(" Start at random number #:" ); gets( s ); sscanf( s, "%ld", &n ); printf("%ld\n", n ); #else n = 0; #endif for( m=0; m<n; m++ ) drand( &x ); n = 0; m = 0; x = floor( x ); loop: for( i=0; i<100; i++ ) { n++; m++; /* make random number in desired range */ drand( &x ); x = WIDTH * ( x - 1.0 ) + LOW; #if EXPSCALE x = exp(x); drand( &a ); a = 1.0e-13 * x * a; if( x > 0.0 ) x -= a; else x += a; #endif #if ONEINT k = x; x = k; #endif etoq( &x, q1 ); /* double number to q type */ /* do again if second argument required */ #if TWOARG || THREEARG || FOURARG drand( &a ); a = WIDTHA * ( a - 1.0 ) + LOWA; /*a /= 50.0;*/ #if EXPSC2 a = exp(a); drand( &y2 ); y2 = 1.0e-13 * y2 * a; if( a > 0.0 ) a -= y2; else a += y2; #endif #if TWOINT || THREEINT k = a + 0.25; a = k; #endif etoq( &a, qy4 ); #endif #if THREEARG || FOURARG drand( &b ); #if PROB /* b = b - 1.0; b = a * b; */ b = WIDTHA * ( b - 1.0 ) + LOWA; /* Half-integer a and b */ /*a = 0.5*floor(2.0*a+1.0);*/ a = 0.5; b = 0.5*floor(2.0*b+1.0); etoq( &a, qy4 ); /*x = (a / (a+b));*/ #else b = WIDTHA * ( b - 1.0 ) + LOWA; #endif #if THREEINT j = b + 0.25; b = j; #endif etoq( &b, qb ); #endif #if FOURARG drand( &c ); c = WIDTHA * ( c - 1.0 ) + LOWA; /* for hyp2f1 to ensure c-a-b > -1 */ /* z = c-a-b; if( z < -1.0 ) c -= 1.6 * z; */ etoq( &c, qc ); #endif /*printf("%.16E %.16E\n", a, x);*/ /* compute function under test */ #if ONEARG #if FOURANS /*FUNC( x, &z, &y2, &y3, &y4 );*/ FUNC( x, &y4, &y2, &y3, &z ); #else #if TWOANS FUNC( x, &z, &y2 ); /*FUNC( x, &y2, &z );*/ #else #if ONEINT z = FUNC( k ); #else z = FUNC( x ); #endif #endif #endif #endif #if TWOARG #if TWOINT /*z = FUNC( k, x );*/ /*z = FUNC( x, k );*/ z = FUNC( a, x ); #else #if FOURANS FUNC( a, x, &z, &y2, &y3, &y4 ); #else z = FUNC( a, x ); #endif #endif #endif #if THREEARG #if THREEINT z = FUNC( j, k, x ); #else z = FUNC( a, b, x ); #endif #endif #if FOURARG z = FUNC( a, b, c, x ); #endif etoq( &z, q2 ); /* handle detected overflow */ if( (z == MAXNUM) || (z == -MAXNUM) ) { printf("detected overflow "); #if FOURARG printf("%.4E %.4E %.4E %.4E %.4E %6ld \n", a, b, c, x, y, n); #else printf("%.16E %.4E %.4E %6ld \n", x, a, z, n); #endif e = 0.0; m -= 1; goto endlup; } /* Skip high precision if underflow. */ if( merror == UNDERFLOW ) goto underf; /* compute high precision function */ #if ONEARG #if FOURANS /*QFUNC( q1, qz, qy2, qy3, qy4 );*/ QFUNC( q1, qy4, qy2, qy3, qz ); #else #if TWOANS QFUNC( q1, qz, qy2 ); /*QFUNC( q1, qy2, qz );*/ #else /*qclear( qy4 );*/ /*qmov( qone, qy4 );*/ /*QFUNC( qy4, q1, qz );*/ /*QFUNC( 1, q1, qz );*/ QFUNC( q1, qz ); /* normal */ #endif #endif #endif #if TWOARG #if TWOINT /*QFUNC( k, q1, qz );*/ /*QFUNC( q1, qy4, qz );*/ QFUNC( qy4, q1, qz ); #else #if FOURANS QFUNC( qy4, q1, qz, qy2, qy3, qc ); #else /*qclear( qy4 );*/ /*qmov( qone, qy4 );*/ QFUNC( qy4, q1, qz ); #endif #endif #endif #if THREEARG #if THREEINT QFUNC( j, k, q1, qz ); #else QFUNC( qy4, qb, q1, qz ); #endif #endif #if FOURARG QFUNC( qy4, qb, qc, q1, qz ); #endif qtoe( qz, &y ); /* correct answer, in double precision */ /* get absolute error, in extended precision */ qsub( qz, q2, qe ); qtoe( qe, &e ); /* the error in double precision */ /* handle function result equal to zero or underflowed. */ if( qz[1] < 3 || merror == UNDERFLOW || fabs(z) < underthresh ) { underf: merror = 0; /* Don't bother to print anything. */ #if 0 printf("ans 0 "); #if ONEARG printf("%.8E %.8E %.4E %6ld \n", x, y, e, n); #endif #if TWOARG #if TWOINT printf("%d %.8E %.8E %.4E %6ld \n", k, x, y, e, n); #else printf("%.6E %.6E %.6E %.4E %6ld \n", a, x, y, e, n); #endif #endif #if THREEARG printf("%.6E %.6E %.6E %.6E %.4E %6ld \n", a, b, x, y, e, n); #endif #if FOURARG printf("%.4E %.4E %.4E %.4E %.4E %.4E %6ld \n", a, b, c, x, y, e, n); #endif #endif /* 0 */ qclear( qe ); e = 0.0; m -= 1; goto endlup; } else /* relative error */ /* comment out the following two lines if absolute accuracy report */ #if RELERR qdiv( qz, qe, qe ); #else { qmov( qz, q2 ); q2[0] = 0; if( qcmp( q2, qone ) > 0 ) qdiv( qz, qe, qe ); } #endif qadd( qave, qe, qave ); /* absolute value of error */ qe[0] = 0; /* peak detect the error */ if( qcmp(qe, qmax) > 0 ) { qmov( qe, qmax ); qtoasc( qmax, strmax, 4 ); #if ONEARG printf("%.8E %.8E %s %6ld \n", x, y, strmax, n); #endif #if TWOARG #if TWOINT printf("%d %.8E %.8E %s %6ld \n", k, x, y, strmax, n); #else printf("%.6E %.6E %.6E %s %6ld \n", a, x, y, strmax, n); #endif #endif #if THREEARG printf("%.6E %.6E %.6E %.6E %s %6ld \n", a, b, x, y, strmax, n); #endif #if FOURARG printf("%.4E %.4E %.4E %.4E %.4E %s %6ld \n", a, b, c, x, y, strmax, n); #endif } /* accumulate rms error */ /* rmsa += e * e; accumulate the square of the error */ qmul( qe, qe, q2 ); qadd( q2, qrmsa, qrmsa ); endlup: ; } /* report every 100 trials */ /* rms = sqrt( rmsa/m ); */ ltoq( &m, q1 ); qdiv( q1, qrmsa, q2 ); qsqrt( q2, q2 ); qtoasc( q2, strrms, 4 ); qdiv( q1, qave, q2 ); qtoasc( q2, strave, 4 ); /* printf("%6ld max = %s rms = %s ave = %s \n", m, strmax, strrms, strave ); */ printf("%6ld max = %s rms = %s ave = %s \r", m, strmax, strrms, strave ); fflush(stdout); goto loop; }
//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(); } } }