Files
source/Strategic/AI Viewer.cpp
T
Wanne e8027d6663 - Made the "Highspeed timer game loop (FF-MOD by tazpn)" optional, so we can decide if we like to build an executable with/without the highspeed timer
o See: builddefines.h: #define USE_HIGHSPEED_GAMELOOP_TIMER
o Gamers reported on the Bears Pit, that an executable compiled WITH the highspeed timer enabled makes the game unplayable slow in mapscreen mode when doing certain actions (repair, ...). That is the reason, why I made the compilation of the highspeed timer optional. Currently it is disabled.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5355 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2012-06-25 15:06:04 +00:00

2065 lines
65 KiB
C++

//Strategic AI Viewer
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "INIReader.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "types.h"
#include "english.h"
#include "Timer Control.h"
#include "vsurface.h"
#include "Button System.h"
#include "Font Control.h"
#include "Simple Render Utils.h"
#include "Editor Taskbar Utils.h"
#include "line.h"
#include "input.h"
#include "vobject_blitters.h"
#include "Text Input.h"
#include "mousesystem.h"
#include "strategicmap.h"
#include "Fileman.h"
#include "Map Information.h"
#include "render dirty.h"
#include "Game Clock.h"
#include "Campaign Types.h"
#include "Queen Command.h"
#include "Campaign Init.h"
#include "overhead.h"
#include "Strategic Movement.h"
#include "GameSettings.h"
#include "Game Event Hook.h"
#include "Creature Spreading.h"
#include "message.h"
#include "Game Init.h"
#include "Strategic AI.h"
#include "Campaign.h"
#include "Auto Resolve.h"
#include "Strategic Status.h"
#include "wordwrap.h"
#endif
#ifdef JA2BETAVERSION
#define VIEWER_LEFT 15
#define VIEWER_TOP 15
#define VIEWER_WIDTH 417
#define VIEWER_HEIGHT 353
#define VIEWER_CELLW 26
#define VIEWER_CELLH 22
#define VIEWER_RIGHT (VIEWER_LEFT+VIEWER_WIDTH)
#define VIEWER_BOTTOM (VIEWER_TOP+VIEWER_HEIGHT)
enum{
VIEWER_EXIT,
VIEWER_TIMEPANEL,
VIEWER_RESET,
RESET_EASY,
RESET_NORMAL,
RESET_HARD,
COMPRESSION0,
COMPRESSION5,
COMPRESSION15,
COMPRESSION60,
//COMPRESSION6H,
TEST_INCOMING_4SIDES,
START_CREATURE_QUEST,
SPREAD_CREATURES,
CREATURE_ATTACK,
VIEW_ENEMIES,
VIEW_CREATURES,
BASEMENT1_BTN,
BASEMENT2_BTN,
BASEMENT3_BTN,
RELOAD_SECTOR,
QUEEN_AWAKE_TOGGLE,
NUM_VIEWER_BUTTONS
};
enum
{
MOVE_RED_ICON,
MOVE_BLUE_ICON,
MOVE_YELLOW_ICON,
MOVE_GRAY_ICON,
MOVE_BURGUNDY_ICON,
MOVE_ORANGE_ICON,
MOVE_GREEN_ICON,
STOP_RED_ICON,
STOP_BLUE_ICON,
STOP_YELLOW_ICON,
STOP_GRAY_ICON,
STOP_BURGUNDY_ICON,
STOP_ORANGE_ICON,
STOP_GREEN_ICON,
REIN_RED_ICON,
REIN_BLUE_ICON,
REIN_YELLOW_ICON,
REIN_GRAY_ICON,
REIN_BURGUNDY_ICON,
REIN_ORANGE_ICON,
REIN_GREEN_ICON,
STAGE_RED_ICON,
STAGE_BLUE_ICON,
STAGE_YELLOW_ICON,
STAGE_GRAY_ICON,
STAGE_BURGUNDY_ICON,
STAGE_ORANGE_ICON,
STAGE_GREEN_ICON,
SAM_ICON,
MINING_ICON,
GROUP_ANCHOR,
};
enum
{
ICON_TYPE_PATROL,
ICON_TYPE_STOPPED,
ICON_TYPE_REINFORCEMENT,
ICON_TYPE_ASSAULT,
NUM_ICON_TYPES
};
enum
{
ICON_COLOR_RED,
ICON_COLOR_BLUE,
ICON_COLOR_YELLOW,
ICON_COLOR_GRAY,
ICON_COLOR_BURGUNDY,
ICON_COLOR_ORANGE,
ICON_COLOR_GREEN,
NUM_ICON_COLORS
};
void ClearViewerRegion( INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom );
void HandleViewerInput();
void RenderViewer();
void ViewerMapMoveCallback( MOUSE_REGION *reg, INT32 reason );
void ViewerMapClickCallback( MOUSE_REGION *reg, INT32 reason );
void ViewerExitCallback( GUI_BUTTON *btn, INT32 reason );
void Compression0Callback( GUI_BUTTON *btn, INT32 reason );
void Compression5Callback( GUI_BUTTON *btn, INT32 reason );
void Compression15Callback( GUI_BUTTON *btn, INT32 reason );
void Compression60Callback( GUI_BUTTON *btn, INT32 reason );
void Compression6HCallback( GUI_BUTTON *btn, INT32 reason );
void EasyCallback( GUI_BUTTON *btn, INT32 reason );
void NormalCallback( GUI_BUTTON *btn, INT32 reason );
void HardCallback( GUI_BUTTON *btn, INT32 reason );
void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason );
void StartCreatureQuestCallback( GUI_BUTTON *btn, INT32 reason );
void SpreadCreaturesCallback( GUI_BUTTON *btn, INT32 reason );
void CreatureAttackCallback( GUI_BUTTON *btn, INT32 reason );
void B1Callback( GUI_BUTTON *btn, INT32 reason );
void B2Callback( GUI_BUTTON *btn, INT32 reason );
void B3Callback( GUI_BUTTON *btn, INT32 reason );
void ReloadSectorCallback( GUI_BUTTON *btn, INT32 reason );
void ToggleQueenAwake( GUI_BUTTON *btn, INT32 reason );
void ViewEnemiesCallback( GUI_BUTTON *btn, INT32 reason );
void ViewCreaturesCallback( GUI_BUTTON *btn, INT32 reason );
void ExtractAndUpdatePopulations();
void PrintEnemyPopTable();
void PrintEnemiesKilledTable();
UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites );
void BlitGroupIcon( UINT8 ubIconType, UINT8 ubIconColor, UINT32 uiX, UINT32 uiY, HVOBJECT hVObject );
void PrintDetailedEnemiesInSectorInfo( INT32 iScreenX, INT32 iScreenY, UINT8 ubSectorX, UINT8 ubSectorY );
MOUSE_REGION ViewerRegion;
UINT32 guiMapGraphicID;
UINT32 guiMapIconsID;
BOOLEAN gfViewerEntry;
BOOLEAN gfExitViewer;
BOOLEAN gfRenderViewer;
BOOLEAN gfRenderMap;
BOOLEAN gfViewEnemies = TRUE;
INT8 gbViewLevel = 0;
UINT16 gusBlue;
UINT16 gusLtBlue;
UINT16 gusDkBlue;
INT16 gsAINumAdmins = -1;
INT16 gsAINumTroops = -1;
INT16 gsAINumElites = -1;
INT16 gsAINumCreatures = -1;
BOOLEAN gfOverrideSector = FALSE;
UINT32 guiLastTime;
INT32 giSaveTCMode; //time compression mode;
//The sector coordinates of the mouse position (yellow)
INT16 gsHiSectorX = 0;
INT16 gsHiSectorY = 0;
//The sector coordinates of the selected sector (red)
INT16 gsSelSectorX = 0, gsSelSectorY = 0;
INT32 iViewerButton[ NUM_VIEWER_BUTTONS ];
extern BOOLEAN gfQueenAIAwake;
extern INT32 giReinforcementPool;
extern UINT32 guiEventListCurrNodes, guiEventListPeekNodes;
extern INT32 giReinforcementPoints, giRequestPoints;
extern ARMY_COMPOSITION gArmyComp[ MAX_ARMY_COMPOSITIONS ];
extern GARRISON_GROUP *gGarrisonGroup;
extern INT32 giGarrisonArraySize;
extern void Ensure_RepairedGarrisonGroup( GARRISON_GROUP **ppGarrison, INT32 *pGarraySize );
CHAR16 gwGroupTypeString[ NUM_ENEMY_INTENTIONS ][ 20 ] =
{
L"RETREAT",
L"ASSAULT",
L"STAGING",
L"PATROL",
L"REINFORCE"
};
void StringFromValue( STR16 str, INT32 iValue, UINT32 uiMax )
{
if( iValue < 0 ) //a blank string is determined by a negative value.
str[0] = '\0';
else if( (UINT32)iValue > uiMax ) //higher than max attribute value, so convert it to the max.
swprintf( str, L"%d", uiMax );
else //this is a valid static value, so convert it to a string.
swprintf( str, L"%d", iValue );
}
BOOLEAN CreateAIViewer()
{
VOBJECT_DESC VObjectDesc;
CHAR16 str[6];
//Kaiden: Loading INI file to read Values...
// Here's another one of those INI reads
// killing the Map Editor>
//CIniReader iniReader("..\\Ja2_Options.ini");
//INT32 iMaxEnemyGroupSize = iniReader.ReadInteger("Options","MAX_STRATEGIC_TEAM_SIZE",20);
//Check to see if data exists.
if( !FileExists( "DevTools\\arulco.sti" ) ||
!FileExists( "DevTools\\icons.sti" ) ||
!FileExists( "DevTools\\SmCheckbox.sti" ) )
{
ScreenMsg( FONT_WHITE, MSG_BETAVERSION, L"AIViewer missing data. Aborted." );
gfExitViewer = FALSE;
gfViewerEntry = TRUE;
return FALSE;
}
DisableScrollMessages();
giSaveTCMode = giTimeCompressMode;
VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
sprintf( VObjectDesc.ImageFile, "DevTools\\arulco.sti" );
if( !AddVideoObject( &VObjectDesc, &guiMapGraphicID ) )
AssertMsg( 0, "Failed to load data\\DevTools\\arulco.sti" );
sprintf( VObjectDesc.ImageFile, "DevTools\\icons.sti" );
if( !AddVideoObject( &VObjectDesc, &guiMapIconsID ) )
AssertMsg( 0, "Failed to load data\\DevTools\\icons.sti" );
gfRenderViewer = TRUE;
//Create all of the buttons here
iViewerButton[ VIEWER_EXIT ] =
CreateTextButton(L"Exit", BLOCKFONT2, FONT_RED, FONT_BLACK, BUTTON_USE_DEFAULT,
585, 425, 50, 30, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
ViewerExitCallback );
iViewerButton[ VIEWER_TIMEPANEL ] =
CreateTextButton( WORLDTIMESTR, FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 3, 0, 88, 20, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, BUTTON_NO_CALLBACK,
BUTTON_NO_CALLBACK );
DisableButton( iViewerButton[ VIEWER_TIMEPANEL ] );
SpecifyDisabledButtonStyle( iViewerButton[ VIEWER_TIMEPANEL ], DISABLED_STYLE_NONE );
iViewerButton[ COMPRESSION0 ] =
CreateTextButton( L"0", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 3, 20, 17, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
Compression0Callback );
iViewerButton[ COMPRESSION5 ] =
CreateTextButton( L"5", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 20, 20, 17, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
Compression5Callback );
iViewerButton[ COMPRESSION15 ] =
CreateTextButton( L"15", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 37, 20, 18, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
Compression15Callback );
iViewerButton[ COMPRESSION60 ] =
CreateTextButton( L"60", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 55, 20, 18, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
Compression60Callback );
/*
iViewerButton[ COMPRESSION6H ] =
CreateTextButton( L"6H", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 73, 20, 18, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
Compression6HCallback );
*/
iViewerButton[ VIEWER_RESET ] =
CreateTextButton( L"Reset Enemies", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
526, 0, 114, 20, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, BUTTON_NO_CALLBACK,
BUTTON_NO_CALLBACK );
DisableButton( iViewerButton[ VIEWER_RESET ] );
SpecifyDisabledButtonStyle( iViewerButton[ VIEWER_RESET ], DISABLED_STYLE_NONE );
iViewerButton[ RESET_EASY ] =
CreateTextButton( L"Easy", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
526, 20, 35, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
EasyCallback );
iViewerButton[ RESET_NORMAL ] =
CreateTextButton( L"Normal", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
561, 20, 44, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
NormalCallback );
iViewerButton[ RESET_HARD ] =
CreateTextButton( L"Hard", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
605, 20, 35, 16, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
HardCallback );
iViewerButton[ TEST_INCOMING_4SIDES ] =
CreateTextButton( L"Incoming 4 Sides", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 20, 100, 120, 18, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
TestIncoming4SidesCallback );
iViewerButton[ START_CREATURE_QUEST ] =
CreateTextButton( L"Start Creature Quest", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 20, 125, 120, 18, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
StartCreatureQuestCallback );
iViewerButton[ SPREAD_CREATURES ] =
CreateTextButton( L"Spread Creatures", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 20, 150, 120, 18, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
SpreadCreaturesCallback );
iViewerButton[ CREATURE_ATTACK ] =
CreateTextButton( L"Creature Attack", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 20, 175, 120, 18, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
CreatureAttackCallback );
iViewerButton[ QUEEN_AWAKE_TOGGLE ] =
CreateCheckBoxButton( 104, VIEWER_BOTTOM + 22, "DevTools//SmCheckbox.sti", MSYS_PRIORITY_HIGH, ToggleQueenAwake );
if( gfQueenAIAwake )
{
ButtonList[ iViewerButton[ QUEEN_AWAKE_TOGGLE ] ]->uiFlags |= BUTTON_CLICKED_ON;
}
iViewerButton[ RELOAD_SECTOR ] =
CreateTextButton( L"Override Sector", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
10, VIEWER_BOTTOM + 5, 90, 18, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
ReloadSectorCallback );
iViewerButton[ VIEW_ENEMIES ] =
CreateTextButton( L"View Enemies", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 13, 40, 90, 20, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
ViewEnemiesCallback );
iViewerButton[ VIEW_CREATURES ] =
CreateTextButton( L"View Creatures", FONT12POINT1, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 103, 40, 90, 20, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
ViewCreaturesCallback );
iViewerButton[ BASEMENT1_BTN ] =
CreateTextButton( L"B1", FONT16ARIAL, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 58, 60, 30, 24, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
B1Callback );
iViewerButton[ BASEMENT2_BTN ] =
CreateTextButton( L"B2", FONT16ARIAL, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 88, 60, 30, 24, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
B2Callback );
iViewerButton[ BASEMENT3_BTN ] =
CreateTextButton( L"B3", FONT16ARIAL, FONT_BLACK, FONT_BLACK, BUTTON_USE_DEFAULT,
VIEWER_RIGHT + 118, 60, 30, 24, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK,
B3Callback );
if( gfViewEnemies )
ButtonList[ iViewerButton[ VIEW_ENEMIES ] ]->uiFlags |= BUTTON_CLICKED_ON;
else
ButtonList[ iViewerButton[ VIEW_CREATURES ] ]->uiFlags |= BUTTON_CLICKED_ON;
MSYS_DefineRegion( &ViewerRegion, VIEWER_LEFT, VIEWER_TOP, VIEWER_RIGHT, VIEWER_BOTTOM, MSYS_PRIORITY_HIGH, 0,
ViewerMapMoveCallback, ViewerMapClickCallback );
//Add the enemy population override fields
InitTextInputModeWithScheme( DEFAULT_SCHEME );
StringFromValue( str, gsAINumAdmins, gGameExternalOptions.iMaxEnemyGroupSize );
AddTextInputField( 10, VIEWER_BOTTOM + 30, 25, 15, MSYS_PRIORITY_NORMAL, str, 2, INPUTTYPE_NUMERICSTRICT );
StringFromValue( str, gsAINumTroops, gGameExternalOptions.iMaxEnemyGroupSize );
AddTextInputField( 10, VIEWER_BOTTOM + 50, 25, 15, MSYS_PRIORITY_NORMAL, str, 2, INPUTTYPE_NUMERICSTRICT );
StringFromValue( str, gsAINumElites, gGameExternalOptions.iMaxEnemyGroupSize );
AddTextInputField( 10, VIEWER_BOTTOM + 70, 25, 15, MSYS_PRIORITY_NORMAL, str, 2, INPUTTYPE_NUMERICSTRICT );
StringFromValue( str, gsAINumCreatures, gGameExternalOptions.iMaxEnemyGroupSize );
AddTextInputField( 10, VIEWER_BOTTOM + 90, 25, 15, MSYS_PRIORITY_NORMAL, str, 2, INPUTTYPE_NUMERICSTRICT );
//Press buttons in based on current settings
if (gGameOptions.ubDifficultyLevel >= DIF_LEVEL_EASY && gGameOptions.ubDifficultyLevel <= DIF_LEVEL_HARD)
ButtonList[ iViewerButton[ RESET_EASY + gGameOptions.ubDifficultyLevel - DIF_LEVEL_EASY ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ COMPRESSION0 ] ]->uiFlags |= BUTTON_CLICKED_ON;
if( !GamePaused() )
SetGameMinutesPerSecond( 0 );
ClearViewerRegion( 0, 0, 640, 480 );
return TRUE;
}
void DestroyAIViewer()
{
INT32 i;
gfExitViewer = FALSE;
gfViewerEntry = TRUE;
for( i = 0; i < NUM_VIEWER_BUTTONS; i++ )
{
RemoveButton( iViewerButton[ i ] );
}
DeleteVideoObjectFromIndex( guiMapGraphicID );
DeleteVideoObjectFromIndex( guiMapIconsID );
MSYS_RemoveRegion( &ViewerRegion );
KillTextInputMode();
SetGameTimeCompressionLevel( giSaveTCMode );
EnableScrollMessages();
}
void ClearViewerRegion( INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom )
{
ColorFillVideoSurfaceArea( ButtonDestBuffer, sLeft, sTop, sRight, sBottom, gusBlue );
InvalidateRegion( sLeft, sTop, sRight, sBottom );
if( !sLeft )
{
ColorFillVideoSurfaceArea( ButtonDestBuffer, 0, sTop, 1, sBottom, gusLtBlue );
sLeft++;
}
if( !sTop )
{
ColorFillVideoSurfaceArea( ButtonDestBuffer, sLeft, 0, sRight, 1, gusLtBlue );
sTop++;
}
if( sBottom == 480 )
ColorFillVideoSurfaceArea( ButtonDestBuffer, sLeft, 479, sRight, 480, gusDkBlue );
if( sRight == 640 )
ColorFillVideoSurfaceArea( ButtonDestBuffer, 639, sTop, 640, sBottom, gusDkBlue );
}
void RenderStationaryGroups()
{
HVOBJECT hVObject;
SECTORINFO *pSector;
INT32 x, y, xp, yp;
CHAR16 str[20];
INT32 iSector = 0;
UINT8 ubIconColor = 0;
UINT8 ubGroupSize = 0;
SetFont( FONT10ARIAL );
SetFontShadow( FONT_NEARBLACK );
GetVideoObject( &hVObject, guiMapIconsID );
Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */
//Render groups that are stationary...
for( y = 0; y < 16; y++ )
{
yp = VIEWER_TOP + VIEWER_CELLH * y + 1;
for( x = 0; x < 16; x++ )
{
SetFontForeground( FONT_YELLOW );
xp = VIEWER_LEFT + VIEWER_CELLW * x + 1;
pSector = &SectorInfo[ iSector ];
if( pSector->uiFlags & SF_MINING_SITE )
BltVideoObject( FRAME_BUFFER, hVObject, MINING_ICON, xp + 25, yp - 1, VO_BLT_SRCTRANSPARENCY, NULL );
if( pSector->uiFlags & SF_SAM_SITE )
BltVideoObject( FRAME_BUFFER, hVObject, SAM_ICON, xp + 20, yp + 4, VO_BLT_SRCTRANSPARENCY, NULL );
if( pSector->ubNumberOfCivsAtLevel[0] + pSector->ubNumberOfCivsAtLevel[1] + pSector->ubNumberOfCivsAtLevel[2] )
{
// show militia
ubIconColor = ICON_COLOR_BLUE;
ubGroupSize = pSector->ubNumberOfCivsAtLevel[0] + pSector->ubNumberOfCivsAtLevel[1] + pSector->ubNumberOfCivsAtLevel[2];
}
else
if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites )
{
// show enemies
ubIconColor = ChooseEnemyIconColor( pSector->ubNumAdmins, pSector->ubNumTroops, pSector->ubNumElites );
ubGroupSize = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites;
if( pSector->ubGarrisonID != NO_GARRISON )
{
if( gGarrisonGroup[ pSector->ubGarrisonID ].ubPendingGroupID )
{
if( GetJA2Clock() % 1000 < 333 )
{
SetFontForeground( FONT_LTRED );
}
}
}
else
{
if( GetJA2Clock() % 1000 < 333 )
{
SetFontForeground( FONT_LTKHAKI );
}
}
}
else
{
ubGroupSize = 0;
}
if ( ubGroupSize > 0 )
{
// draw the icon
BlitGroupIcon( ICON_TYPE_STOPPED, ubIconColor, xp, yp, hVObject );
//Print the group size
swprintf( str, L"%d", ubGroupSize );
mprintf( xp + 2, yp + 2, str );
}
iSector++;
}
}
}
void RenderMovingGroupsAndMercs()
{
GROUP *pGroup;
HVOBJECT hVObject;
INT32 x, y;
UINT8 ubNumTroops, ubNumAdmins, ubNumElites;
float ratio;
INT32 minX, maxX, minY, maxY;
UINT8 ubIconType;
UINT8 ubIconColor;
UINT8 ubFontColor;
SetFont( FONT10ARIAL );
SetFontShadow( FONT_NEARBLACK );
GetVideoObject( &hVObject, guiMapIconsID );
//Render groups that are moving...
pGroup = gpGroupList;
while( pGroup )
{
if( pGroup->ubGroupSize && !pGroup->fVehicle)
{
if( pGroup->uiTraverseTime )
{
// display how far along to the next sector they are
ratio = (pGroup->uiTraverseTime-pGroup->uiArrivalTime + GetWorldTotalMin())/(float)pGroup->uiTraverseTime;
minX = VIEWER_LEFT + VIEWER_CELLW * (pGroup->ubSectorX-1);
maxX = VIEWER_LEFT + VIEWER_CELLW * (pGroup->ubNextX-1);
x = (UINT32)(minX + ratio *(maxX-minX));
minY = VIEWER_TOP + VIEWER_CELLH * (pGroup->ubSectorY-1);
maxY = VIEWER_TOP + VIEWER_CELLH * (pGroup->ubNextY-1);
y = (UINT32)(minY + ratio *(maxY-minY));
}
else
{
x = VIEWER_LEFT + VIEWER_CELLW * (pGroup->ubSectorX-1);
y = VIEWER_TOP + VIEWER_CELLH * (pGroup->ubSectorY-1);
}
if( pGroup->fPlayer )
{
ubIconType = (UINT8) (( pGroup->uiTraverseTime ) ? ICON_TYPE_ASSAULT : ICON_TYPE_STOPPED);
ubIconColor = ICON_COLOR_GREEN;
ubFontColor = FONT_YELLOW;
}
else
{
//if the group was moving, then draw the anchor to visually indicate the sector of
//influence for enemy patrol groups.
if( pGroup->uiTraverseTime )
{
BltVideoObject( FRAME_BUFFER, hVObject, GROUP_ANCHOR, VIEWER_LEFT + VIEWER_CELLW * (pGroup->ubSectorX - 1), VIEWER_TOP + VIEWER_CELLH * (pGroup->ubSectorY - 1), VO_BLT_SRCTRANSPARENCY, NULL );
}
ubNumAdmins = pGroup->pEnemyGroup->ubNumAdmins;//+ pGroup->pEnemyGroup->ubAdminsInBattle;
ubNumTroops = pGroup->pEnemyGroup->ubNumTroops;//+ pGroup->pEnemyGroup->ubTroopsInBattle;
ubNumElites = pGroup->pEnemyGroup->ubNumElites;// + pGroup->pEnemyGroup->ubElitesInBattle;
// must have one of the three, already checked groupsize!
Assert( ubNumAdmins || ubNumTroops || ubNumElites );
//determine icon color
ubIconColor = ChooseEnemyIconColor( ubNumAdmins, ubNumTroops, ubNumElites );
// must have a valid intention
Assert( pGroup->pEnemyGroup->ubIntention < NUM_ENEMY_INTENTIONS );
// determine icon type - shows the groups intentions
switch ( pGroup->pEnemyGroup->ubIntention )
{
case REINFORCEMENTS: ubIconType = ICON_TYPE_REINFORCEMENT; ubFontColor = FONT_YELLOW; break;
case PATROL: ubIconType = ICON_TYPE_PATROL; ubFontColor = FONT_YELLOW; break;
case STAGING: ubIconType = ICON_TYPE_PATROL; ubFontColor = FONT_LTBLUE; break;
case PURSUIT: ubIconType = ICON_TYPE_ASSAULT; ubFontColor = FONT_YELLOW; break;
case ASSAULT: ubIconType = ICON_TYPE_ASSAULT; ubFontColor = FONT_LTBLUE; break;
default:
Assert(0);
return;
}
}
// draw the icon
BlitGroupIcon( ubIconType, ubIconColor, x, y, hVObject );
// set color
SetFontForeground( ubFontColor );
//Print the group size
if( pGroup->fPlayer && !pGroup->uiTraverseTime )
// stationary player - count all mercs there, not just the group
mprintf( x+11, y+11, L"%d", PlayerMercsInSector( pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ ) );
else
{
if( !pGroup->pWaypoints )
{
if( GetJA2Clock() % 1000 < 750 )
{
SetFontForeground( FONT_WHITE );
}
}
mprintf( x+7, y+7, L"%d", pGroup->ubGroupSize );
}
}
pGroup = pGroup->next;
}
}
void RenderInfoInSector()
{
UINT8 ubSectorX, ubSectorY;
UINT8 ubMercs=0, ubActive=0, ubUnconcious=0, ubCollapsed=0;
INT32 i, yp;
if( gfViewEnemies && !gbViewLevel )
{
RenderStationaryGroups();
RenderMovingGroupsAndMercs();
SetFontForeground( FONT_LTRED );
mprintf( 78, 358, L"%3d", giReinforcementPool );
//Render general enemy statistics
ClearViewerRegion( 105, VIEWER_BOTTOM + 10, 265, VIEWER_BOTTOM + 66 );
SetFontForeground( FONT_YELLOW );
mprintf( 105, VIEWER_BOTTOM + 10, L"GLOBAL INFO" );
SetFontForeground( FONT_GRAY2 );
mprintf( 118, VIEWER_BOTTOM + 24, L"Strategic AI Awake" );
mprintf( 105, VIEWER_BOTTOM + 36, L"Total Request Points: %d", giRequestPoints );
mprintf( 105, VIEWER_BOTTOM + 46, L"Total Reinforcement Points: %d", giReinforcementPoints );
mprintf( 105, VIEWER_BOTTOM + 56, L"Progress (Current/Highest): %d%%/%d%%", CurrentPlayerProgressPercentage(), HighestPlayerProgressPercentage() );
PrintEnemyPopTable();
PrintEnemiesKilledTable();
}
if( gsHiSectorX && gsHiSectorY && ( gsHiSectorX != gsSelSectorX || gsHiSectorY != gsSelSectorY ) )
{ //Render sector info for the hilighted sector
SetFontForeground( FONT_YELLOW );
ubSectorX = (UINT8)gsHiSectorX;
ubSectorY = (UINT8)gsHiSectorY;
}
else if( gsSelSectorX && gsSelSectorY )
{ //Render sector info for the selected sector
SetFontForeground( FONT_RED );
ubSectorX = (UINT8)gsSelSectorX;
ubSectorY = (UINT8)gsSelSectorY;
}
else
{
return;
}
//Count the number of mercs and their states (even for underground sectors)
for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
{
SOLDIERTYPE *pSoldier;
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive && pSoldier->sSectorX == ubSectorX && pSoldier->sSectorY == ubSectorY && pSoldier->bSectorZ == gbViewLevel )
{
if( pSoldier->stats.bLife )
{
ubMercs++;
if( pSoldier->stats.bLife >= OKLIFE )
{
if( pSoldier->bBreath < OKBREATH )
ubCollapsed++;
else
ubActive++;
}
else
ubUnconcious++;
}
}
}
yp = 375;
if( !gbViewLevel )
{
SECTORINFO *pSector;
GROUP *pGroup;
UINT8 ubNumAdmins=0, ubNumTroops=0, ubNumElites=0, ubAdminsInBattle=0, ubTroopsInBattle=0, ubElitesInBattle=0, ubNumGroups=0;
pSector = &SectorInfo[ SECTOR( ubSectorX, ubSectorY ) ];
//Now count the number of mobile groups in the sector.
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == ubSectorX && pGroup->ubSectorY == ubSectorY )
{
ubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
ubNumElites += pGroup->pEnemyGroup->ubNumElites;
ubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
ubTroopsInBattle += pGroup->pEnemyGroup->ubTroopsInBattle;
ubElitesInBattle += pGroup->pEnemyGroup->ubElitesInBattle;
ubAdminsInBattle += pGroup->pEnemyGroup->ubAdminsInBattle;
ubNumGroups++;
}
pGroup = pGroup->next;
}
ClearViewerRegion( 280, 375, 640, 480 );
mprintf( 280, yp, L"SECTOR INFO: %c%d (ID: %d)", ubSectorY + 'A' - 1, ubSectorX, SECTOR( ubSectorX, ubSectorY ) );
yp += 10;
SetFontForeground( FONT_LTGREEN );
mprintf( 280, yp, L"%d Player Mercs: (%d Active, %d Unconcious, %d Collapsed)",
ubMercs, ubActive, ubUnconcious, ubCollapsed );
yp += 10;
SetFontForeground( FONT_LTBLUE );
mprintf( 280, yp, L"Militia: (%d Green, %d Regular, %d Elite)",
pSector->ubNumberOfCivsAtLevel[0], pSector->ubNumberOfCivsAtLevel[1], pSector->ubNumberOfCivsAtLevel[2] );
yp += 10;
SetFontForeground( FONT_ORANGE );
mprintf( 280, yp, L"Garrison: (%d:%d Admins, %d:%d Troops, %d:%d Elites)",
pSector->ubAdminsInBattle, pSector->ubNumAdmins,
pSector->ubTroopsInBattle, pSector->ubNumTroops,
pSector->ubElitesInBattle, pSector->ubNumElites );
yp += 10;
mprintf( 280, yp, L"%d Groups: (%d:%d Admins, %d:%d Troops, %d:%d Elites)", ubNumGroups,
ubAdminsInBattle, ubNumAdmins,
ubTroopsInBattle, ubNumTroops,
ubElitesInBattle, ubNumElites );
yp += 10;
SetFontForeground( FONT_WHITE );
if( gfViewEnemies )
{
PrintDetailedEnemiesInSectorInfo( 280, yp, ubSectorX, ubSectorY );
yp += 10;
}
else
{
SetFontForeground( FONT_YELLOW );
mprintf( 280, yp, L"Monsters: (%d:%d)", pSector->ubCreaturesInBattle, pSector->ubNumCreatures );
yp += 10;
}
}
else
{
UNDERGROUND_SECTORINFO *pSector;
ClearViewerRegion( 280, 375, 640, 480 );
pSector = FindUnderGroundSector( ubSectorX, ubSectorY, gbViewLevel );
if( !pSector )
{
return;
}
mprintf( 280, yp, L"SECTOR INFO: %c%d_b%d", ubSectorY + 'A' - 1, ubSectorX, gbViewLevel );
yp += 10;
SetFontForeground( FONT_LTGREEN );
mprintf( 280, yp, L"%d Player Mercs: (%d Active, %d Unconcious, %d Collapsed)",
ubMercs, ubActive, ubUnconcious, ubCollapsed );
yp += 10;
SetFontForeground( FONT_YELLOW );
mprintf( 280, yp, L"Monsters: (%d:%d)", pSector->ubCreaturesInBattle, pSector->ubNumCreatures );
yp += 10;
if( pSector->uiFlags & SF_PENDING_ALTERNATE_MAP )
{
mprintf( 280, yp, L"SF_PENDING_ALTERNATE_MAP", pSector->ubCreaturesInBattle, pSector->ubNumCreatures );
yp += 10;
}
if( pSector->uiFlags & SF_USE_ALTERNATE_MAP )
{
mprintf( 280, yp, L"SF_USE_ALTERNATE_MAP", pSector->ubCreaturesInBattle, pSector->ubNumCreatures );
yp += 10;
}
}
}
void RenderViewer()
{
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES;
SGPRect ClipRect;
INT32 i, x, y, xp, yp;
if( gfRenderViewer )
{
ClearViewerRegion( VIEWER_LEFT, VIEWER_TOP, VIEWER_RIGHT, VIEWER_BOTTOM );
gfRenderViewer = FALSE;
gfRenderMap = TRUE;
for( i = 0; i < NUM_VIEWER_BUTTONS; i++ )
{
MarkAButtonDirty( iViewerButton[ i ] );
}
SetFont( FONT10ARIAL );
SetFontForeground( FONT_YELLOW );
SetFontShadow( FONT_NEARBLACK );
mprintf( 38, VIEWER_BOTTOM + 33, L"Admins" );
mprintf( 38, VIEWER_BOTTOM + 53, L"Troops" );
mprintf( 38, VIEWER_BOTTOM + 73, L"Elites" );
mprintf( 38, VIEWER_BOTTOM + 93, L"Creatures" );
}
if( gfRenderMap )
{
gfRenderMap = FALSE;
BltVideoObjectFromIndex( FRAME_BUFFER, guiMapGraphicID, 0, VIEWER_LEFT, VIEWER_TOP, VO_BLT_SRCTRANSPARENCY, NULL );
InvalidateRegion( VIEWER_LEFT, VIEWER_TOP, VIEWER_RIGHT, VIEWER_BOTTOM );
//Draw the coordinates
ClearViewerRegion( 0, 0, VIEWER_RIGHT, 14 );
ClearViewerRegion( 0, 0, 14, VIEWER_BOTTOM );
SetFont( FONT10ARIAL );
SetFontShadow( FONT_NEARBLACK );
for( y = 0; y < 16; y++ )
{
if( y+1 == gsSelSectorY )
SetFontForeground( FONT_RED );
else if( y+1 == gsHiSectorY )
SetFontForeground( FONT_YELLOW );
else
SetFontForeground( FONT_GRAY1 );
mprintf( VIEWER_LEFT-10, VIEWER_TOP+7+y*22, L"%c", 'A' + y );
}
for( x = 1; x <= 16; x++ )
{
CHAR16 str[3];
if( x == gsSelSectorX )
SetFontForeground( FONT_RED );
else if( x == gsHiSectorX )
SetFontForeground( FONT_YELLOW );
else
SetFontForeground( FONT_GRAY1 );
swprintf( str, L"%d", x );
mprintf( VIEWER_LEFT+x*26-(26+StringPixLength( str, FONT12POINT1 ))/2, VIEWER_TOP-12, str );
}
if( gbViewLevel )
{
UNDERGROUND_SECTORINFO *pUnder;
SetFont( FONT10ARIAL );
SetFontForeground( FONT_YELLOW );
SetFontShadow( FONT_NEARBLACK );
for( y = 0; y < 16; y++ )
{
ClipRect.iTop = VIEWER_TOP + y*VIEWER_CELLH;
ClipRect.iBottom = ClipRect.iTop + VIEWER_CELLH - 1;
for( x = 0; x < 16; x++ )
{
pUnder = FindUnderGroundSector( (INT16)(x + 1), (INT16)(y + 1), gbViewLevel );
if( pUnder )
{
xp = VIEWER_LEFT+x*VIEWER_CELLW+2;
yp = VIEWER_TOP+y*VIEWER_CELLH+2;
mprintf( xp, yp, L"%d", pUnder->ubNumCreatures );
}
else
{ //not found, so visually shade it darker.
pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
ClipRect.iLeft = VIEWER_LEFT + x*VIEWER_CELLW;
ClipRect.iRight = ClipRect.iLeft + VIEWER_CELLW - 1;
Blt16BPPBufferShadowRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect );
Blt16BPPBufferShadowRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect );
UnLockVideoSurface( FRAME_BUFFER );
}
}
}
}
RenderInfoInSector();
}
pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, 640, 480 );
//Render the grid for the sector if the mouse is over it (yellow).
if( gsHiSectorX > 0 )
{
x = VIEWER_LEFT + (gsHiSectorX-1) * 26;
y = VIEWER_TOP + (gsHiSectorY-1) * 22;
RectangleDraw( TRUE, x, y, x+26, y+22, Get16BPPColor( FROMRGB( 200, 200, 50 ) ), pDestBuf );
}
//Render the grid for the sector currently in focus (red).
if( gsSelSectorX > 0 )
{
x = VIEWER_LEFT + (gsSelSectorX-1) * 26 ;
y = VIEWER_TOP + (gsSelSectorY-1) * 22 ;
RectangleDraw( TRUE, x, y, x+26, y+22, Get16BPPColor( FROMRGB( 200, 50, 50 ) ), pDestBuf );
}
UnLockVideoSurface( FRAME_BUFFER );
}
void ViewerExitCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfExitViewer = TRUE;
}
}
void HandleViewerInput()
{
SECTORINFO *pSector;
InputAtom Event;
#ifdef USE_HIGHSPEED_GAMELOOP_TIMER
while( DequeueSpecificEvent(&Event, KEY_DOWN|KEY_UP) )
#else
while( DequeueEvent( &Event ) )
#endif
{
if( !HandleTextInput( &Event ) && Event.usEvent == KEY_DOWN )
{
switch( Event.usParam )
{
case ESC:
gfExitViewer = TRUE;
break;
case ENTER:
// this means GO! for doing overrides
ExtractAndUpdatePopulations();
break;
case 'x':
if( Event.usKeyState & ALT_DOWN )
{
gfExitViewer = TRUE;
gfProgramIsRunning = FALSE;
}
break;
case 'm':
//Kill all enemies and add militia
if( Event.usKeyState & ALT_DOWN )
{
pSector = NULL;
if( gsSelSectorX && gsSelSectorY )
{
pSector = &SectorInfo[ SECTOR( gsSelSectorX, gsSelSectorY ) ];
pSector->ubNumberOfCivsAtLevel[0] = 15;
pSector->ubNumberOfCivsAtLevel[1] = 4;
pSector->ubNumberOfCivsAtLevel[2] = 1;
gfRenderMap = TRUE;
EliminateAllEnemies( (UINT8)gsSelSectorX, (UINT8)gsSelSectorY );
}
else if( gsHiSectorX && gsHiSectorY )
{
pSector = &SectorInfo[ SECTOR( gsHiSectorX, gsHiSectorY ) ];
pSector->ubNumberOfCivsAtLevel[0] = 15;
pSector->ubNumberOfCivsAtLevel[1] = 4;
pSector->ubNumberOfCivsAtLevel[2] = 1;
gfRenderMap = TRUE;
EliminateAllEnemies( (UINT8)gsHiSectorX, (UINT8)gsHiSectorY );
}
}
break;
case 'o':
// kill all enemies!
if( Event.usKeyState & ALT_DOWN )
{
pSector = NULL;
if( gsSelSectorX && gsSelSectorY )
{
gfRenderMap = TRUE;
EliminateAllEnemies( (UINT8)gsSelSectorX, (UINT8)gsSelSectorY );
}
else if( gsHiSectorX && gsHiSectorY )
{
gfRenderMap = TRUE;
EliminateAllEnemies( (UINT8)gsHiSectorX, (UINT8)gsHiSectorY );
}
}
break;
case 'g':
//Add a group of 8 stationary enemies
if( gsSelSectorX && gsSelSectorY )
{
pSector = &SectorInfo[ SECTOR( gsSelSectorX, gsSelSectorY ) ];
pSector->ubNumElites += 1;
pSector->ubNumTroops += 7;
}
else if( gsHiSectorX && gsHiSectorY )
{
pSector = &SectorInfo[ SECTOR( gsHiSectorX, gsHiSectorY ) ];
pSector->ubNumElites += 1;
pSector->ubNumTroops += 7;
}
break;
case 'c':
//Add a group of 8 creatures.
if( gsSelSectorX && gsSelSectorY )
{
pSector = &SectorInfo[ SECTOR( gsSelSectorX, gsSelSectorY ) ];
pSector->ubNumCreatures += 8;
}
else if( gsHiSectorX && gsHiSectorY )
{
pSector = &SectorInfo[ SECTOR( gsHiSectorX, gsHiSectorY ) ];
pSector->ubNumCreatures += 8;
}
break;
}
}
}
}
void EasyCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ RESET_EASY ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ RESET_NORMAL ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ RESET_HARD ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ QUEEN_AWAKE_TOGGLE ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
gfRenderViewer = TRUE;
gGameOptions.ubDifficultyLevel = DIF_LEVEL_EASY;
ShutdownStrategicLayer();
InitStrategicLayer();
Compression0Callback( ButtonList[ iViewerButton[ COMPRESSION0 ] ], MSYS_CALLBACK_REASON_LBUTTON_UP );
MarkButtonsDirty();
WarpGameTime( 45 * 60, WARPTIME_PROCESS_EVENTS_NORMALLY );
}
}
void NormalCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ RESET_EASY ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ RESET_NORMAL ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ RESET_HARD ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ QUEEN_AWAKE_TOGGLE ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
gfRenderViewer = TRUE;
gGameOptions.ubDifficultyLevel = DIF_LEVEL_MEDIUM;
ShutdownStrategicLayer();
InitStrategicLayer();
Compression0Callback( ButtonList[ iViewerButton[ COMPRESSION0 ] ], MSYS_CALLBACK_REASON_LBUTTON_UP );
MarkButtonsDirty();
WarpGameTime( 45 * 60, WARPTIME_PROCESS_EVENTS_NORMALLY );
}
}
void HardCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ RESET_EASY ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ RESET_NORMAL ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ RESET_HARD ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ QUEEN_AWAKE_TOGGLE ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
gfRenderViewer = TRUE;
gGameOptions.ubDifficultyLevel = DIF_LEVEL_HARD;
ShutdownStrategicLayer();
InitStrategicLayer();
Compression0Callback( ButtonList[ iViewerButton[ COMPRESSION0 ] ], MSYS_CALLBACK_REASON_LBUTTON_UP );
MarkButtonsDirty();
WarpGameTime( 45 * 60, WARPTIME_PROCESS_EVENTS_NORMALLY );
}
}
void ViewerMapMoveCallback( MOUSE_REGION *reg, INT32 reason )
{
static INT16 gsPrevX = 0, gsPrevY = 0;
//calc current sector highlighted.
if( reason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
gsPrevX = gsHiSectorX = 0;
gsPrevY = gsHiSectorY = 0;
gfRenderViewer = TRUE;
return;
}
gsHiSectorX = min( (reg->RelativeXPos / 26) + 1, 16 );
gsHiSectorY = min( (reg->RelativeYPos / 22) + 1, 16 );
if( gsPrevX != gsHiSectorX || gsPrevY != gsHiSectorY )
{
gsPrevX = gsHiSectorX;
gsPrevY = gsHiSectorY;
gfRenderViewer = TRUE;
}
}
void ViewerMapClickCallback( MOUSE_REGION *reg, INT32 reason )
{
static INT16 sLastX = -1, sLastY = -1;
//calc current sector selected.
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gsSelSectorX = min( (reg->RelativeXPos / 26) + 1, 16 );
gsSelSectorY = min( (reg->RelativeYPos / 22) + 1, 16 );
if( gsSelSectorX != sLastX || gsSelSectorY != sLastY )
{ //clicked in a new sector
sLastX = gsSelSectorX;
sLastY = gsSelSectorY;
gfRenderViewer = TRUE;
}
}
}
UINT32 AIViewerScreenInit()
{
gfViewerEntry = TRUE;
gusBlue = Get16BPPColor( FROMRGB( 65, 79, 94 ) );
gusLtBlue = Get16BPPColor( FROMRGB( 122, 124, 121 ) );
gusDkBlue = Get16BPPColor( FROMRGB( 22, 55, 73 ) );
return TRUE;
}
UINT32 AIViewerScreenHandle()
{
StartFrameBufferRender();
RestoreBackgroundRects();
if( gfViewerEntry )
{
gfViewerEntry = FALSE;
if( !CreateAIViewer() )
{
return MAP_SCREEN;
}
}
if( GetWorldTotalSeconds() != guiLastTime )
{
guiLastTime = GetWorldTotalSeconds();
gfRenderViewer = TRUE;
SpecifyButtonText( iViewerButton[ VIEWER_TIMEPANEL ], WORLDTIMESTR );
}
HandleViewerInput();
RenderViewer();
RenderAllTextFields();
RenderButtons();
SaveBackgroundRects( );
RenderButtonsFastHelp();
ExecuteBaseDirtyRectQueue();
EndFrameBufferRender();
if( gfExitViewer )
{
DestroyAIViewer();
return MAP_SCREEN;
}
return AIVIEWER_SCREEN;
}
UINT32 AIViewerScreenShutdown()
{
return TRUE;
}
void Compression0Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ COMPRESSION0 ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ COMPRESSION5 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION15 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION60 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
// ButtonList[ iViewerButton[ COMPRESSION6H ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
SetGameMinutesPerSecond( 0 );
}
}
void Compression5Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ COMPRESSION0 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION5 ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ COMPRESSION15 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION60 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
// ButtonList[ iViewerButton[ COMPRESSION6H ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
SetGameMinutesPerSecond( 5 );
SetFactTimeCompressHasOccured( );
}
}
void Compression15Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ COMPRESSION0 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION5 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION15 ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ COMPRESSION60 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
// ButtonList[ iViewerButton[ COMPRESSION6H ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
SetGameMinutesPerSecond( 15 );
SetFactTimeCompressHasOccured( );
}
}
void Compression60Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ COMPRESSION0 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION5 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION15 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION60 ] ]->uiFlags |= BUTTON_CLICKED_ON;
// ButtonList[ iViewerButton[ COMPRESSION6H ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
SetGameHoursPerSecond( 1 );
SetFactTimeCompressHasOccured( );
}
}
void Compression6HCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
ButtonList[ iViewerButton[ COMPRESSION0 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION5 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION15 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
ButtonList[ iViewerButton[ COMPRESSION60 ] ]->uiFlags &= (~BUTTON_CLICKED_ON);
// ButtonList[ iViewerButton[ COMPRESSION6H ] ]->uiFlags |= BUTTON_CLICKED_ON;
SetGameHoursPerSecond( 6 );
SetFactTimeCompressHasOccured( );
}
}
void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
GROUP *pGroup;
UINT8 ubSector;
UINT32 uiWorldMin;
Compression0Callback( ButtonList[ iViewerButton[ COMPRESSION0 ] ], MSYS_CALLBACK_REASON_LBUTTON_UP );
if( ( gsSelSectorX == 0 ) || ( gsSelSectorY == 0 ) )
// HEADROCK HAM 3.5: Not sure what this function does at all... But this is externalized now anyway.
gsSelSectorX = gGameExternalOptions.ubDefaultArrivalSectorX, gsSelSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
ubSector = SECTOR( gsSelSectorX, gsSelSectorY );
uiWorldMin = GetWorldTotalMin();
gfRenderViewer = TRUE;
if( gsSelSectorY > 1 )
{
pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector-16, 0, 11, 5 );
pGroup->ubNextX = (UINT8)gsSelSectorX;
pGroup->ubNextY = (UINT8)gsSelSectorY;
pGroup->uiTraverseTime = 10;
pGroup->pEnemyGroup->ubIntention = ASSAULT;
SetGroupArrivalTime( pGroup, uiWorldMin + 10 );
pGroup->ubMoveType = ONE_WAY;
pGroup->fDebugGroup = TRUE;
AddStrategicEvent( EVENT_GROUP_ARRIVAL, pGroup->uiArrivalTime, pGroup->ubGroupID );
}
if( gsSelSectorY < 16 )
{
pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+16, 0, 8, 8 );
pGroup->ubNextX = (UINT8)gsSelSectorX;
pGroup->ubNextY = (UINT8)gsSelSectorY;
pGroup->uiTraverseTime = 12;
pGroup->pEnemyGroup->ubIntention = ASSAULT;
SetGroupArrivalTime( pGroup, uiWorldMin + 12 );
pGroup->ubMoveType = ONE_WAY;
pGroup->fDebugGroup = TRUE;
AddStrategicEvent( EVENT_GROUP_ARRIVAL, pGroup->uiArrivalTime, pGroup->ubGroupID );
}
if( gsSelSectorX > 1 )
{
pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector-1, 0, 11, 5 );
pGroup->ubNextX = (UINT8)gsSelSectorX;
pGroup->ubNextY = (UINT8)gsSelSectorY;
pGroup->uiTraverseTime = 11;
pGroup->pEnemyGroup->ubIntention = ASSAULT;
SetGroupArrivalTime( pGroup, uiWorldMin + 11 );
pGroup->ubMoveType = ONE_WAY;
pGroup->fDebugGroup = TRUE;
AddStrategicEvent( EVENT_GROUP_ARRIVAL, pGroup->uiArrivalTime, pGroup->ubGroupID );
}
if( gsSelSectorX < 16 )
{
pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+1, 0, 14, 0 );
pGroup->ubNextX = (UINT8)gsSelSectorX;
pGroup->ubNextY = (UINT8)gsSelSectorY;
pGroup->uiTraverseTime = 13;
pGroup->pEnemyGroup->ubIntention = ASSAULT;
SetGroupArrivalTime( pGroup, uiWorldMin + 13 );
pGroup->ubMoveType = ONE_WAY;
pGroup->fDebugGroup = TRUE;
AddStrategicEvent( EVENT_GROUP_ARRIVAL, pGroup->uiArrivalTime, pGroup->ubGroupID );
}
}
}
void StartCreatureQuestCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
//Madd: wtf? gGameOptions.ubGameStyle == STYLE_PLATINUM;
gfRenderMap = TRUE;
ClearCreatureQuest();
InitCreatureQuest();
}
}
void SpreadCreaturesCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfRenderMap = TRUE;
if( _KeyDown( ALT ) )
{
INT32 i;
// spread 10 times
for( i = 0; i < 10; i++ )
{
SpreadCreatures();
}
}
SpreadCreatures();
}
}
void CreatureAttackCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if( ( gsSelSectorX != 0 ) && ( gsSelSectorX != 0 ) )
{
if( _KeyDown( ALT ) )
{
AddStrategicEventUsingSeconds( EVENT_CREATURE_ATTACK, GetWorldTotalSeconds()+4, SECTOR( gsSelSectorX, gsSelSectorY ) );
}
else
{
CreatureAttackTown( (UINT8)SECTOR( gsSelSectorX, gsSelSectorY ), TRUE );
}
}
}
}
void ViewEnemiesCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfViewEnemies = TRUE;
gfRenderMap = TRUE;
ButtonList[ iViewerButton[ VIEW_CREATURES ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
gbViewLevel = 0;
ButtonList[ iViewerButton[ BASEMENT1_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT2_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT3_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
}
}
void ViewCreaturesCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfViewEnemies = FALSE;
gfRenderMap = TRUE;
ButtonList[ iViewerButton[ VIEW_ENEMIES] ]->uiFlags &= ~BUTTON_CLICKED_ON;
if( !gbViewLevel )
{
gbViewLevel = 1;
ButtonList[ iViewerButton[ BASEMENT1_BTN ] ]->uiFlags |= BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT2_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT3_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
}
}
}
void B1Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfRenderMap = TRUE;
gbViewLevel = 1;
ButtonList[ iViewerButton[ BASEMENT2_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT3_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
}
}
void B2Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfRenderMap = TRUE;
gbViewLevel = 2;
ButtonList[ iViewerButton[ BASEMENT1_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT3_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
}
}
void B3Callback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfRenderMap = TRUE;
gbViewLevel = 3;
ButtonList[ iViewerButton[ BASEMENT1_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ iViewerButton[ BASEMENT2_BTN ] ]->uiFlags &= ~BUTTON_CLICKED_ON;
}
}
void ReloadSectorCallback( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
gfOverrideSector = TRUE;
ExtractAndUpdatePopulations();
SetCurrentWorldSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
gfOverrideSector = FALSE;
DestroyAIViewer();
}
}
void ExtractAndUpdatePopulations()
{
//Kaiden: Loading INI file to read Values...
//Tag for later - this is one of the reasons the
// Map Editor won't compile. And I feel stupid about it.
// Pointing to a static location for the INI file.
// Not only bad, the file is no longer there.
//CIniReader iniReader("..\\Ja2_Options.ini");
//INT32 iMaxEnemyGroupSize = iniReader.ReadInteger("Options","MAX_STRATEGIC_TEAM_SIZE",20);
gsAINumAdmins = (INT16) min( GetNumericStrictValueFromField( 0 ), gGameExternalOptions.iMaxEnemyGroupSize );
SetInputFieldStringWithNumericStrictValue( 0, gsAINumAdmins );
gsAINumTroops = (INT16) min( GetNumericStrictValueFromField( 1 ), gGameExternalOptions.iMaxEnemyGroupSize );
SetInputFieldStringWithNumericStrictValue( 1, gsAINumTroops );
gsAINumElites = (INT16) min( GetNumericStrictValueFromField( 2 ), gGameExternalOptions.iMaxEnemyGroupSize );
SetInputFieldStringWithNumericStrictValue( 2, gsAINumElites );
gsAINumCreatures = (INT16) min( GetNumericStrictValueFromField( 3 ), gGameExternalOptions.iMaxEnemyGroupSize );
SetInputFieldStringWithNumericStrictValue( 3, gsAINumCreatures );
}
void ToggleQueenAwake( GUI_BUTTON *btn, INT32 reason )
{
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if( btn->uiFlags & BUTTON_CLICKED_ON )
{
WakeUpQueen();
}
else
{
gfQueenAIAwake = FALSE;
}
}
}
enum
{
ENEMY_RANK_TOTAL = NUM_ENEMY_RANKS,
ENEMY_RANK_PERCENT,
TABLE_ENEMY_RANKS
};
CHAR16 EnemyRankString[ TABLE_ENEMY_RANKS ][ 10 ] =
{
L"Adm",
L"Trp",
L"Elt",
L"TOT",
L"%%",
};
enum
{
ENEMY_TYPE_POOL,
ENEMY_TYPE_GARRISON,
ENEMY_TYPE_PATROL,
ENEMY_TYPE_REINFORCEMENTS,
ENEMY_TYPE_ASSAULT,
ENEMY_TYPE_STAGING,
ENEMY_TYPE_RETREATING,
ENEMY_TYPE_TOTAL,
ENEMY_TYPE_PERCENT,
POP_TABLE_ENEMY_TYPES
};
CHAR16 EnemyTypeString[ POP_TABLE_ENEMY_TYPES ][ 10 ] =
{
L"Pool",
L"Garr",
L"Ptrl",
L"Rein",
L"Aslt",
L"Stag",
L"Rtrt",
L" TOT",
L" %%",
};
#define POP_TABLE_X_OFFSET 30
#define POP_TABLE_X_GAP 30
#define POP_TABLE_Y_GAP 10
void PrintEnemyPopTable()
{
UINT16 usX, usY;
UINT16 usEnemyPopTable[ TABLE_ENEMY_RANKS ][ POP_TABLE_ENEMY_TYPES ];
UINT32 uiSector = 0;
UINT8 ubEnemyRank;
UINT8 ubEnemyType;
SECTORINFO *pSector;
GROUP *pGroup;
CHAR16 wPrintSpec[ 10 ];
CHAR16 wTempString [10 ];
memset( &usEnemyPopTable, 0, sizeof ( usEnemyPopTable ) );
// count how many enemies of each type & rank there are
// this is quite inaccurate, since elites can also come from the pool
usEnemyPopTable[ ENEMY_RANK_TROOP ][ ENEMY_TYPE_POOL ] += ( UINT16 ) giReinforcementPool;
// count stationary enemies (garrisons)
for ( uiSector = 0; uiSector < 256; uiSector++ )
{
pSector = &SectorInfo[ uiSector ];
usEnemyPopTable[ ENEMY_RANK_ADMIN ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumAdmins;
usEnemyPopTable[ ENEMY_RANK_TROOP ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumTroops;
usEnemyPopTable[ ENEMY_RANK_ELITE ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumElites;
}
// count moving enemies
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fDebugGroup )
{
Assert( pGroup->pEnemyGroup != NULL );
switch ( pGroup->pEnemyGroup->ubIntention )
{
case REINFORCEMENTS: ubEnemyType = ENEMY_TYPE_REINFORCEMENTS; break;
case ASSAULT: ubEnemyType = ENEMY_TYPE_ASSAULT; break;
case STAGING: ubEnemyType = ENEMY_TYPE_STAGING; break;
case PATROL: ubEnemyType = ENEMY_TYPE_PATROL; break;
case PURSUIT: ubEnemyType = ENEMY_TYPE_ASSAULT; break;
default:
AssertMsg( 0, String( "Unknown moving group intention %d", pGroup->pEnemyGroup->ubIntention ) );
continue;
}
usEnemyPopTable[ ENEMY_RANK_ADMIN ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumAdmins;
usEnemyPopTable[ ENEMY_RANK_TROOP ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumTroops;
usEnemyPopTable[ ENEMY_RANK_ELITE ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumElites;
}
pGroup = pGroup->next;
}
// add up totals across rows (ranks) by type
for ( ubEnemyType = 0; ubEnemyType < ENEMY_TYPE_TOTAL; ubEnemyType++ )
{
for ( ubEnemyRank = 0; ubEnemyRank < ENEMY_RANK_TOTAL; ubEnemyRank++ )
{
usEnemyPopTable[ ENEMY_RANK_TOTAL ][ ubEnemyType ] += usEnemyPopTable[ ubEnemyRank ][ ubEnemyType ];
}
}
// add up totals by rank across columns (types)
for ( ubEnemyRank = 0; ubEnemyRank <= ENEMY_RANK_TOTAL; ubEnemyRank++ )
{
for ( ubEnemyType = 0; ubEnemyType < ENEMY_TYPE_TOTAL; ubEnemyType++ )
{
usEnemyPopTable[ ubEnemyRank ][ ENEMY_TYPE_TOTAL ] += usEnemyPopTable[ ubEnemyRank ][ ubEnemyType ];
}
}
// avoid division by zero
if ( usEnemyPopTable[ ENEMY_RANK_TOTAL ][ ENEMY_TYPE_TOTAL ] > 0 )
{
// calculate rank percentages
for ( ubEnemyRank = 0; ubEnemyRank < ENEMY_RANK_PERCENT; ubEnemyRank++ )
{
usEnemyPopTable[ ubEnemyRank ][ ENEMY_TYPE_PERCENT ] = ( ( 100 * usEnemyPopTable[ ubEnemyRank ][ ENEMY_TYPE_TOTAL ] ) /
usEnemyPopTable[ ENEMY_RANK_TOTAL ][ ENEMY_TYPE_TOTAL ] );
}
// calculate type percentages
for ( ubEnemyType = 0; ubEnemyType < ENEMY_TYPE_PERCENT; ubEnemyType++ )
{
usEnemyPopTable[ ENEMY_RANK_PERCENT ][ ubEnemyType ] = ( ( 100 * usEnemyPopTable[ ENEMY_RANK_TOTAL ][ ubEnemyType ] ) /
usEnemyPopTable[ ENEMY_RANK_TOTAL ][ ENEMY_TYPE_TOTAL ] );
}
}
usX = VIEWER_RIGHT + 10;
usY = 200;
// titles and headings mean 2 extra rows
ClearViewerRegion( usX, usY, 640, ( INT16 ) ( usY + ( POP_TABLE_Y_GAP * ( POP_TABLE_ENEMY_TYPES + 2 )) + 11 ) );
// print table title
SetFontForeground( FONT_RED );
mprintf( usX, usY, L"ENEMY POPULATION:" );
usY += POP_TABLE_Y_GAP;
// print horizontal labels
for ( ubEnemyRank = 0; ubEnemyRank < TABLE_ENEMY_RANKS; ubEnemyRank++ )
{
DrawTextToScreen( EnemyRankString[ ubEnemyRank ], ( UINT16 ) ( usX + POP_TABLE_X_OFFSET + ( POP_TABLE_X_GAP * ubEnemyRank ) ), usY, POP_TABLE_X_GAP, FONT10ARIAL, FONT_LTBLUE, 0, FALSE, RIGHT_JUSTIFIED );
}
// print vertical labels
for ( ubEnemyType = 0; ubEnemyType < POP_TABLE_ENEMY_TYPES; ubEnemyType++ )
{
DrawTextToScreen( EnemyTypeString[ ubEnemyType ], usX, ( UINT16 ) ( usY + POP_TABLE_Y_GAP + ( POP_TABLE_Y_GAP * ubEnemyType ) ), POP_TABLE_X_OFFSET, FONT10ARIAL, FONT_LTBLUE, 0, FALSE, RIGHT_JUSTIFIED );
}
// over to first column, and down 1 line
usY += POP_TABLE_Y_GAP;
usX += POP_TABLE_X_OFFSET;
SetFontForeground( FONT_YELLOW );
// print table values
for ( ubEnemyRank = 0; ubEnemyRank < TABLE_ENEMY_RANKS; ubEnemyRank++ )
{
for ( ubEnemyType = 0; ubEnemyType < POP_TABLE_ENEMY_TYPES; ubEnemyType++ )
{
// an exclusive OR operator, how often do ya see that, huh? :-)
if ( ( ubEnemyRank == ENEMY_RANK_PERCENT ) ^ ( ubEnemyType == ENEMY_TYPE_PERCENT ) )
{
wcscpy( wPrintSpec, L"%3d%%%%" );
}
else
if ( ( ubEnemyRank == ENEMY_RANK_PERCENT ) && ( ubEnemyType == ENEMY_TYPE_PERCENT ) )
{
wcscpy( wPrintSpec, L"" );
}
else
{
wcscpy( wPrintSpec, L"%4d" );
}
swprintf( wTempString, wPrintSpec, usEnemyPopTable[ ubEnemyRank ][ ubEnemyType ] );
DrawTextToScreen( wTempString, ( UINT16 ) ( usX + ( POP_TABLE_X_GAP * ubEnemyRank ) ), ( UINT16 ) ( usY + ( POP_TABLE_Y_GAP * ubEnemyType ) ), POP_TABLE_X_GAP, FONT10ARIAL, FONT_YELLOW, 0, FALSE, RIGHT_JUSTIFIED );
}
}
}
enum
{
ENEMIES_KILLED_IN_TACTICAL,
ENEMIES_KILLED_IN_AUTO_RESOLVE,
ENEMIES_KILLED_TOTAL,
ENEMIES_KILLED_PERCENT,
KILLED_TABLE_ROWS
};
CHAR16 EnemiesKilledString[ KILLED_TABLE_ROWS ][ 10 ] =
{
L"Tact",
L"Auto",
L" TOT",
L" %%",
};
#define KILLED_TABLE_X_OFFSET 30
#define KILLED_TABLE_X_GAP 30
#define KILLED_TABLE_Y_GAP 10
void PrintEnemiesKilledTable()
{
UINT16 usX, usY;
UINT16 usEnemiesKilledTable[ TABLE_ENEMY_RANKS ][ KILLED_TABLE_ROWS ];
UINT8 ubEnemyRank;
UINT8 ubKillType;
CHAR16 wPrintSpec[ 10 ];
CHAR16 wTempString [10 ];
memset( &usEnemiesKilledTable, 0, sizeof ( usEnemiesKilledTable ) );
// fill table with raw data
for ( ubKillType = 0; ubKillType < ENEMIES_KILLED_TOTAL; ubKillType++ )
{
for ( ubEnemyRank = 0; ubEnemyRank < ENEMY_RANK_TOTAL; ubEnemyRank++ )
{
usEnemiesKilledTable[ ubEnemyRank ][ ubKillType ] = gStrategicStatus.usEnemiesKilled[ ubKillType ][ ubEnemyRank ];
}
}
// count how many enemies of each type & rank there are
// add up totals across rows (ranks) by type
for ( ubKillType = 0; ubKillType < ENEMIES_KILLED_TOTAL; ubKillType++ )
{
for ( ubEnemyRank = 0; ubEnemyRank < ENEMY_RANK_TOTAL; ubEnemyRank++ )
{
usEnemiesKilledTable[ ENEMY_RANK_TOTAL ][ ubKillType ] += usEnemiesKilledTable[ ubEnemyRank ][ ubKillType ];
}
}
// add up totals by rank across columns (types)
for ( ubEnemyRank = 0; ubEnemyRank <= ENEMY_RANK_TOTAL; ubEnemyRank++ )
{
for ( ubKillType = 0; ubKillType < ENEMIES_KILLED_TOTAL; ubKillType++ )
{
usEnemiesKilledTable[ ubEnemyRank ][ ENEMIES_KILLED_TOTAL ] += usEnemiesKilledTable[ ubEnemyRank ][ ubKillType ];
}
}
// avoid division by zero
if ( usEnemiesKilledTable[ ENEMY_RANK_TOTAL ][ ENEMIES_KILLED_TOTAL ] > 0 )
{
// calculate rank percentages
for ( ubEnemyRank = 0; ubEnemyRank < ENEMY_RANK_PERCENT; ubEnemyRank++ )
{
usEnemiesKilledTable[ ubEnemyRank ][ ENEMIES_KILLED_PERCENT ] = ( ( 100 * usEnemiesKilledTable[ ubEnemyRank ][ ENEMIES_KILLED_TOTAL ] ) /
usEnemiesKilledTable[ ENEMY_RANK_TOTAL ][ ENEMIES_KILLED_TOTAL ] );
}
// calculate kill type percentages
for ( ubKillType = 0; ubKillType < ENEMIES_KILLED_PERCENT; ubKillType++ )
{
usEnemiesKilledTable[ ENEMY_RANK_PERCENT ][ ubKillType ] = ( ( 100 * usEnemiesKilledTable[ ENEMY_RANK_TOTAL ][ ubKillType ] ) /
usEnemiesKilledTable[ ENEMY_RANK_TOTAL ][ ENEMIES_KILLED_TOTAL ] );
}
}
usX = VIEWER_RIGHT + 10;
usY = 310;
// titles and headings mean 2 extra rows
ClearViewerRegion( usX, usY, 640, ( INT16 ) ( usY + ( KILLED_TABLE_Y_GAP * ( KILLED_TABLE_ROWS + 2 ) ) + 11) );
// print table title
SetFontForeground( FONT_RED );
mprintf( usX, usY, L"ENEMIES KILLED:" );
usY += KILLED_TABLE_Y_GAP;
// print horizontal labels
for ( ubEnemyRank = 0; ubEnemyRank < TABLE_ENEMY_RANKS; ubEnemyRank++ )
{
DrawTextToScreen( EnemyRankString[ ubEnemyRank ], ( UINT16 ) ( usX + KILLED_TABLE_X_OFFSET + ( KILLED_TABLE_X_GAP * ubEnemyRank ) ), usY, KILLED_TABLE_X_GAP, FONT10ARIAL, FONT_LTBLUE, 0, FALSE, RIGHT_JUSTIFIED );
}
// print vertical labels
for ( ubKillType = 0; ubKillType < KILLED_TABLE_ROWS; ubKillType++ )
{
DrawTextToScreen( EnemiesKilledString[ ubKillType ], usX, ( UINT16 ) ( usY + KILLED_TABLE_Y_GAP + ( KILLED_TABLE_Y_GAP * ubKillType ) ), KILLED_TABLE_X_OFFSET, FONT10ARIAL, FONT_LTBLUE, 0, FALSE, RIGHT_JUSTIFIED );
}
// over to first column, and down 1 line
usY += KILLED_TABLE_Y_GAP;
usX += KILLED_TABLE_X_OFFSET;
SetFontForeground( FONT_YELLOW );
// print table values
for ( ubEnemyRank = 0; ubEnemyRank < TABLE_ENEMY_RANKS; ubEnemyRank++ )
{
for ( ubKillType = 0; ubKillType < KILLED_TABLE_ROWS; ubKillType++ )
{
// an exclusive OR operator, how often do ya see that, huh? :-)
if ( ( ubEnemyRank == ENEMY_RANK_PERCENT ) ^ ( ubKillType == ENEMIES_KILLED_PERCENT ) )
{
wcscpy( wPrintSpec, L"%3d%%%%" );
}
else
if ( ( ubEnemyRank == ENEMY_RANK_PERCENT ) && ( ubKillType == ENEMIES_KILLED_PERCENT ) )
{
wcscpy( wPrintSpec, L"" );
}
else
{
wcscpy( wPrintSpec, L"%4d" );
}
swprintf( wTempString, wPrintSpec, usEnemiesKilledTable[ ubEnemyRank ][ ubKillType ] );
DrawTextToScreen( wTempString, ( UINT16 ) ( usX + ( KILLED_TABLE_X_GAP * ubEnemyRank ) ), ( UINT16 ) ( usY + ( KILLED_TABLE_Y_GAP * ubKillType ) ), KILLED_TABLE_X_GAP, FONT10ARIAL, FONT_YELLOW, 0, FALSE, RIGHT_JUSTIFIED );
}
}
}
UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites )
{
UINT8 ubIconColor;
// The colors are:
// Yellow Admins only
// Red Troops only
// Gray Elites only
// Orange Mixed, no elites (Admins + Troops)
// Burgundy Mixed, with elites (Elites + (Admins OR Troops))
Assert( ubAdmins || ubTroops || ubElites );
if ( ubElites )
{
if ( ubTroops || ubAdmins )
ubIconColor = ICON_COLOR_BURGUNDY;
else
ubIconColor = ICON_COLOR_GRAY;
}
else // no elites
{
if ( ubTroops )
{
if ( ubAdmins )
ubIconColor = ICON_COLOR_ORANGE;
else
ubIconColor = ICON_COLOR_RED;
}
else // admins only
{
ubIconColor = ICON_COLOR_YELLOW;
}
}
return ( ubIconColor );
}
void BlitGroupIcon( UINT8 ubIconType, UINT8 ubIconColor, UINT32 uiX, UINT32 uiY, HVOBJECT hVObject )
{
UINT8 ubObjectIndex;
Assert( ubIconType < NUM_ICON_TYPES );
Assert( ubIconColor < NUM_ICON_COLORS );
ubObjectIndex = (UINT8)( ubIconType * NUM_ICON_COLORS ) + ubIconColor;
BltVideoObject( FRAME_BUFFER, hVObject, ubObjectIndex, uiX, uiY, VO_BLT_SRCTRANSPARENCY, NULL );
}
void PrintDetailedEnemiesInSectorInfo( INT32 iScreenX, INT32 iScreenY, UINT8 ubSectorX, UINT8 ubSectorY )
{
SECTORINFO *pSector;
GROUP *pGroup;
INT32 iDesired, iSurplus;
UINT8 ubGroupCnt = 0;
UINT8 ubSectorID;
CHAR16 wString[ 120 ];
CHAR16 wSubString[ 120 ];
INT16 iGarrisonIndex;
INT16 iPatrolIndex;
WAYPOINT *pFinalWaypoint;
pSector = &SectorInfo[ SECTOR( ubSectorX, ubSectorY ) ];
Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */
// handle garrisoned enemies
if( pSector->ubGarrisonID != NO_GARRISON )
{
iDesired = gArmyComp[ gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition ].bDesiredPopulation;
iSurplus = pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumElites - iDesired;
SetFontForeground( FONT_WHITE );
swprintf( wString, L"Garrison #%d: %d desired, ", pSector->ubGarrisonID, iDesired );
if( iSurplus >= 0 )
{
swprintf( wSubString, L"%d surplus troops", iSurplus );
wcscat( wString, wSubString );
}
else
{
swprintf( wSubString, L"%d reinforcements requested", -iSurplus );
wcscat( wString, wSubString );
}
mprintf( iScreenX, iScreenY, wString );
iScreenY += 10;
if( gGarrisonGroup[ pSector->ubGarrisonID ].ubPendingGroupID )
{
pGroup = GetGroup( gGarrisonGroup[ pSector->ubGarrisonID ].ubPendingGroupID );
if( pGroup )
{
mprintf( iScreenX, iScreenY, L"%d reinforcements on route from group %d in %c%d", pGroup->ubGroupSize, pGroup->ubGroupID,
pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX );
}
else
{ //ERROR! Should be a valid group...
}
}
else
{
mprintf( iScreenX, iScreenY, L"No pending reinforcements for this sector." );
}
iScreenY += 10;
}
else
{
SetFontForeground( FONT_GRAY2 );
mprintf( iScreenX, iScreenY, L"No garrison information for this sector." );
iScreenY += 10;
}
// handle mobile enemies anchored in this sector
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle )
{
if ( ( pGroup->ubSectorX == ubSectorX ) && ( pGroup->ubSectorY == ubSectorY ) )
{
Assert( pGroup->pEnemyGroup->ubIntention < NUM_ENEMY_INTENTIONS );
swprintf( wString, L"Group %c: %s", 'A' + ubGroupCnt, gwGroupTypeString[ pGroup->pEnemyGroup->ubIntention ] );
switch ( pGroup->pEnemyGroup->ubIntention )
{
case ASSAULT:
case PURSUIT:
iGarrisonIndex = FindGarrisonIndexForGroupIDPending( pGroup->ubGroupID );
if ( iGarrisonIndex != -1 )
{
ubSectorID = gGarrisonGroup[ iGarrisonIndex ].ubSectorID;
swprintf( wSubString, L", target sector %c%d", SECTORY( ubSectorID ) + 'A' - 1, SECTORX( ubSectorID ) );
}
else
{
pFinalWaypoint = GetFinalWaypoint( pGroup );
if( pFinalWaypoint )
{
if( pFinalWaypoint->x == 3 && pFinalWaypoint->y == 16 )
{
swprintf( wSubString, L" - group returning to pool.");
}
else
{
swprintf( wSubString, L" - moving to %c%d", pFinalWaypoint->y + 'A' - 1, pFinalWaypoint->x );
}
}
else
{
swprintf( wSubString, L" - can't determine target sector" );
}
}
wcscat( wString, wSubString );
break;
case REINFORCEMENTS:
case STAGING:
// check if it's reinforcing a garrison
iGarrisonIndex = FindGarrisonIndexForGroupIDPending( pGroup->ubGroupID );
if ( iGarrisonIndex != -1 )
{
ubSectorID = gGarrisonGroup[ iGarrisonIndex ].ubSectorID;
swprintf( wSubString, L", dest sector %c%d", SECTORY( ubSectorID ) + 'A' - 1, SECTORX( ubSectorID ) );
wcscat( wString, wSubString );
}
else // must be reinforcing a patrol
{
iPatrolIndex = FindPatrolGroupIndexForGroupIDPending( pGroup->ubGroupID );
if( iPatrolIndex != -1 )
{
pFinalWaypoint = GetFinalWaypoint( pGroup );
Assert( pFinalWaypoint );
swprintf( wSubString, L", Patrol #%d, dest sector %c%d", iPatrolIndex, pFinalWaypoint->y + 'A' - 1, pFinalWaypoint->x );
wcscat( wString, wSubString );
}
else
{
pFinalWaypoint = GetFinalWaypoint( pGroup );
if( pFinalWaypoint )
{
if( pFinalWaypoint->x == 3 && pFinalWaypoint->y == 16 )
{
swprintf( wSubString, L" - group returning to pool.");
}
else
{
swprintf( wSubString, L" - lost group moving to %c%d", pFinalWaypoint->y + 'A' - 1, pFinalWaypoint->x );
}
}
else
{
swprintf( wSubString, L" (LOST GROUP!)" );
}
wcscat( wString, wSubString );
}
}
break;
case PATROL:
iPatrolIndex = FindPatrolGroupIndexForGroupID( pGroup->ubGroupID );
if( iPatrolIndex != -1 )
{
swprintf( wSubString, L"#%d, next sector %c%d", iPatrolIndex, pGroup->ubNextY + 'A' - 1, pGroup->ubNextX );
}
else
{
swprintf( wSubString, L"#err, FLOATING GROUP!" );
}
wcscat( wString, wSubString );
break;
}
mprintf( iScreenX, iScreenY, wString );
iScreenY += 10;
ubGroupCnt++;
// no room on screen to display info for more than 3 groups in one sector!
if ( ubGroupCnt >= 3 )
{
break;
}
}
}
pGroup = pGroup->next;
}
}
#endif