Moving Tanks Feature (by anv)

- feature: tanks can move around in tactical. Set with Tactical Gameplay Settings > ENEMY_TANKS_CAN_MOVE.
- feature: tanks can ignore chance to get through and destroy enemy cover even if it probably won't hit anyone behind it. Set with Tactical Gameplay Settings > ENEMY_TANKS_BLOW_OBSTACLES_UP.
- feature: tanks can use cannon even against single mercs and in perfect health. Set with Tactical Gameplay Settings > ENEMY_TANKS_DONT_SPARE_SHELLS.
- feature: tanks can noticed as soon as any part of it is visible. Set with Tactical Gameplay Settings > ENEMY_TANKS_ANY_PART_VISIBLE.
- feature: depending on game difficulty enemy patrols at game start can be randomly reinforced with tank. Set with Strategic Gameplay Settings > ARMY_USES_TANKS_IN_PATROLS.
- feature: depending on game difficulty enemy groups created during offensives can include tanks. Set with trategic Gameplay Settings > ARMY_USES_TANKS_IN_ATTACKS.
- feature: mercs in vehicles automatically rest their guns,
- fix: guns can be rested on vehicles,
- rewritten code to allow putting enemies inside vehicles,
- added missing descriptions for all vehicle options to INIEditorJA2Options.xml.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7277 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2014-06-18 18:10:07 +00:00
parent 33b3707381
commit 981c81b4b4
42 changed files with 971 additions and 372 deletions
+2
View File
@@ -316,9 +316,11 @@ void DoneFadeOutKilledQueen( void )
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumAdmins = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumTroops = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumElites = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumTanks = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubAdminsInBattle = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubTroopsInBattle = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubElitesInBattle = 0;
SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubTanksInBattle = 0;
// ATE: banish elliot... dead or alive
gMercProfiles[ ELLIOT ].sSectorX = 0;
+47 -15
View File
@@ -43,7 +43,7 @@ int gCivPreservedTempFileVersion[256];
BOOLEAN AddPlacementToWorld( SOLDIERINITNODE *pNode, GROUP *pGroup = NULL );
BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures );
BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures, UINT8 *pubNumTanks );
BOOLEAN gfRestoringEnemySoldiersFromTempFile = FALSE;
BOOLEAN gfRestoringCiviliansFromTempFile = FALSE;
@@ -104,8 +104,8 @@ BOOLEAN LoadEnemySoldiersFromTempFile()
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0;
UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0, ubNumTanks = 0;
UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures, ubStrategicTanks;
gfRestoringEnemySoldiersFromTempFile = TRUE;
@@ -253,6 +253,7 @@ BOOLEAN LoadEnemySoldiersFromTempFile()
ubStrategicElites = pSector->ubNumElites;
ubStrategicTroops = pSector->ubNumTroops;
ubStrategicAdmins = pSector->ubNumAdmins;
ubStrategicTanks = pSector->ubNumTanks;
ubStrategicCreatures = pSector->ubNumCreatures;
}
else
@@ -260,7 +261,7 @@ BOOLEAN LoadEnemySoldiersFromTempFile()
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubStrategicCreatures = pSector->ubNumCreatures;
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites );
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites, &ubStrategicTanks );
}
for( i = 0; i < slots; i++ )
@@ -347,6 +348,16 @@ BOOLEAN LoadEnemySoldiersFromTempFile()
AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_TANK:
if( curr->pBasicPlacement->bBodyType == TANK_NE || curr->pBasicPlacement->bBodyType == TANK_NW )
{
ubNumTanks++;
if( ubNumTanks < ubStrategicTanks )
{
AddPlacementToWorld( curr );
}
}
break;
}
break;
}
@@ -374,12 +385,13 @@ BOOLEAN LoadEnemySoldiersFromTempFile()
}
//now add any extra enemies that have arrived since the temp file was made.
if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins )
if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins || ubStrategicTanks > ubNumTanks )
{
ubStrategicTroops = ( ubStrategicTroops > ubNumTroops ) ? ubStrategicTroops - ubNumTroops : 0;
ubStrategicElites = ( ubStrategicElites > ubNumElites ) ? ubStrategicElites - ubNumElites : 0;
ubStrategicAdmins = ( ubStrategicAdmins > ubNumAdmins ) ? ubStrategicAdmins - ubNumAdmins : 0;
AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites );
ubStrategicTanks = ( ubStrategicTanks > ubNumTanks ) ? ubStrategicTanks - ubNumTanks : 0;
AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites, ubStrategicTanks );
}
if( ubStrategicCreatures > ubNumCreatures )
{
@@ -662,8 +674,8 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
#endif
INT8 bSectorZ;
UINT8 ubSectorID;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0;
UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures;
UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0, ubNumTanks = 0;
UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures, ubStrategicTanks;
gfRestoringEnemySoldiersFromTempFile = TRUE;
@@ -702,16 +714,17 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
ubNumElites = pSector->ubNumElites;
ubNumTroops = pSector->ubNumTroops;
ubNumAdmins = pSector->ubNumAdmins;
ubNumTanks = pSector->ubNumTanks;
ubNumCreatures = pSector->ubNumCreatures;
}
if( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
{
// Get the number of enemies form the temp file
CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( &ubStrategicElites, &ubStrategicTroops, &ubStrategicAdmins, &ubStrategicCreatures );
CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( &ubStrategicElites, &ubStrategicTroops, &ubStrategicAdmins, &ubStrategicCreatures, &ubStrategicTanks );
//If any of the counts differ from what is in memory
if( ubStrategicElites != ubNumElites || ubStrategicTroops != ubNumTroops || ubStrategicAdmins != ubNumAdmins || ubStrategicCreatures != ubNumCreatures )
if( ubStrategicElites != ubNumElites || ubStrategicTroops != ubNumTroops || ubStrategicAdmins != ubNumAdmins || ubStrategicCreatures != ubNumCreatures || ubStrategicTanks != ubNumTanks )
{
//remove the file
RemoveEnemySoldierTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
@@ -720,7 +733,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
}
//reset
ubNumElites = ubNumTroops = ubNumAdmins = ubNumCreatures = 0;
ubNumElites = ubNumTroops = ubNumAdmins = ubNumCreatures = ubNumTanks = 0;
//Open the file for reading
@@ -860,6 +873,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
ubStrategicElites = pSector->ubNumElites;
ubStrategicTroops = pSector->ubNumTroops;
ubStrategicAdmins = pSector->ubNumAdmins;
ubStrategicTanks = pSector->ubNumTanks;
ubStrategicCreatures = pSector->ubNumCreatures;
}
else
@@ -867,7 +881,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubStrategicCreatures = pSector->ubNumCreatures;
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites );
GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites, &ubStrategicTanks );
}
for( i = 0; i < slots; i++ )
@@ -944,6 +958,16 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
//def: AddPlacementToWorld( curr );
}
break;
case SOLDIER_CLASS_TANK:
if( curr->pBasicPlacement->bBodyType == TANK_NE || curr->pBasicPlacement->bBodyType == TANK_NW )
{
ubNumTanks++;
if( ubNumTanks <= ubStrategicTanks )
{
//def: AddPlacementToWorld( curr );
}
}
break;
}
break;
}
@@ -969,12 +993,13 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile()
}
//now add any extra enemies that have arrived since the temp file was made.
if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins )
if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins || ubStrategicTanks > ubNumTanks )
{
ubStrategicTroops = ( ubStrategicTroops > ubNumTroops ) ? ubStrategicTroops - ubNumTroops : 0;
ubStrategicElites = ( ubStrategicElites > ubNumElites ) ? ubStrategicElites - ubNumElites : 0;
ubStrategicAdmins = ( ubStrategicAdmins > ubNumAdmins ) ? ubStrategicAdmins - ubNumAdmins : 0;
AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites );
ubStrategicTanks = ( ubStrategicTanks > ubNumTanks ) ? ubStrategicTanks - ubNumTanks : 0;
AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites, ubStrategicTanks );
}
if( ubStrategicCreatures > ubNumCreatures )
{
@@ -1567,7 +1592,7 @@ BOOLEAN NewWayOfSavingEnemyAndCivliansToTempFile( INT16 sSectorX, INT16 sSectorY
BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures )
BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures, UINT8 *pubNumTanks )
{
// SOLDIERINITNODE *curr;
SOLDIERCREATE_STRUCT tempDetailedPlacement;
@@ -1592,6 +1617,7 @@ BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile(
*pubNumElites = 0;
*pubNumRegulars = 0;
*pubNumAdmins = 0;
*pubNumTanks = 0;
*pubNumCreatures = 0;
@@ -1758,6 +1784,12 @@ BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile(
case SOLDIER_CLASS_CREATURE:
(*pubNumCreatures)++;
break;
case SOLDIER_CLASS_TANK:
if( tempDetailedPlacement.bBodyType == TANK_NE || tempDetailedPlacement.bBodyType == TANK_NW )
{
(*pubNumTanks)++;
}
break;
}
/*
while( curr )
+1 -1
View File
@@ -259,7 +259,7 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8
}
Assert( ( bSoldierClass >= SOLDIER_CLASS_NONE ) && ( bSoldierClass <= SOLDIER_CLASS_ELITE_MILITIA ) );
Assert( ( bSoldierClass >= SOLDIER_CLASS_NONE ) && ( bSoldierClass <= SOLDIER_CLASS_ELITE_MILITIA ) || bSoldierClass == SOLDIER_CLASS_TANK );
Assert( ( bEquipmentRating >= 0 ) && ( bEquipmentRating <= 4 ) );
+1 -1
View File
@@ -2329,7 +2329,7 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE
// anv: special check for vehicles - since they're no longer transparent, we need to check for visibility
// of all substructures, also vehicle will be noticed even if just part of it is sticking around the corner
if( pEndSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && !TANK( pEndSoldier ) )
if( pEndSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && ( !TANK( pEndSoldier ) || gGameExternalOptions.fEnemyTanksAnyPartVisible ) )
{
STRUCTURE *pBase = pEndSoldier->pLevelNode->pStructureData;
if( pBase == NULL )
+4 -4
View File
@@ -6950,16 +6950,16 @@ void RemoveStaticEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
{
SECTORINFO *pSectorInfo = &(SectorInfo[SECTOR( sMapX, sMapY )]);
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = pSectorInfo->ubNumTanks = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = pSectorInfo->ubTanksInBattle = 0;
}
else
{
UNDERGROUND_SECTORINFO *pSectorInfo;
pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ );
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0;
pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = pSectorInfo->ubNumTanks = 0;
pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = pSectorInfo->ubTanksInBattle = 0;
}
}
+1 -1
View File
@@ -2610,7 +2610,7 @@ INT16 MinPtsToMove(SOLDIERTYPE *pSoldier)
INT16 sCost;
INT32 sGridNo;
if ( TANK( pSoldier ) )
if ( TANK( pSoldier ) && !gGameExternalOptions.fEnemyTanksCanMoveInTactical )
{
return(sLowest);//dnl ch64 290813 100AP made INT8 return obsolete
}
+21 -2
View File
@@ -14228,6 +14228,15 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void )
if ( TileIsOutOfBounds(this->sGridNo) )
return( FALSE );
// anv: passengers who can shoot can rest their guns
if ( this->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) )
{
if( !gNewVehicle[pVehicleList[this->iVehicleId].ubVehicleType].VehicleSeats[GetSeatIndexFromSoldier(this)].fBlockedShots )
return( TRUE );
else
return( FALSE );
}
// we determine the height of the next tile in our direction. Because of the way structures are handled, we sometimes have to take the very tile we're occupying right now
INT32 nextGridNoinSight = this->sGridNo;
if ( this->ubDirection == NORTH || this->ubDirection == SOUTHWEST || this->ubDirection == WEST || this->ubDirection == NORTHWEST )
@@ -14258,8 +14267,13 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void )
{
SOLDIERTYPE* pSoldier = MercPtrs[ usPersonID ];
// anv: vehicles don't mind
if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
applybipod = TRUE;
}
// if the other person is an ally and prone
if ( this->bSide == pSoldier->bSide && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE )
else if ( this->bSide == pSoldier->bSide && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE )
{
// if we are facing the other guy in a 90 degree angle, we can mount our gun on his back
// Once merc's relationship allows angering mercs through actions of others, add a penalty here
@@ -14324,8 +14338,13 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void )
{
SOLDIERTYPE* pSoldier = MercPtrs[usPersonID];
// anv: vehicles don't mind
if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
applybipod = TRUE;
}
// if the other person is an ally and prone
if ( this->bSide == pSoldier->bSide && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH )
else if ( this->bSide == pSoldier->bSide && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH )
{
applybipod = TRUE;
+1
View File
@@ -329,6 +329,7 @@ enum
SOLDIER_CLASS_CREATURE,
SOLDIER_CLASS_MINER,
SOLDIER_CLASS_ZOMBIE,
SOLDIER_CLASS_TANK,
SOLDIER_CLASS_MAX,
};
+84
View File
@@ -2430,6 +2430,10 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
}
break;
case SOLDIER_CLASS_TANK:
pp->bExpLevel = bp->bRelativeAttributeLevel;
break;
default:
pp->bExpLevel = bp->bRelativeAttributeLevel; //avg 2 (1-4)
ubSoldierClass = SOLDIER_CLASS_NONE;
@@ -3033,6 +3037,86 @@ SOLDIERTYPE* TacticalCreateEliteEnemy()
return( pSoldier );
}
//USED BY STRATEGIC AI and AUTORESOLVE
SOLDIERTYPE* TacticalCreateEnemyTank()
{
BASIC_SOLDIERCREATE_STRUCT bp;
SOLDIERCREATE_STRUCT pp;
UINT8 ubID;
SOLDIERTYPE * pSoldier;
if( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI )
{
pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ELITE );
if( pSoldier ) return pSoldier;
}
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ELITE );
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ELITE );
bp.bTeam = ENEMY_TEAM;
bp.bOrders = SEEKENEMY;
bp.bAttitude = (INT8) Random( MAXATTITUDES );
bp.bBodyType = TANK_NW;
bp.ubSoldierClass = SOLDIER_CLASS_TANK;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
//SPECIAL! Certain events in the game can cause profiled NPCs to become enemies. The two cases are
//adding Mike and Iggy. We will only add one NPC in any given combat and the conditions for setting
//the associated facts are done elsewhere. There is also another place where NPCs can get added, which
//is in AddPlacementToWorld() used for inserting defensive enemies.
//NOTE: We don't want to add Mike or Iggy if this is being called from autoresolve!
OkayToUpgradeEliteToSpecialProfiledEnemy( &pp );
pSoldier = TacticalCreateSoldier( &pp, &ubID );
if ( pSoldier )
{
// send soldier to centre of map, roughly
pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS);
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
}
return( pSoldier );
}
//USED BY STRATEGIC AI and AUTORESOLVE
// should to be succeeded by TacticalCreateArmyTroop/EliteEnemy and AddSoldierToVehicle
SOLDIERTYPE* TacticalCreateJeep()
{
BASIC_SOLDIERCREATE_STRUCT bp;
SOLDIERCREATE_STRUCT pp;
UINT8 ubID;
SOLDIERTYPE * pSoldier;
SOLDIERTYPE * pDriver;
if( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI )
{
pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ELITE );
if( pSoldier ) return pSoldier;
}
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ELITE );
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ELITE );
bp.bTeam = CIV_TEAM;
bp.bOrders = STATIONARY;
bp.bAttitude = (INT8) Random( MAXATTITUDES );
bp.bBodyType = JEEP;
bp.ubSoldierClass = SOLDIER_CLASS_NONE;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
pp.ubProfile = 199;
pSoldier = TacticalCreateSoldier( &pp, &ubID );
if ( pSoldier )
{
// send soldier to centre of map, roughly
pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS);
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
}
return( pSoldier );
}
#ifdef ENABLE_ZOMBIES
//USED BY STRATEGIC AI and AUTORESOLVE
SOLDIERTYPE* TacticalCreateZombie()
+2
View File
@@ -425,6 +425,8 @@ SOLDIERTYPE* TacticalCreateArmyTroop();
#endif
SOLDIERTYPE* TacticalCreateMilitia( UINT8 ubMilitiaClass, INT16 sX, INT16 sY ); // Flugente: added sector coordinates
SOLDIERTYPE* TacticalCreateCreature( INT8 bCreatureBodyType );
SOLDIERTYPE* TacticalCreateEnemyTank();
SOLDIERTYPE* TacticalCreateJeep();
// Flugente: assassins are elite soldiers of the civ team that go hostile on a certain event, otherwise they just blend in
SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype);
+54 -3
View File
@@ -976,7 +976,7 @@ UINT8 AddSoldierInitListTeamToWorld( INT8 bTeam, UINT8 ubMaxNum )
return ubNumAdded;
}
void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite )
void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite, UINT8 ubTotalTanks )
{
SOLDIERINITNODE *mark;
SOLDIERINITNODE *curr;
@@ -985,6 +985,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
UINT8 ubElitePDSlots = 0, ubEliteDSlots = 0, ubElitePSlots = 0, ubEliteBSlots = 0;
UINT8 ubTroopPDSlots = 0, ubTroopDSlots = 0, ubTroopPSlots = 0, ubTroopBSlots = 0;
UINT8 ubAdminPDSlots = 0, ubAdminDSlots = 0, ubAdminPSlots = 0, ubAdminBSlots = 0;
UINT8 ubTankPDSlots = 0, ubTankDSlots = 0, ubTankPSlots = 0, ubTankBSlots = 0;
UINT8 ubFreeSlots;
UINT8 *pCurrSlots=NULL;
UINT8 *pCurrTotal=NULL;
@@ -1002,7 +1003,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
//of each type of enemy may not be the same. Elites will choose the best placements, then army, then
//administrators.
ubMaxNum = ubTotalAdmin + ubTotalTroops + ubTotalElite;
ubMaxNum = ubTotalAdmin + ubTotalTroops + ubTotalElite + ubTotalTanks;
AssertLE (ubMaxNum, gGameExternalOptions.ubGameMaximumNumberOfEnemies);
@@ -1052,6 +1053,19 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
else
ubTroopBSlots++;
break;
case SOLDIER_CLASS_TANK:
if( curr->pDetailedPlacement->bBodyType == TANK_NW ||curr->pDetailedPlacement->bBodyType == TANK_NE )
{
if( curr->pBasicPlacement->fPriorityExistance && curr->pDetailedPlacement )
ubTankPDSlots++;
else if( curr->pBasicPlacement->fPriorityExistance )
ubTankPSlots++;
else if( curr->pDetailedPlacement )
ubTankDSlots++;
else
ubTankBSlots++;
}
break;
}
}
curr = curr->next;
@@ -1060,7 +1074,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
//ADD PLACEMENTS WITH PRIORITY EXISTANCE WITH DETAILED PLACEMENT INFORMATION FIRST
//we now have the numbers of available slots for each soldier class, so loop through three times
//and randomly choose some (or all) of the matching slots to fill. This is done randomly.
for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY; ubCurrClass++ )
for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY + 1; ubCurrClass++ )
{
//First, prepare the counters.
switch( ubCurrClass )
@@ -1077,6 +1091,11 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
pCurrSlots = &ubTroopPDSlots;
pCurrTotal = &ubTotalTroops;
break;
case SOLDIER_CLASS_ARMY + 1:// SOLDIER_CLASS_TANK
ubCurrClass = SOLDIER_CLASS_TANK;
pCurrSlots = &ubTankPDSlots;
pCurrTotal = &ubTotalTanks;
break;
}
//Now, loop through the priority existance and detailed placement section of the list.
curr = gSoldierInitHead;
@@ -1253,6 +1272,12 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_ADMINISTRATOR;
ubTotalAdmin--;
}
else if( iRandom < ubTotalElite + ubTotalTroops + ubTotalAdmin + ubTotalTanks )
{
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_TANK;
curr->pBasicPlacement->bBodyType = TANK_NW;
ubTotalTanks--;
}
else
Assert(0);
if( AddPlacementToWorld( curr ) )
@@ -1334,6 +1359,26 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
curr = curr->next;
}
// anv: try to place tanks outdoors
curr = gSoldierInitHead;
while( curr && ubFreeSlots && ubMaxNum )
{
if( !curr->pSoldier && curr->pBasicPlacement->bTeam == ENEMY_TEAM && ubTotalTanks && !GridNoIndoors( curr->pBasicPlacement->usStartingGridNo ))
{
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_TANK;
curr->pBasicPlacement->bBodyType = TANK_NW;
ubTotalTanks--;
if( AddPlacementToWorld( curr ) )
{
ubMaxNum--;
}
else
return;
ubFreeSlots--;
}
curr = curr->next;
}
//Now, loop through the entire list again, but for the last time. All enemies will be inserted now ignoring
//detailed placements and classes.
curr = gSoldierInitHead;
@@ -1362,6 +1407,12 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_ADMINISTRATOR;
ubTotalAdmin--;
}
else if( iRandom < ubTotalElite + ubTotalTroops + ubTotalAdmin + ubTotalTanks )
{
curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_TANK;
curr->pBasicPlacement->bBodyType = TANK_NW;
ubTotalTanks--;
}
else
Assert(0);
/* DISABLE THE OVERRIDE FOR NOW...
+1 -1
View File
@@ -40,7 +40,7 @@ void RemoveSoldierNodeFromInitList( SOLDIERINITNODE *pNode );
SOLDIERINITNODE* FindSoldierInitNodeWithID( UINT16 usID );
UINT8 AddSoldierInitListTeamToWorld( INT8 bTeam, UINT8 ubMaxNum );
void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite );
void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite, UINT8 ubTotalTanks );
void AddSoldierInitListCreatures( BOOLEAN fQueen, UINT8 ubNumLarvae, UINT8 ubNumInfants,
UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8 ubNumAdultMales,
UINT8 ubNumAdultFemales );
+36 -32
View File
@@ -510,24 +510,24 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex
if( pVehicleSoldier )
{
if ( pVehicleSoldier->bTeam != gbPlayerNum )
if ( pVehicleSoldier->bTeam != pSoldier->bTeam )
{
// Can we add a new vehicle
if( vCount >= gGameExternalOptions.ubGameMaximumNumberOfPlayerVehicles )
if( vCount >= gGameExternalOptions.ubGameMaximumNumberOfPlayerVehicles && pSoldier->bTeam == gbPlayerNum )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[VEHICLE_CAN_NOT_BE_ADDED] );
return( FALSE );
}
// Change sides...
pVehicleSoldier = ChangeSoldierTeam( pVehicleSoldier, gbPlayerNum );
pVehicleSoldier = ChangeSoldierTeam( pVehicleSoldier, pSoldier->bTeam );
// add it to mapscreen list
fReBuildCharacterList = TRUE;
}
}
// If vehicle is empty, add to unique squad now that it has somebody in it!
if ( GetNumberInVehicle( iId ) == 0 && pVehicleSoldier )
if ( GetNumberInVehicle( iId ) == 0 && pVehicleSoldier && pSoldier->bTeam == gbPlayerNum )
{
// 2 ) Add to unique squad...
AddCharacterToUniqueSquad( pVehicleSoldier );
@@ -536,17 +536,17 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex
// We have now a guy on a squad group, remove him!
RemovePlayerFromGroup( SquadMovementGroups[ pVehicleSoldier->bAssignment ], pVehicleSoldier );
// I really have vehicles.\
// ONLY add to vehicle group once!
if ( !DoesPlayerExistInPGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ) )
{
//NOW.. add guy to vehicle group....
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier );
}
else
{
pVehicleSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup;
}
// I really have vehicles.\
// ONLY add to vehicle group once!
if ( !DoesPlayerExistInPGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ) )
{
//NOW.. add guy to vehicle group....
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier );
}
else
{
pVehicleSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup;
}
}
// check if the grunt is already here
@@ -565,7 +565,7 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex
UnSetUIBusy( pSoldier->ubID );
// can't call SelectSoldier in mapscreen, that will initialize interface panels!!!
if ( guiCurrentScreen == GAME_SCREEN )
if ( guiCurrentScreen == GAME_SCREEN && pSoldier->bTeam == gbPlayerNum )
{
SelectSoldier( pVehicleSoldier->ubID, FALSE, TRUE );
}
@@ -611,11 +611,11 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex
}
// if in a squad, remove from squad, if not, check if in vehicle, if so remove, if not, then check if in mvt group..if so, move and destroy group
if( pSoldier->bAssignment < ON_DUTY )
if( pSoldier->bTeam == gbPlayerNum && pSoldier->bAssignment < ON_DUTY )
{
RemoveCharacterFromSquads( pSoldier );
}
else if( pSoldier->ubGroupID != 0 )
else if( pSoldier->bTeam == gbPlayerNum && pSoldier->ubGroupID != 0 )
{
// Flugente 2012-08-15: had very weird behaviour here. The outcommented code below failed, because the group size wasn't 0, which then threw an Assert()-error.
// This happened in r5468 when assinging a merc on repair duty to the truck, switching back and forth between the two
@@ -628,22 +628,26 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex
//pSoldier->ubGroupID = 0;
}
if( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier->iVehicleId != iId ) )
{
SetTimeOfAssignmentChangeForMerc( pSoldier );
}
// set thier assignment
ChangeSoldiersAssignment( pSoldier, VEHICLE );
// set vehicle id
pSoldier->iVehicleId = iId;
// if vehicle is part of mvt group, then add character to mvt group
if( pVehicleList[ iId ].ubMovementGroup != 0 )
if( pSoldier->bTeam == gbPlayerNum )
{
// add character
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pSoldier );
if( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier->iVehicleId != iId ) )
{
SetTimeOfAssignmentChangeForMerc( pSoldier );
}
// set thier assignment
ChangeSoldiersAssignment( pSoldier, VEHICLE );
// if vehicle is part of mvt group, then add character to mvt group
if( pVehicleList[ iId ].ubMovementGroup != 0 )
{
// add character
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pSoldier );
}
}
@@ -692,7 +696,7 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex
pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection );
// can't call SetCurrentSquad OR SelectSoldier in mapscreen, that will initialize interface panels!!!
if ( guiCurrentScreen == GAME_SCREEN )
if ( pSoldier->bTeam == gbPlayerNum && guiCurrentScreen == GAME_SCREEN )
{
SetCurrentSquad( pVehicleSoldier->bAssignment, TRUE );
}
@@ -1592,7 +1596,7 @@ SOLDIERTYPE *GetDriver( INT32 iID )
void SetDriver( INT32 iID, UINT8 ubID )
{
// anv: first make sure previous driver won't be driver anymore
if( pVehicleList[ iID ].ubDriver != NOBODY )
if( pVehicleList[ iID ].ubDriver != NOBODY && MercPtrs[ pVehicleList[ iID ].ubDriver ]->iVehicleId == iID )
{
if( MercPtrs[ pVehicleList[ iID ].ubDriver ] )
{