HAM5.5b2 merged in!

Notes:
-There may still be bugs!! (In fact, I almost guarantee it -- there's
-Ammo box code added to HR's crate code
-Splitting a crate/box also automatically refills half empty magazines
-new pathing arrows for map screen not included
-code for scouts to know where enemies are going doesn't appear to work... but i'm not sure it was completed.
-lots of gobledy gook (chinese?) comments turned back to english
-also added Bob's popups
-other languages besides english still need to have there language.cpp files updated with array changes
-AI enhancements by Warmsteel (reloading, suppression, roaming, avoiding gas, and other fixes)

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5181 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
MaddMugsy
2012-04-10 23:45:46 +00:00
parent ab3412e5ed
commit c845f9f117
72 changed files with 10737 additions and 2362 deletions
+12
View File
@@ -2095,6 +2095,8 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
// WANNE.TANK: Choose cannon or rocket
UINT16 usHandItem = pSoldier->inv[HANDPOS].usItem;
INT8 bSlot;
if (TANK(pSoldier))
{
// No cannon selected to fire
@@ -2790,6 +2792,16 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier)
break;
/////////////////////////////////////////////////////////////
case AI_ACTION_RELOAD_GUN:
bSlot = FindAmmoToReload( pSoldier, pSoldier->aiData.usActionData, NO_SLOT );
if(bSlot != NO_SLOT)
{
ReloadGun( pSoldier, &(pSoldier->inv[pSoldier->aiData.usActionData]), &(pSoldier->inv[bSlot]) );
ActionDone( pSoldier );
}
break;
default:
#ifdef BETAVERSION
NumMessage("ExecuteAction - Illegal action type = ",pSoldier->aiData.bAction);
+107 -41
View File
@@ -1726,31 +1726,20 @@ BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
// smoke
if (gpWorldLevelData[sGridNo].ubExtFlags[ pSoldier->pathing.bLevel ] & MAPELEMENT_EXT_SMOKE)
{
return( TRUE );
return TRUE;
}
// tear/mustard gas
if((gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_TEARGAS|MAPELEMENT_EXT_MUSTARDGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 200909
return(TRUE);
if ( gpWorldLevelData[sGridNo].ubExtFlags[ pSoldier->pathing.bLevel ] & MAPELEMENT_EXT_BURNABLEGAS )
{
return( TRUE );
}
return(FALSE);
return InGas( pSoldier, sGridNo );
}
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo )
{
// smoke/tear/mustard gas
if((gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_SMOKE|MAPELEMENT_EXT_TEARGAS|MAPELEMENT_EXT_MUSTARDGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 230909
return(TRUE);
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & MAPELEMENT_EXT_BURNABLEGAS )
{
return( TRUE );
}
return(FALSE);
// smoke
if (gpWorldLevelData[sGridNo].ubExtFlags[ pSoldier->pathing.bLevel ] & MAPELEMENT_EXT_SMOKE)
return TRUE;
return InGas(pSoldier,sGridNo);
}
@@ -1761,25 +1750,28 @@ INT16 InWaterOrGas(SOLDIERTYPE *pSoldier, INT32 sGridNo)
return(TRUE);
}
// tear/mustard gas
if((gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_TEARGAS|MAPELEMENT_EXT_MUSTARDGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 200909
return(TRUE);
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & MAPELEMENT_EXT_BURNABLEGAS )
{
return( TRUE );
}
return(FALSE);
return (INT16)InGas( pSoldier, sGridNo );
}
BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo )
{
// tear/mustard gas
if((gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_TEARGAS|MAPELEMENT_EXT_MUSTARDGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 200909
return(TRUE);
if ( gpWorldLevelData[sGridNo].ubExtFlags[pSoldier->pathing.bLevel] & MAPELEMENT_EXT_BURNABLEGAS )
{
return( TRUE );
{//WarmSteel - One square away from gas is still considered in gas, because it could expand any moment.
//Note: this only works for gas that expands with one tile, but hey it's better than nothing!
int iNeighbourGridNo;
for(int iDir = 0; iDir < NUM_WORLD_DIRECTIONS; ++iDir)
{
iNeighbourGridNo = sGridNo + DirectionInc(iDir);
if(!TileIsOutOfBounds(iNeighbourGridNo))
{
// tear/mustard gas
if((gpWorldLevelData[iNeighbourGridNo].ubExtFlags[pSoldier->pathing.bLevel] & (MAPELEMENT_EXT_TEARGAS|MAPELEMENT_EXT_MUSTARDGAS)) && !DoesSoldierWearGasMask(pSoldier))//dnl ch40 200909
{
return(TRUE);
}
if ( gpWorldLevelData[iNeighbourGridNo].ubExtFlags[pSoldier->pathing.bLevel] & MAPELEMENT_EXT_BURNABLEGAS )
{
return( TRUE );
}
}
}
return(FALSE);
@@ -2249,6 +2241,7 @@ INT32 CalcManThreatValue( SOLDIERTYPE *pEnemy, INT32 sMyGrid, UINT8 ubReduceForC
INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT32 * pusFromGridNo)
{
BOOL OppPosKnown = FALSE;
if ( CREATURE_OR_BLOODCAT( pSoldier ) )
{
if ( pSoldier->aiData.bAlertStatus == STATUS_BLACK )
@@ -2269,6 +2262,19 @@ INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT32 * pusFromGridNo)
*pusFromGridNo = pSoldier->aiData.sPatrolGrid[0];
}
//Do we know about any opponent?
for(UINT16 oppID = 0; oppID < MAX_NUM_SOLDIERS; oppID++)
{
if ( pSoldier->aiData.bOppList[oppID] != NOT_HEARD_OR_SEEN && gbPublicOpplist[pSoldier->bTeam][oppID] != NOT_HEARD_OR_SEEN)
{
OppPosKnown = TRUE;
break;
}
}
//TODO: Externalize if people want?
BOOL fLessRestrictiveRoaming = TRUE;
switch (pSoldier->aiData.bOrders)
{
// JA2 GOLD: give non-NPCs a 5 tile roam range for cover in combat when being shot at
@@ -2281,16 +2287,68 @@ INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT32 * pusFromGridNo)
return( 5 );
}
case ONGUARD: return( 5 );
case CLOSEPATROL: return( 15 );
case RNDPTPATROL:
case POINTPATROL: return(10 ); // from nextPatrolGrid, not whereIWas
case FARPATROL: if (pSoldier->aiData.bAlertStatus < STATUS_RED)
case CLOSEPATROL: if (pSoldier->aiData.bAlertStatus < STATUS_RED)
{
return( 25 );
return( 5 );
}
else
{
return( 50 );
if(!OppPosKnown || !fLessRestrictiveRoaming)
{
return( 15 );
}
else
{
return( 30 );
//return( MAX_ROAMING_RANGE );
}
}
case POINTPATROL: if (pSoldier->aiData.bAlertStatus < STATUS_RED)
{
return( 10 );
}
else
{
if(!OppPosKnown || !fLessRestrictiveRoaming)
{
return( 20 );
}
else
{
return( 40 );
//return( MAX_ROAMING_RANGE );
}
} // from nextPatrolGrid, not whereIWas
case RNDPTPATROL: if (pSoldier->aiData.bAlertStatus < STATUS_RED)
{
return( 10 );
}
else
{
if(!OppPosKnown || !fLessRestrictiveRoaming)
{
return( 20 );
}
else
{
//return( 40 );
return( MAX_ROAMING_RANGE );
}
}// from nextPatrolGrid, not whereIWas
case FARPATROL: if (pSoldier->aiData.bAlertStatus < STATUS_RED)
{
return( 15 );
}
else
{
if(!OppPosKnown || !fLessRestrictiveRoaming)
{
return( 30 );
}
else
{
return( MAX_ROAMING_RANGE );
}
}
case ONCALL: if (pSoldier->aiData.bAlertStatus < STATUS_RED)
{
@@ -2298,7 +2356,15 @@ INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT32 * pusFromGridNo)
}
else
{
return( 30 );
if(!OppPosKnown || !fLessRestrictiveRoaming)
{
return( 30 );
}
else
{
//return(50);
return( MAX_ROAMING_RANGE );
}
}
case SEEKENEMY: *pusFromGridNo = pSoldier->sGridNo; // from current position!
return(MAX_ROAMING_RANGE);
+1 -1
View File
@@ -349,7 +349,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
continue; // next opponent
// calculate chance to REALLY hit: shoot accurately AND get past cover
ubChanceToReallyHit = (ubBestChanceToHit * ubChanceToGetThrough) / 100;
ubChanceToReallyHit = (UINT8)ceil((ubBestChanceToHit * ubChanceToGetThrough) / 100.0f);
// if we can't REALLY hit at all
if (ubChanceToReallyHit == 0)
+41 -15
View File
@@ -2100,7 +2100,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: soldier orders = %d",pSoldier->aiData.bOrders));
// if we have absolutely no action points, we can't do a thing under RED!
if (!pSoldier->bActionPoints)
if ( pSoldier->bActionPoints <= 0 ) //Action points can be negative
{
pSoldier->aiData.usActionData = NOWHERE;
return(AI_ACTION_NONE);
@@ -2163,7 +2163,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
}
}
if(WearGasMaskIfAvailable(pSoldier))//dnl ch40 200909
//Only put mask on in gas
if(bInGas && WearGasMaskIfAvailable(pSoldier))//dnl ch40 200909
bInGas = InGasOrSmoke(pSoldier, pSoldier->sGridNo);
////////////////////////////////////////////////////////////////////////////
@@ -2464,22 +2465,46 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
return(AI_ACTION_NONE);
}
}
}
}
//RELOADING
// WarmSteel - Because of suppression fire, we need enough ammo to even consider suppressing
// This means we need to reload. Also reload if we're just plainly low on bullets.
if(BestShot.bWeaponIn != NO_SLOT
&& ((pSoldier->inv[BestShot.bWeaponIn][0]->data.gun.ubGunShotsLeft < gGameExternalOptions.ubAISuppressionMinimumAmmo && GetMagSize(&pSoldier->inv[BestShot.bWeaponIn]) >= gGameExternalOptions.ubAISuppressionMinimumMagSize)
|| pSoldier->inv[BestShot.bWeaponIn][0]->data.gun.ubGunShotsLeft < (UINT8)(GetMagSize(&pSoldier->inv[BestShot.bWeaponIn]) / 4) ))
{
// HEADROCK HAM 5: Fixed an issue where no ammo was found, leading to a crash when overloading the
// inventory vector (bAmmoSlot = -1...)
INT8 bAmmoSlot = FindAmmoToReload( pSoldier, BestShot.bWeaponIn, NO_SLOT );
if (bAmmoSlot > -1)
{
OBJECTTYPE * pAmmo = &(pSoldier->inv[bAmmoSlot]);
if((*pAmmo)[0]->data.ubShotsLeft > pSoldier->inv[BestShot.bWeaponIn][0]->data.gun.ubGunShotsLeft && GetAPsToReloadGunWithAmmo( pSoldier, &(pSoldier->inv[BestShot.bWeaponIn]), pAmmo ) <= (INT16)pSoldier->bActionPoints)
{
pSoldier->aiData.usActionData = BestShot.bWeaponIn;
return AI_ACTION_RELOAD_GUN;
}
}
}
//SUPPRESSION FIRE
CheckIfShotPossible(pSoldier,&BestShot,TRUE);
CheckIfShotPossible(pSoldier,&BestShot,TRUE); //WarmSteel - No longer returns 0 when there IS actually a chance to hit.
//must have a small chance to hit and the opponent must be on the ground (can't suppress guys on the roof)
// HEADROCK HAM BETA2.4: Adjusted this for a random chance to suppress regardless of chance. This augments
// current revamp of suppression fire.
BOOLEAN fEnableAIAutofire = FALSE;
// CHRISL: Changed from a simple flag to two externalized values for more modder control over AI suppression
if ( BestShot.bWeaponIn != -1 && (GetMagSize(&pSoldier->inv[BestShot.bWeaponIn]) >= gGameExternalOptions.ubAISuppressionMinimumMagSize && pSoldier->inv[BestShot.bWeaponIn][0]->data.gun.ubGunShotsLeft >= gGameExternalOptions.ubAISuppressionMinimumAmmo) && ( ( BestShot.ubPossible && BestShot.ubChanceToReallyHit < 50 ) || (BestShot.ubPossible && BestShot.ubChanceToReallyHit < (INT16)PreRandom(100)) && Menptr[BestShot.ubOpponent].pathing.bLevel == 0 && pSoldier->aiData.bOrders != SNIPER ))
fEnableAIAutofire = TRUE;
if (fEnableAIAutofire)
// WarmSteel - Don't *always* try to suppress when under 50 CTH
if ( BestShot.bWeaponIn != -1
&& BestShot.ubPossible
&& GetMagSize(&pSoldier->inv[BestShot.bWeaponIn]) >= gGameExternalOptions.ubAISuppressionMinimumMagSize
&& pSoldier->inv[BestShot.bWeaponIn][0]->data.gun.ubGunShotsLeft >= gGameExternalOptions.ubAISuppressionMinimumAmmo
&& BestShot.ubChanceToReallyHit < (INT16)(PreRandom(100) - 50)
&& Menptr[BestShot.ubOpponent].pathing.bLevel == 0
&& pSoldier->aiData.bOrders != SNIPER )
{
// then do it!
@@ -2522,9 +2547,9 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
// Make sure we decided to fire at least one shot!
ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire );
// minimum 10 bullets
// minimum 5 bullets //WarmSteel: 5 bullets sounds reasonable, no?
// Hmmm, automatic suppression? Howcome we don't get this?
if (pSoldier->bDoAutofire >= 10 && pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs )
if (pSoldier->bDoAutofire >= 5 && pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs )
{
pSoldier->aiData.bAimTime = 0;
pSoldier->bDoBurst = 1;
@@ -3203,8 +3228,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
guiRedHelpTimeTotal += (uiEndTime - uiStartTime);
guiRedHelpCounter++;
#endif
if (!TileIsOutOfBounds(sClosestFriend))
//WarmSteel - Dont try if we're already quite close to our friend
if (!TileIsOutOfBounds(sClosestFriend) && PythSpacesAway(pSoldier->sGridNo, sClosestFriend) > pSoldier->GetMaxDistanceVisible(sClosestFriend, 0, CALC_FROM_ALL_DIRS ))
{
//////////////////////////////////////////////////////////////////////
// GO DIRECTLY TOWARDS CLOSEST FRIEND UNDER FIRE OR WHO LAST RADIOED
@@ -3900,8 +3925,9 @@ INT16 ubMinAPCost;
}
}
if(WearGasMaskIfAvailable(pSoldier))//dnl ch40 200909
bInGas = InGasOrSmoke(pSoldier, pSoldier->sGridNo);
//Only put mask on in gas
if(bInGas && WearGasMaskIfAvailable(pSoldier))//dnl ch40 200909
bInGas = InGasOrSmoke(pSoldier, pSoldier->sGridNo);
////////////////////////////////////////////////////////////////////////////
// IF GASSED, OR REALLY TIRED (ON THE VERGE OF COLLAPSING), TRY TO RUN AWAY
+13 -2
View File
@@ -651,7 +651,8 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// HEADROCK HAM 3.6: This doesn't take into account the 100AP system. Adjusting.
// Please note, I used a calculation that may have a better representation in some global variable.
//iMaxMoveTilesLeft = __max( 0, pSoldier->bActionPoints - MinAPsToStartMovement( pSoldier, usMovementMode ) );
iMaxMoveTilesLeft = __max( 0, (pSoldier->bActionPoints - MinAPsToStartMovement( pSoldier, usMovementMode ) / (APBPConstants[AP_MAXIMUM]/25)) );
// WarmSteel - Bugfix: wrong parentheses
iMaxMoveTilesLeft = __max( 0, (pSoldier->bActionPoints - MinAPsToStartMovement( pSoldier, usMovementMode )) / (APBPConstants[AP_MAXIMUM] / 25) );
//NumMessage("In BLACK, maximum tiles to move left = ",maxMoveTilesLeft);
@@ -799,7 +800,17 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
//PopMessage(tempstr);
}
iCurrentCoverValue -= (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
// reduce cover for each person adjacent to this gridno who is on our team,
// by 10% (so locations next to several people will be very much frowned upon
if ( iCurrentCoverValue >= 0 )
{
iCurrentCoverValue -= (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
}
else
{
// when negative, must add a negative to decrease the total
iCurrentCoverValue += (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
}
#ifdef DEBUGCOVER
// AINumMessage("Search Range = ",iSearchRange);
+2
View File
@@ -98,6 +98,8 @@ typedef enum
AI_ACTION_OFFER_SURRENDER, // offer surrender to the player
AI_ACTION_RAISE_GUN,
AI_ACTION_STEAL_MOVE, // added by SANDRO
AI_ACTION_RELOAD_GUN,
} ActionType;