Beispiel #1
0
INT16 InternalGoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT16 sDesGrid, INT8 bReserveAPs, INT8 bAction, INT8 fFlags )
{
	INT16 sLoop,sAPCost;
	INT16 sTempDest,sGoToGrid;
	INT16 sOrigin;
	UINT16 usMaxDist;
	UINT8 ubDirection,ubDirsLeft,ubDirChecked[8],fFound = FALSE;
	INT8 bAPsLeft, fPathFlags;
	UINT8 ubRoomRequired = 0, ubTempRoom;

	if ( bReserveAPs == -1 )
	{
		// default reserve points
		if ( CREATURE_OR_BLOODCAT( pSoldier ) )
		{
			bReserveAPs = 0;
		}
		else
		{
			bReserveAPs = MAX_AP_CARRIED;
		}
	}

	sTempDest = -1;

	// obtain maximum roaming distance from soldier's sOrigin
	usMaxDist = RoamingRange(pSoldier,&sOrigin);

	if ( pSoldier->bOrders <= CLOSEPATROL && (pSoldier->bTeam == CIV_TEAM || pSoldier->ubProfile != NO_PROFILE ) )
	{
		if ( InARoom( pSoldier->usPatrolGrid[0], &ubRoomRequired ) )
		{
			// make sure this doesn't interfere with pathing for scripts
			if ( pSoldier->sAbsoluteFinalDestination != NOWHERE )
			{
				ubRoomRequired = 0;
			}
		}
	}

	pSoldier->usUIMovementMode = DetermineMovementMode(pSoldier, bAction );
	if ( pSoldier->usUIMovementMode == RUNNING && fFlags & FLAG_CAUTIOUS )
	{
		pSoldier->usUIMovementMode = WALKING;
	}

#ifdef DEBUGDECISIONS
	sprintf(tempstr,"%s wants to go towards %d (has range %d)",pSoldier->name,sDesGrid,usMaxDist);
	AIPopMessage(tempstr);
#endif

	// if soldier is ALREADY at the desired destination, quit right away
	if (sDesGrid == pSoldier->sGridNo)
	{
		return(NOWHERE);
	}

	// don't try to approach go after noises or enemies actually in water
	// would be too easy to throw rocks in water, etc. & distract the AI
	if (Water(sDesGrid))
	{
		return(NOWHERE);
	}

	fPathFlags = 0;
	if ( CREATURE_OR_BLOODCAT( pSoldier ) )
	{	/*
		if ( PythSpacesAway( pSoldier->sGridNo, sDesGrid ) <= PATH_CLOSE_RADIUS )
		{
			// then do a limited range path search and see if we can get there
			gubNPCDistLimit = 10;
			if ( !LegalNPCDestination( pSoldier, sDesGrid, ENSURE_PATH, NOWATER, fPathFlags) )
			{
				gubNPCDistLimit = 0;
				return( NOWHERE );
			}
			else
			{
				// allow attempt to path without 'good enough' flag on
				gubNPCDistLimit = 0;
			}
		}
		else
		{
		*/
			fPathFlags = PATH_CLOSE_GOOD_ENOUGH;
		//}
	}

	// first step: try to find an OK destination at or near the desired gridno
	if (!LegalNPCDestination(pSoldier,sDesGrid,ENSURE_PATH,NOWATER,fPathFlags))
	{
#ifdef DEBUGDECISIONS
		AIPopMessage("destination Grid # itself not valid, looking around it");
#endif
		if ( CREATURE_OR_BLOODCAT( pSoldier ) )
		{
			// we tried to get close, failed; abort!
			return( NOWHERE );
		}
		else
		{
			// else look at the 8 nearest gridnos to sDesGrid for a valid destination

			// clear ubDirChecked flag for all 8 directions
			for (ubDirection = 0; ubDirection < 8; ubDirection++)
				ubDirChecked[ubDirection] = FALSE;

			ubDirsLeft = 8;

			// examine all 8 spots around 'sDesGrid'
			// keep looking while directions remain and a satisfactory one not found
			for (ubDirsLeft = 8; ubDirsLeft != 0; ubDirsLeft--)
			{
				if (fFound)
				{
					break;
				}
				// randomly select a direction which hasn't been 'checked' yet
				do
				{
					ubDirection = (UINT8) Random(8);
				}
				while (ubDirChecked[ubDirection]);

				ubDirChecked[ubDirection] = TRUE;

				// determine the gridno 1 tile away from current friend in this direction
				sTempDest = NewGridNo(sDesGrid,DirectionInc( (INT16)(ubDirection + 1) ));

				// if that's out of bounds, ignore it & check next direction
				if (sTempDest == sDesGrid)
					continue;

				if (LegalNPCDestination(pSoldier,sTempDest,ENSURE_PATH,NOWATER,0))
				{
					fFound = TRUE;            // found a spot

#ifdef DEBUGDECISIONS
					AINumMessage("Found a spot!  ubDirection = ",ubDirection + 1);
#endif

					break;                   // stop checking in other directions
				}
			}

			if (!fFound)
			{
#ifdef DEBUGDECISIONS
				AINumMessage("Couldn't find OK destination around grid #",sDesGrid);
#endif

				return(NOWHERE);
			}

			// found a good grid #, this becomes our actual desired grid #
			sDesGrid = sTempDest;
		}
	}

 // HAVE FOUND AN OK destination AND PLOTTED A VALID BEST PATH TO IT


#ifdef DEBUGDECISIONS
 AINumMessage("Chosen legal destination is gridno ",sDesGrid);
 AINumMessage("Tracing along path, pathRouteToGo = ",pSoldier->pathRouteToGo);
#endif

 sGoToGrid = pSoldier->sGridNo;      // start back where soldier is standing now
 sAPCost = 0;		      // initialize path cost counter

 // we'll only go as far along the plotted route as is within our
 // permitted roaming range, and we'll stop as soon as we're down to <= 5 APs

 for (sLoop = 0; sLoop < (pSoldier->usPathDataSize - pSoldier->usPathIndex); sLoop++)
  {
   // what is the next gridno in the path?

	 //sTempDest = NewGridNo( sGoToGrid,DirectionInc( (INT16) (pSoldier->usPathingData[sLoop] + 1) ) );
	 sTempDest = NewGridNo( sGoToGrid,DirectionInc( (INT16) (pSoldier->usPathingData[sLoop]) ) );
   //NumMessage("sTempDest = ",sTempDest);

   // this should NEVER be out of bounds
   if (sTempDest == sGoToGrid)
    {
#ifdef BETAVERSION
     sprintf(tempstr,"GoAsFarAsPossibleTowards: ERROR - gridno along valid route is invalid!  guynum %d, sTempDest = %d",pSoldier->ubID,sTempDest);

#ifdef RECORDNET
     fprintf(NetDebugFile,"\n\t%s\n",tempstr);
#endif

     PopMessage(tempstr);
     SaveGame(ERROR_SAVE);
#endif

     break;           // quit here, sGoToGrid is where we are going
    }

   // if this takes us beyond our permitted "roaming range"
   if (SpacesAway(sOrigin,sTempDest) > usMaxDist)
     break;           // quit here, sGoToGrid is where we are going


	 if ( ubRoomRequired )
	 {
		if ( !( InARoom( sTempDest, &ubTempRoom ) && ubTempRoom == ubRoomRequired ) )
		{
		 // quit here, limited by room!
		 break;
		}
	 }

   if ( (fFlags & FLAG_STOPSHORT) && SpacesAway( sDesGrid, sTempDest ) <= STOPSHORTDIST )
	 {
     break;           // quit here, sGoToGrid is where we are going
	 }

   // if this gridno is NOT a legal NPC destination
   // DONT'T test path again - that would replace the traced path! - Ian
   // NOTE: It's OK to go *THROUGH* water to try and get to the destination!
   if (!LegalNPCDestination(pSoldier,sTempDest,IGNORE_PATH,WATEROK,0))
     break;           // quit here, sGoToGrid is where we are going


   // CAN'T CALL PathCost() HERE! IT CALLS findBestPath() and overwrites
   //       pathRouteToGo !!!  Gotta calculate the cost ourselves - Ian
   //
   //ubAPsLeft = pSoldier->bActionPoints - PathCost(pSoldier,sTempDest,FALSE,FALSE,FALSE,FALSE,FALSE);

	 if (gfTurnBasedAI)
	 {
		 // if we're just starting the "costing" process (first gridno)
		 if (sLoop == 0)
			{
			/*
			 // first, add any additional costs - such as intermediate animations, etc.
			 switch(pSoldier->anitype[pSoldier->anim])
				{
				 // in theory, no NPC should ever be in one of these animations as
				 // things stand (they don't medic anyone), but leave it for robustness
				 case START_AID   :
				 case GIVING_AID  : sAnimCost = AP_STOP_FIRST_AID;
					break;

				 case TWISTOMACH  :
				 case COLLAPSED   : sAnimCost = AP_GET_UP;
					break;

				 case TWISTBACK   :
				 case UNCONSCIOUS : sAnimCost = (AP_ROLL_OVER + AP_GET_UP);
					break;

				 default          : sAnimCost = 0;
				}

			 // this is our first cost
			 sAPCost += sAnimCost;
			 */

			 if (pSoldier->usUIMovementMode == RUNNING)
			 {
				sAPCost += AP_START_RUN_COST;
			 }
			}

		 // ATE: Direction here?
		 sAPCost += EstimateActionPointCost( pSoldier, sTempDest, (INT8) pSoldier->usPathingData[sLoop], pSoldier->usUIMovementMode, (INT8) sLoop, (INT8) pSoldier->usPathDataSize );

		 bAPsLeft = pSoldier->bActionPoints - sAPCost;
	 }

	 // if after this, we have <= 5 APs remaining, that's far enough, break out
	 // (the idea is to preserve APs so we can crouch or react if
	 // necessary, and benefit from the carry-over next turn if not needed)
	 // This routine is NOT used by any GREEN AI, so such caution is warranted!

	 if ( gfTurnBasedAI && (bAPsLeft < bReserveAPs) )
		 break;
	 else
		{
		 sGoToGrid = sTempDest;    // we're OK up to here

		 // if exactly 5 APs left, don't bother checking any further
		 if ( gfTurnBasedAI && (bAPsLeft == bReserveAPs) )
			 break;
		}		
  }


 // if it turned out we couldn't go even 1 tile towards the desired gridno
 if (sGoToGrid == pSoldier->sGridNo)
  {
#ifdef DEBUGDECISIONS
   sprintf(tempstr,"%s will go NOWHERE, path doesn't meet criteria",pSoldier->name);
   AIPopMessage(tempstr);
#endif

   return(NOWHERE);             // then go nowhere
  }
 else
  {
   // possible optimization - stored path IS good if we're going all the way
   if (sGoToGrid == sDesGrid)
	 {
     pSoldier->bPathStored = TRUE;
		 pSoldier->sFinalDestination = sGoToGrid;
	 }
	 else if ( pSoldier->usPathIndex == 0 )
	 {
		// we can hack this surely! -- CJC
     pSoldier->bPathStored = TRUE; 
		 pSoldier->sFinalDestination = sGoToGrid;
		 pSoldier->usPathDataSize = sLoop + 1;
	 }

#ifdef DEBUGDECISIONS
		ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"%d to %d with %d APs left", pSoldier->ubID, sGoToGrid, pSoldier->bActionPoints );
 #endif


		return( sGoToGrid );
  }
}
Beispiel #2
0
INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod )
{
	INT32	iSkill;
	INT32	iChance, iReportChance;
	INT32	iRoll, iMadeItBy;
	INT8	bSlot;
	INT32	iLoop;
	SOLDIERTYPE * pTeamSoldier;
	INT8	bBuddyIndex;
  BOOLEAN fForceDamnSound = FALSE;

	iReportChance = -1;

	switch (bReason)
	{
		case LOCKPICKING_CHECK:
		case ELECTRONIC_LOCKPICKING_CHECK:

      fForceDamnSound = TRUE;

			iSkill = EffectiveMechanical( pSoldier );
			if (iSkill == 0)
			{
				break;
			}
			// adjust skill based on wisdom (knowledge) 
			iSkill = iSkill * (EffectiveWisdom( pSoldier ) + 100) / 200;
			// and dexterity (clumsy?)
			iSkill = iSkill * (EffectiveDexterity( pSoldier ) + 100) / 200;
			// factor in experience
			iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3;
			if (HAS_SKILL_TRAIT( pSoldier, LOCKPICKING ) )
			{
				// if we specialize in picking locks...
				iSkill += gbSkillTraitBonus[LOCKPICKING] * NUM_SKILL_TRAITS( pSoldier, LOCKPICKING );
			}
			if (bReason == ELECTRONIC_LOCKPICKING_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) )
			{
				// if we are unfamiliar with electronics...
				iSkill /= 2;
			}
			// adjust chance based on status of kit
			bSlot = FindObj( pSoldier, LOCKSMITHKIT );
			if (bSlot == NO_SLOT)
			{
				// this should never happen, but might as well check...
				iSkill = 0;
			}
			iSkill = iSkill * pSoldier->inv[bSlot].bStatus[0] / 100;
			break;
		case ATTACHING_DETONATOR_CHECK:
		case ATTACHING_REMOTE_DETONATOR_CHECK:
			iSkill = EffectiveExplosive( pSoldier );			
			if (iSkill == 0)
			{
				break;
			}
			iSkill = (iSkill * 3 + EffectiveDexterity( pSoldier ) ) / 4;
			if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS )) )
			{
				iSkill /= 2;
			}
			break;
		case PLANTING_BOMB_CHECK:
		case PLANTING_REMOTE_BOMB_CHECK:
			iSkill = EffectiveExplosive( pSoldier ) * 7;
			iSkill += EffectiveWisdom( pSoldier ) * 2;
			iSkill += EffectiveExpLevel( pSoldier ) * 10;
			iSkill = iSkill / 10; // bring the value down to a percentage

			if ( bReason == PLANTING_REMOTE_BOMB_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) )
			{
				// deduct only a bit...
				iSkill = (iSkill * 3) / 4;
			}

			// Ok, this is really damn easy, so skew the values...
			// e.g. if calculated skill is 84, skewed up to 96
			// 51 to 84
			// 22 stays as is
			iSkill = (iSkill + 100 * (iSkill / 25) ) / (iSkill / 25 + 1);
			break;

		case DISARM_TRAP_CHECK:

      fForceDamnSound = TRUE;

			iSkill = EffectiveExplosive( pSoldier ) * 7;
			if ( iSkill == 0 )
			{
				break;
			}
			iSkill += EffectiveDexterity( pSoldier ) * 2;
			iSkill += EffectiveExpLevel( pSoldier ) * 10;
			iSkill = iSkill / 10; // bring the value down to a percentage
			// penalty based on poor wisdom
			iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5;
			break;

		case DISARM_ELECTRONIC_TRAP_CHECK:

      fForceDamnSound = TRUE;

			iSkill = __max( EffectiveMechanical( pSoldier ) , EffectiveExplosive( pSoldier ) ) * 7;
			if ( iSkill == 0 )
			{
				break;
			}
			iSkill += EffectiveDexterity( pSoldier ) * 2;
			iSkill += EffectiveExpLevel( pSoldier ) * 10;
			iSkill = iSkill / 10; // bring the value down to a percentage
			// penalty based on poor wisdom
			iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5;

			if ( !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS )) )
			{
				iSkill = (iSkill * 3) / 4;
			}
			break;

		case OPEN_WITH_CROWBAR:
			// Add for crowbar...
			iSkill = EffectiveStrength( pSoldier ) + 20;
      fForceDamnSound = TRUE;
			break;

		case SMASH_DOOR_CHECK:
			iSkill = EffectiveStrength( pSoldier );
			break;
		case UNJAM_GUN_CHECK:
			iSkill = 30 + EffectiveMechanical( pSoldier ) / 2;
			break;
		case NOTICE_DART_CHECK:
			// only a max of ~20% chance
			iSkill = EffectiveWisdom( pSoldier ) / 10 + EffectiveExpLevel( pSoldier );
			break;
		case LIE_TO_QUEEN_CHECK:
			// competitive check vs the queen's wisdom and leadership... poor guy!
			iSkill = 50 * ( EffectiveWisdom( pSoldier ) + EffectiveLeadership( pSoldier ) ) / ( gMercProfiles[ QUEEN ].bWisdom + gMercProfiles[ QUEEN ].bLeadership );
			break;
		case ATTACHING_SPECIAL_ITEM_CHECK:
		case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK:
			iSkill = EffectiveMechanical( pSoldier );
			if (iSkill == 0)
			{
				break;
			}
			// adjust skill based on wisdom (knowledge) 
			iSkill = iSkill * (EffectiveWisdom( pSoldier ) + 100) / 200;
			// and dexterity (clumsy?)
			iSkill = iSkill * (EffectiveDexterity( pSoldier ) + 100) / 200;
			// factor in experience
			iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3;
			if (bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) )
			{
				// if we are unfamiliar with electronics...
				iSkill /= 2;
			}
			break;
		default:
			iSkill = 0;
			break;
	}

	iSkill -= GetSkillCheckPenaltyForFatigue( pSoldier, iSkill );

	iChance = iSkill + bChanceMod;

	switch (bReason)
	{
		case LOCKPICKING_CHECK:
		case ELECTRONIC_LOCKPICKING_CHECK:
		case DISARM_TRAP_CHECK:
		case DISARM_ELECTRONIC_TRAP_CHECK:
		case OPEN_WITH_CROWBAR:
		case SMASH_DOOR_CHECK:
		case ATTACHING_SPECIAL_ITEM_CHECK:
		case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK:
			// for lockpicking and smashing locks, if the chance isn't reasonable
			// we set it to 0 so they can never get through the door if they aren't
			// good enough
			if (iChance < 30)
			{
				iChance = 0;
				break;
			}
			// else fall through
		default:
			iChance += GetMoraleModifier( pSoldier );
			break;
	}

	if (iChance > 99)
	{
		iChance = 99;
	}
	else if (iChance < 0)
	{
		iChance = 0;
	}

	iRoll = PreRandom( 100 );
	iMadeItBy = iChance - iRoll;
	if (iMadeItBy < 0)
	{
		if ( (pSoldier->bLastSkillCheck == bReason) && (pSoldier->sGridNo == pSoldier->sSkillCheckGridNo) )
		{
			pSoldier->ubSkillCheckAttempts++;
			if (pSoldier->ubSkillCheckAttempts > 2)
			{
				if (iChance == 0)
				{
					// do we realize that we just can't do this?
					if ( (100 - (pSoldier->ubSkillCheckAttempts - 2) * 20) < EffectiveWisdom( pSoldier ) )
					{
						// say "I can't do this" quote
						TacticalCharacterDialogue( pSoldier, QUOTE_DEFINITE_CANT_DO );
						return( iMadeItBy );
					}
				}
			}
		}
		else
		{
			pSoldier->bLastSkillCheck = bReason;
			pSoldier->ubSkillCheckAttempts = 1;
			pSoldier->sSkillCheckGridNo = pSoldier->sGridNo;
		}

		if ( fForceDamnSound || Random( 100 ) < 40 )
		{
			switch( bReason )
			{
				case UNJAM_GUN_CHECK:
				case NOTICE_DART_CHECK:
				case LIE_TO_QUEEN_CHECK:
					// silent check
					break;
				default:
					DoMercBattleSound( pSoldier, BATTLE_SOUND_CURSE1 );
					break;
			}
		}

	}
	else 
	{
		// A buddy might make a positive comment based on our success;
		// Increase the chance for people with higher skill and for more difficult tasks
		iChance = 15 + iSkill / 20 + (-bChanceMod) / 20;
		if (iRoll < iChance)
		{
			// If a buddy of this merc is standing around nearby, they'll make a positive comment.
			iLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;	
			for ( pTeamSoldier = MercPtrs[ iLoop ]; iLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; iLoop++,pTeamSoldier++ )
			{
				if ( OK_INSECTOR_MERC( pTeamSoldier ) )
				{				
					bBuddyIndex = WhichBuddy( pTeamSoldier->ubProfile, pSoldier->ubProfile );
					if (bBuddyIndex >= 0 && SpacesAway( pSoldier->sGridNo, pTeamSoldier->sGridNo ) < 15)
					{
						switch( bBuddyIndex )
						{
							case 0:
								// buddy #1 did something good!
								TacticalCharacterDialogue( pTeamSoldier, QUOTE_BUDDY_1_GOOD );
								break;
							case 1:
								// buddy #2 did something good!
								TacticalCharacterDialogue( pTeamSoldier, 	QUOTE_BUDDY_2_GOOD );
								break;
							case 2:
								// learn to like buddy did something good!
								TacticalCharacterDialogue( pTeamSoldier, QUOTE_LEARNED_TO_LIKE_WITNESSED );
								break;
							default:
								break;
						}
					}
				}
			}
		}	
	}
	return( iMadeItBy );
}
Beispiel #3
0
int LegalNPCDestination(SOLDIERTYPE *pSoldier, INT16 sGridno, UINT8 ubPathMode, UINT8 ubWaterOK, UINT8 fFlags)
{
	BOOLEAN fSkipTilesWithMercs;
 
	if ((sGridno < 0) || (sGridno >= GRIDSIZE))
  {
#ifdef RECORDNET
   fprintf(NetDebugFile,"LegalNPC->sDestination: ERROR - rcvd invalid gridno %d",gridno);
#endif

#ifdef BETAVERSION
   NumMessage("LegalNPC->sDestination: ERROR - rcvd invalid gridno ",gridno);
#endif

   return(FALSE);
  }

	// return false if gridno on different level from merc
	if ( GridNoOnVisibleWorldTile( pSoldier->sGridNo ) && gpWorldLevelData[ pSoldier->sGridNo ].sHeight != gpWorldLevelData[ sGridno ].sHeight )
	{
		return( FALSE );
	}


	// skip mercs if turnbased and adjacent AND not doing an IGNORE_PATH check (which is used almost exclusively by GoAsFarAsPossibleTowards)
	fSkipTilesWithMercs = (gfTurnBasedAI && ubPathMode != IGNORE_PATH && SpacesAway( pSoldier->sGridNo, sGridno ) == 1 );

 // if this gridno is an OK destination
 // AND the gridno is NOT in a tear-gassed tile when we have no gas mask
 // AND someone is NOT already standing there
 // AND we're NOT already standing at that gridno
 // AND the gridno hasn't been black-listed for us

 // Nov 28 98: skip people in destination tile if in turnbased
 if ( ( NewOKDestination(pSoldier, sGridno, fSkipTilesWithMercs, pSoldier->bLevel ) ) &&
				( !InGas( pSoldier, sGridno ) ) &&
				( sGridno != pSoldier->sGridNo ) &&
				( sGridno != pSoldier->sBlackList ) )
 /*
 if ( ( NewOKDestination(pSoldier, sGridno, FALSE, pSoldier->bLevel ) ) &&
				( !(gpWorldLevelData[ sGridno ].ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS)) || ( pSoldier->inv[ HEAD1POS ].usItem == GASMASK || pSoldier->inv[ HEAD2POS ].usItem == GASMASK ) ) &&
				( sGridno != pSoldier->sGridNo ) &&
				( sGridno != pSoldier->sBlackList ) )*/
 /*
 if ( ( NewOKDestination(pSoldier,sGridno,ALLPEOPLE, pSoldier->bLevel ) ) &&
				( !(gpWorldLevelData[ sGridno ].ubExtFlags[0] & (MAPELEMENT_EXT_SMOKE | MAPELEMENT_EXT_TEARGAS | MAPELEMENT_EXT_MUSTARDGAS)) || ( pSoldier->inv[ HEAD1POS ].usItem == GASMASK || pSoldier->inv[ HEAD2POS ].usItem == GASMASK ) ) &&
				( sGridno != pSoldier->sGridNo ) &&
				( sGridno != pSoldier->sBlackList ) )
				*/
   {
    
	  // if water's a problem, and gridno is in a water tile (bridges are OK)
		if (!ubWaterOK && Water(sGridno))
		  return(FALSE);

    // passed all checks, now try to make sure we can get there!
    switch (ubPathMode)
     {
      // if finding a path wasn't asked for (could have already been done,
      // for example), don't bother
      case IGNORE_PATH     :	return(TRUE);

      case ENSURE_PATH     :	if ( FindBestPath( pSoldier, sGridno, pSoldier->bLevel, WALKING, COPYROUTE, fFlags ) )
															{
			   												return(TRUE);        // legal destination
															}
      												else // got this far, but found no clear path,
															{
																// so test fails
        												return(FALSE);
															}
															// *** NOTE: movement mode hardcoded to WALKING !!!!!
			case ENSURE_PATH_COST:	return(PlotPath(pSoldier,sGridno,FALSE,FALSE,FALSE,WALKING,FALSE,FALSE,0));

      default              :
#ifdef BETAVERSION
			     NumMessage("LegalNPC->sDestination: ERROR - illegal pathMode = ",ubPathMode);
#endif
			     return(FALSE);
     }
   }
 else  // something failed - didn't even have to test path
   return(FALSE);       	// illegal destination
}
Beispiel #4
0
INT16 MostImportantNoiseHeard( SOLDIERTYPE *pSoldier, INT32 *piRetValue, BOOLEAN * pfClimbingNecessary, BOOLEAN * pfReachable )
{
	UINT32 uiLoop;
	INT8 * pbPersOL, * pbPublOL;
	INT16 *psLastLoc,*psNoiseGridNo;
	INT8 * pbNoiseLevel;
	INT8 *pbLastLevel;
	UINT8 *pubNoiseVolume;
	INT32 iDistAway;
	INT32	iNoiseValue, iBestValue = -10000;
	INT16 sBestGridNo = NOWHERE;
	INT8	bBestLevel = 0;
	INT16 sClimbingGridNo;
	BOOLEAN fClimbingNecessary = FALSE;
	SOLDIERTYPE * pTemp;	

	pubNoiseVolume = &gubPublicNoiseVolume[pSoldier->bTeam];
	psNoiseGridNo = &gsPublicNoiseGridno[pSoldier->bTeam];
	pbNoiseLevel = &gbPublicNoiseLevel[pSoldier->bTeam];

	psLastLoc = gsLastKnownOppLoc[pSoldier->ubID];

	// hang pointers at start of this guy's personal and public opponent opplists
	pbPersOL = pSoldier->bOppList;
	pbPublOL = gbPublicOpplist[pSoldier->bTeam];

	// look through this man's personal & public opplists for opponents heard
	for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
	{
		pTemp = MercSlots[ uiLoop ];

		// if this merc is inactive, at base, on assignment, or dead
		if (!pTemp || !pTemp->bLife)
			continue;          // next merc

		// if this merc is neutral/on same side, he's not an opponent
		if ( CONSIDERED_NEUTRAL( pSoldier, pTemp ) || (pSoldier->bSide == pTemp->bSide))
			continue;          // next merc

		pbPersOL = pSoldier->bOppList + pTemp->ubID;
		pbPublOL = gbPublicOpplist[pSoldier->bTeam] + pTemp->ubID;
		psLastLoc = gsLastKnownOppLoc[pSoldier->ubID] + pTemp->ubID;
		pbLastLevel = gbLastKnownOppLevel[pSoldier->ubID] + pTemp->ubID;

		// if this guy's been personally heard within last 3 turns
		if (*pbPersOL < NOT_HEARD_OR_SEEN)
		{
			// calculate how far this noise was, and its relative "importance"
			iDistAway = SpacesAway(pSoldier->sGridNo,*psLastLoc);
			iNoiseValue = (*pbPersOL) * iDistAway;               // always a negative number!

			if (iNoiseValue > iBestValue)
			{
				iBestValue = iNoiseValue;
				sBestGridNo = *psLastLoc;
				bBestLevel = *pbLastLevel;
			}
		}

		// if this guy's been publicly heard within last 3 turns
		if (*pbPublOL < NOT_HEARD_OR_SEEN)
		{
			// calculate how far this noise was, and its relative "importance"
			iDistAway = SpacesAway(pSoldier->sGridNo,gsPublicLastKnownOppLoc[pSoldier->bTeam][pTemp->ubID]);
			iNoiseValue = (*pbPublOL) * iDistAway;               // always a negative number!

			if (iNoiseValue > iBestValue)
			{
				iBestValue = iNoiseValue;
				sBestGridNo = gsPublicLastKnownOppLoc[pSoldier->bTeam][pTemp->ubID];
				bBestLevel = gbPublicLastKnownOppLevel[pSoldier->bTeam][pTemp->ubID];
			}
		}

	}

	// if any "misc. noise" was also heard recently
	if (pSoldier->sNoiseGridno != NOWHERE)
	{
		if ( pSoldier->bNoiseLevel != pSoldier->bLevel || PythSpacesAway( pSoldier->sGridNo, pSoldier->sNoiseGridno ) >= 6 || SoldierTo3DLocationLineOfSightTest( pSoldier, pSoldier->sNoiseGridno, pSoldier->bNoiseLevel, 0, (UINT8) MaxDistanceVisible(), FALSE ) == 0 )
		{
			// calculate how far this noise was, and its relative "importance"
			iDistAway = SpacesAway(pSoldier->sGridNo,pSoldier->sNoiseGridno);
			iNoiseValue = ((pSoldier->ubNoiseVolume / 2) - 6) * iDistAway;

			if (iNoiseValue > iBestValue)
			{
				iBestValue = iNoiseValue;
				sBestGridNo = pSoldier->sNoiseGridno;
				bBestLevel = pSoldier->bNoiseLevel;
			}
		}
		else
		{
			// we are there or near
			pSoldier->sNoiseGridno = NOWHERE;        // wipe it out, not useful anymore
			pSoldier->ubNoiseVolume = 0;
		}
	}


	// if any recent PUBLIC "misc. noise" is also known
	if ( (pSoldier->bTeam != CIV_TEAM) || ( pSoldier->ubCivilianGroup == KINGPIN_CIV_GROUP ) )
	{
	
		if (*psNoiseGridNo != NOWHERE)
		{
			// if we are NOT there (at the noise gridno)
			if ( *pbNoiseLevel != pSoldier->bLevel || PythSpacesAway( pSoldier->sGridNo, *psNoiseGridNo ) >= 6 || SoldierTo3DLocationLineOfSightTest( pSoldier, *psNoiseGridNo, *pbNoiseLevel, 0, (UINT8) MaxDistanceVisible(), FALSE ) == 0 )
			{
				// calculate how far this noise was, and its relative "importance"
				iDistAway = SpacesAway(pSoldier->sGridNo,*psNoiseGridNo);
				iNoiseValue = ((*pubNoiseVolume / 2) - 6) * iDistAway;

				if (iNoiseValue > iBestValue)
				{
					iBestValue = iNoiseValue;
					sBestGridNo = *psNoiseGridNo;
					bBestLevel = *pbNoiseLevel;
				}
			}
		}

	}

	if (sBestGridNo != NOWHERE && pfReachable )
	{
		*pfReachable = TRUE;

		// make civs not walk to noises outside their room if on close patrol/onguard
		if ( pSoldier->bOrders <= CLOSEPATROL && (pSoldier->bTeam == CIV_TEAM || pSoldier->ubProfile != NO_PROFILE ) )
		{
			UINT8	ubRoom, ubNewRoom;

			// any other combo uses the default of ubRoom == 0, set above
			if ( InARoom( pSoldier->usPatrolGrid[0], &ubRoom ) )
			{
				if ( !InARoom( pSoldier->usPatrolGrid[0], &ubNewRoom ) || ubRoom != ubNewRoom )
				{
					*pfReachable = FALSE;
				}
			}
		}

		if ( *pfReachable )
		{
			// if there is a climb involved then we should store the location 
			// of where we have to climb to instead
			sClimbingGridNo = GetInterveningClimbingLocation( pSoldier, sBestGridNo, bBestLevel, &fClimbingNecessary );
			if ( fClimbingNecessary )
			{
				if ( sClimbingGridNo == NOWHERE )
				{
					// can't investigate!
					*pfReachable = FALSE;
				}
				else
				{
					sBestGridNo = sClimbingGridNo;
					fClimbingNecessary = TRUE;
				}
			}
			else
			{
				fClimbingNecessary = FALSE;
			} 
		}
	}

	if ( piRetValue )
	{
		*piRetValue = iBestValue;
	}

	if ( pfClimbingNecessary )
	{
		*pfClimbingNecessary = fClimbingNecessary;
	}

#ifdef DEBUGDECISIONS
	if (sBestGridNo != NOWHERE)
		AINumMessage("MOST IMPORTANT NOISE HEARD FROM GRID #",sBestGridNo);
#endif

	return(sBestGridNo);
}