void HandleBulletSpecialFlags( INT32 iBulletIndex ) { BULLET *pBullet; ANITILE_PARAMS AniParams; FLOAT dX, dY; UINT8 ubDirection; pBullet = &( gBullets[ iBulletIndex ] ); memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) ); if ( pBullet->fReal ) { // Create ani tile if this is a spit! if ( pBullet->usFlags & ( BULLET_FLAG_KNIFE ) ) { AniParams.sGridNo = pBullet->sGridNo; AniParams.ubLevelID = ANI_STRUCT_LEVEL; AniParams.sDelay = 100; AniParams.sStartFrame = 3; AniParams.uiFlags = ANITILE_CACHEDTILE | ANITILE_FORWARD | ANITILE_LOOPING | ANITILE_USE_DIRECTION_FOR_START_FRAME; AniParams.sX = FIXEDPT_TO_INT32( pBullet->qCurrX ); AniParams.sY = FIXEDPT_TO_INT32( pBullet->qCurrY ); AniParams.sZ = CONVERT_HEIGHTUNITS_TO_PIXELS( FIXEDPT_TO_INT32( pBullet->qCurrZ ) ); if ( pBullet->usFlags & ( BULLET_FLAG_CREATURE_SPIT ) ) { strcpy( AniParams.zCachedFile, "TILECACHE\\SPIT2.STI" ); } else if ( pBullet->usFlags & ( BULLET_FLAG_KNIFE ) ) { strcpy( AniParams.zCachedFile, "TILECACHE\\KNIFING.STI" ); pBullet->ubItemStatus = pBullet->pFirer->inv[ HANDPOS ][0]->data.objectStatus; } // Get direction to use for this guy.... dX = ( (FLOAT)( pBullet->qIncrX ) / FIXEDPT_FRACTIONAL_RESOLUTION ); dY = ( (FLOAT)( pBullet->qIncrY ) / FIXEDPT_FRACTIONAL_RESOLUTION ); ubDirection = atan8( 0, 0, (INT16)( dX * 100 ), (INT16)( dY * 100 ) ); AniParams.uiUserData3 = ubDirection; pBullet->pAniTile = CreateAnimationTile( &AniParams ); // IF we are anything that needs a shadow.. set it here.... if ( pBullet->usFlags & ( BULLET_FLAG_KNIFE ) ) { AniParams.ubLevelID = ANI_SHADOW_LEVEL; AniParams.sZ = 0; pBullet->pShadowAniTile = CreateAnimationTile( &AniParams ); } } } }
INT16 TrackScent( SOLDIERTYPE * pSoldier ) { // This function returns the best gridno to go to based on the scent being followed, // and the soldier (creature/animal)'s current direction (which is used to resolve // ties. INT32 iXDiff, iYDiff, iXIncr; INT32 iStart, iXStart, iYStart; INT32 iGridNo; INT8 bDir; INT32 iBestGridNo = NOWHERE; UINT8 ubBestDirDiff = 5, ubBestStrength = 0; UINT8 ubDirDiff, ubStrength; UINT8 ubSoughtSmell; MAP_ELEMENT * pMapElement; iStart = pSoldier->sGridNo; iXStart = iStart % WORLD_COLS; iYStart = iStart / WORLD_COLS; if (CREATURE_OR_BLOODCAT( pSoldier ) ) // or bloodcats { // tracking humans; search the edges of a 7x7 square for the // most promising tile ubSoughtSmell = HUMAN; for (iYDiff = -RADIUS; iYDiff < (RADIUS + 1); iYDiff++) { if (iYStart + iYDiff < 0) { // outside of map! might be on map further down... continue; } else if (iYStart + iYDiff > WORLD_ROWS) { // outside of bottom of map! abort! break; } if (iYDiff == -RADIUS || iYDiff == RADIUS) { iXIncr = 1; } else { // skip over the spots in the centre of the square iXIncr = RADIUS * 2; } for (iXDiff = -RADIUS; iXDiff < (RADIUS + 1); iXDiff += iXIncr) { iGridNo = iStart + iXDiff + iYDiff * WORLD_ROWS; if (abs( iGridNo % WORLD_ROWS - iXStart ) > RADIUS) { // wrapped across map! continue; } if (LegalNPCDestination(pSoldier,pSoldier->usActionData,ENSURE_PATH,WATEROK,0)) { // check this location out pMapElement = &(gpWorldLevelData[iGridNo]); if (pMapElement->ubSmellInfo && (SMELL_TYPE( pMapElement->ubSmellInfo ) == ubSoughtSmell)) { ubStrength = SMELL_STRENGTH( pMapElement->ubSmellInfo ); if (ubStrength > ubBestStrength ) { iBestGridNo = iGridNo; ubBestStrength = ubStrength; bDir = atan8( (INT16) iXStart, (INT16) iYStart, (INT16) (iXStart + iXDiff), (INT16) (iYStart + iYDiff) ); // now convert it into a difference in degree between it and our current dir ubBestDirDiff = abs( pSoldier->bDirection - bDir ); if (ubBestDirDiff > 4 ) // dir 0 compared with dir 6, for instance { ubBestDirDiff = 8 - ubBestDirDiff; } } else if (ubStrength == ubBestStrength) { if (iBestGridNo == NOWHERE) { // first place we've found with the same strength iBestGridNo = iGridNo; ubBestStrength = ubStrength; } else { // use directions to decide between the two // start by calculating direction to the new gridno bDir = atan8( (INT16) iXStart, (INT16) iYStart, (INT16) (iXStart + iXDiff), (INT16) (iYStart + iYDiff) ); // now convert it into a difference in degree between it and our current dir ubDirDiff = abs( pSoldier->bDirection - bDir ); if (ubDirDiff > 4 ) // dir 0 compared with dir 6, for instance { ubDirDiff = 8 - ubDirDiff; } if (ubDirDiff < ubBestDirDiff || ((ubDirDiff == ubBestDirDiff) && Random( 2 ))) { // follow this trail as its closer to the one we're following! // (in the case of a tie, we tossed a coin) ubBestDirDiff = ubDirDiff; } } } } } } // go on to next tile } // go on to next row } else { // who else can track? } if (iBestGridNo != NOWHERE ) { pSoldier->usActionData = (INT16) iBestGridNo; return( (INT16) iBestGridNo ); } return( 0 ); }