From f05cdc328674807dfa86a5fd14236fb2949a6c4f Mon Sep 17 00:00:00 2001 From: silversurfer Date: Sat, 18 Oct 2014 15:26:03 +0000 Subject: [PATCH] Fix: Improved the fix for militia manning tanks in revision 7557. Tank slots are not made invalid anymore. Instead the placement body type will be converted to a normal militia body and moved to a free slot next to the tank. There is a new function "FindNearestPassableSpot" for finding an accessible tile next to a starting grid. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7588 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Tactical/Soldier Init List.cpp | 28 +++++++++++++++++++-------- TacticalAI/FindLocations.cpp | 35 ++++++++++++++++++++++++++++++++++ TacticalAI/ai.h | 1 + 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/Tactical/Soldier Init List.cpp b/Tactical/Soldier Init List.cpp index 8f1f9586..9f9ae4ba 100644 --- a/Tactical/Soldier Init List.cpp +++ b/Tactical/Soldier Init List.cpp @@ -1476,13 +1476,6 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl if( curr->pBasicPlacement->bTeam == ENEMY_TEAM || curr->pBasicPlacement->bTeam == MILITIA_TEAM ) { - // silversurfer: Militia is not supposed to reuse tanks, especially enemy tanks that have been destroyed in combat. - // The player would get free tanks to drive around with. Not good... - // Set the SoldierClass to None so this spot is no longer considered. We do not want to put militia here because it could get stuck in the tank body. - if( curr->pDetailedPlacement ) - if( curr->pDetailedPlacement->bBodyType == TANK_NE || curr->pDetailedPlacement->bBodyType == TANK_NW ) - curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_NONE; - //Matching team (kindof), now check the soldier class... if( ubNumElites && curr->pBasicPlacement->ubSoldierClass == SOLDIER_CLASS_ELITE ) { @@ -1507,6 +1500,16 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl curr->pBasicPlacement->bTeam = MILITIA_TEAM; curr->pBasicPlacement->bOrders = STATIONARY; curr->pBasicPlacement->bAttitude = (INT8) Random( MAXATTITUDES ); + // silversurfer: Replace body type. Militia tanks are not allowed. + if( curr->pDetailedPlacement->bBodyType == TANK_NE || curr->pDetailedPlacement->bBodyType == TANK_NW + || curr->pBasicPlacement->bBodyType == TANK_NE || curr->pBasicPlacement->bBodyType == TANK_NW ) + { + curr->pBasicPlacement->bBodyType = PreRandom( REGFEMALE + 1 ); + // check for better spot next to the tank so the militia doesn't get stuck in the tank + INT32 iNewSpot = FindNearestPassableSpot( curr->pBasicPlacement->usStartingGridNo ); + if( iNewSpot != NOWHERE) + curr->pBasicPlacement->usStartingGridNo = iNewSpot; + } if( curr->pDetailedPlacement ) { //delete the detailed placement information. delete( curr->pDetailedPlacement ); @@ -1635,7 +1638,7 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl curr = gSoldierInitHead; while( curr && ubFreeSlots && ubMaxNum ) { - if( !curr->pSoldier && (curr->pBasicPlacement->bTeam == ENEMY_TEAM || curr->pBasicPlacement->bTeam == MILITIA_TEAM) && curr->pBasicPlacement->ubSoldierClass != SOLDIER_CLASS_NONE ) + if( !curr->pSoldier && (curr->pBasicPlacement->bTeam == ENEMY_TEAM || curr->pBasicPlacement->bTeam == MILITIA_TEAM) ) { //Randomly determine if we will use this slot; the more available slots in proportion to //the number of enemies, the lower the chance of accepting the slot. @@ -1663,6 +1666,15 @@ void AddSoldierInitListMilitia( UINT8 ubNumGreen, UINT8 ubNumRegs, UINT8 ubNumEl curr->pBasicPlacement->bTeam = MILITIA_TEAM; curr->pBasicPlacement->bOrders = STATIONARY; curr->pBasicPlacement->bAttitude = (INT8) Random( MAXATTITUDES ); + // silversurfer: Replace body type. Militia tanks are not allowed. + if( curr->pBasicPlacement->bBodyType == TANK_NE || curr->pBasicPlacement->bBodyType == TANK_NW ) + { + curr->pBasicPlacement->bBodyType = PreRandom( REGFEMALE + 1 ); + // check for better spot next to the tank so the militia doesn't get stuck in the tank + INT32 iNewSpot = FindNearestPassableSpot( curr->pBasicPlacement->usStartingGridNo ); + if( iNewSpot != NOWHERE) + curr->pBasicPlacement->usStartingGridNo = iNewSpot; + } if( curr->pDetailedPlacement ) { //delete the detailed placement information. delete( curr->pDetailedPlacement ); diff --git a/TacticalAI/FindLocations.cpp b/TacticalAI/FindLocations.cpp index 44b44682..1eb9077d 100644 --- a/TacticalAI/FindLocations.cpp +++ b/TacticalAI/FindLocations.cpp @@ -2907,5 +2907,40 @@ INT8 FindDirectionForClimbing( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel return DIRECTION_IRRELEVANT; } +INT32 FindNearestPassableSpot( INT32 sGridNo, UINT8 usSearchRadius ) +{ + INT32 sNearestSpot = NOWHERE; + INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset; + INT32 sTestGridNo; + INT32 iDist, iClosestDist = 10; + // determine maximum horizontal limits + sMaxLeft = min( usSearchRadius, (sGridNo % MAXCOL)); + sMaxRight = min( usSearchRadius, MAXCOL - ((sGridNo % MAXCOL) + 1)); + // determine maximum vertical limits + sMaxUp = min( usSearchRadius, (sGridNo / MAXROW)); + sMaxDown = min( usSearchRadius, MAXROW - ((sGridNo / MAXROW) + 1)); + + // SET UP DOUBLE-LOOP TO STEP THROUGH POTENTIAL GRID #s + for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++) + { + for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++) + { + // calculate the next potential gridno + sTestGridNo = sGridNo + sXOffset + (MAXCOL * sYOffset); + // is this an empty tile (no structure on it) or is the structure passable? + if (gpWorldLevelData[sTestGridNo].pStructureHead == NULL || FindStructure( sTestGridNo, STRUCTURE_PASSABLE ) != NULL) + { + iDist = PythSpacesAway( sGridNo, sTestGridNo ); + if (iDist < iClosestDist) + { + iClosestDist = iDist; + sNearestSpot = sTestGridNo; + } + } + } + } + + return( sNearestSpot ); +} diff --git a/TacticalAI/ai.h b/TacticalAI/ai.h index 8e3a0053..5d3b668f 100644 --- a/TacticalAI/ai.h +++ b/TacticalAI/ai.h @@ -189,6 +189,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *pPercentBe INT32 FindClosestDoor( SOLDIERTYPE * pSoldier ); INT32 FindNearbyPointOnEdgeOfMap( SOLDIERTYPE * pSoldier, INT8 * pbDirection ); INT32 FindNearestEdgePoint( INT32 sGridNo ); +INT32 FindNearestPassableSpot( INT32 sGridNo, UINT8 usSearchRadius = 5 ); //Kris: Added these as I need specific searches on certain sides. enum