Files
source/Strategic/AI Viewer.cpp
majcostaandGitHub 24425a82b1 More unused stuff removal (#49)
* More unused stuff removal

delete:
- giant 'metaheaders' (JA2 All.h, Laptop All.h, etc), preferring to add #includes directly where needed
- unused ExceptionHandling and DbMan translation units
- unused WizShare.h, Bitmap.h, trle.h, video_private.h headers

* remove mentions from vc proj files too

* remove preprocessor conditionals for unused definitions

find . -iname '*.h' -o -iname '*.cpp' -exec unifdef.exe -m -UPRECOMPILED_HEADERS -UJA2_PRECOMPILED_HEADERS -UWIZ8_PRECOMPILED_HEADERS -UPRECOMPILEDHEADERS {} ';'

then manually fixed a couple files the tool errored out on

* yes, the comments too

as title
2023-01-03 15:51:48 +02:00

2071 lines
66 KiB
C++

//Strategic AI Viewer
#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 "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 "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"
#include "Town Militia.h" // added by Flugente
#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, UINT8 ubTanks, UINT8 ubJeeps );
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 gsAINumTanks = -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 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 ( INT32 y = 0; y < 16; ++y )
{
yp = VIEWER_TOP + VIEWER_CELLH * y + 1;
for ( INT32 x = 0; x < 16; ++x )
{
SetFontForeground( FONT_YELLOW );
xp = VIEWER_LEFT + VIEWER_CELLW * x + 1;
iSector = SECTOR(x, y);
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 );
UINT8 nummilitia = NumNonPlayerTeamMembersInSector( x, y, MILITIA_TEAM );
if ( nummilitia )
{
// show militia
ubIconColor = ICON_COLOR_BLUE;
ubGroupSize = nummilitia;
}
else if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumJeeps + pSector->ubNumTanks )
{
// show enemies
ubIconColor = ChooseEnemyIconColor( pSector->ubNumAdmins, pSector->ubNumTroops, pSector->ubNumElites, pSector->ubNumTanks, pSector->ubNumJeeps );
ubGroupSize = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumJeeps + pSector->ubNumTanks;
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, ubNumTanks, ubNumJeeps;
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->usGroupTeam == OUR_TEAM )
{
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;
ubNumTanks = pGroup->pEnemyGroup->ubNumTanks;
ubNumJeeps = pGroup->pEnemyGroup->ubNumJeeps;
// must have one of the three, already checked groupsize!
Assert( ubNumAdmins || ubNumTroops || ubNumElites || ubNumTanks || ubNumJeeps );
//determine icon color
ubIconColor = ChooseEnemyIconColor( ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks, ubNumJeeps );
// 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->usGroupTeam == OUR_TEAM && !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, xp, yp;
if( gfViewEnemies && !gbViewLevel )
{
RenderStationaryGroups();
RenderMovingGroupsAndMercs();
SetFontForeground( FONT_LTRED );
xp = VIEWER_LEFT + VIEWER_CELLW * ( gModSettings.ubSAISpawnSectorX - 1 ) + 6;
yp = VIEWER_TOP + VIEWER_CELLH * ( gModSettings.ubSAISpawnSectorY - 1 ) + 13;
//mprintf( 78, 358, L"%3d", giReinforcementPool );
mprintf( xp, yp, 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, ubNumTanks = 0, ubNumJeeps = 0, ubAdminsInBattle = 0, ubTroopsInBattle = 0, ubElitesInBattle = 0, ubTanksInBattle = 0, ubJeepsInBattle = 0,ubNumGroups = 0;
pSector = &SectorInfo[ SECTOR( ubSectorX, ubSectorY ) ];
//Now count the number of mobile groups in the sector.
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam != OUR_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == ubSectorX && pGroup->ubSectorY == ubSectorY )
{
ubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
ubNumElites += pGroup->pEnemyGroup->ubNumElites;
ubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
ubNumTanks += pGroup->pEnemyGroup->ubNumTanks;
ubNumJeeps += pGroup->pEnemyGroup->ubNumJeeps;
ubTroopsInBattle += pGroup->pEnemyGroup->ubTroopsInBattle;
ubElitesInBattle += pGroup->pEnemyGroup->ubElitesInBattle;
ubAdminsInBattle += pGroup->pEnemyGroup->ubAdminsInBattle;
ubTanksInBattle += pGroup->pEnemyGroup->ubTanksInBattle;
ubJeepsInBattle += pGroup->pEnemyGroup->ubJeepsInBattle;
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)",
MilitiaInSectorOfRank( ubSectorX, ubSectorY, GREEN_MILITIA ), MilitiaInSectorOfRank( ubSectorX, ubSectorY, REGULAR_MILITIA ), MilitiaInSectorOfRank( ubSectorX, ubSectorY, ELITE_MILITIA ) );
yp += 10;
SetFontForeground( FONT_ORANGE );
mprintf( 280, yp, L"Garrison: (%d:%d Admins, %d:%d Troops, %d:%d Elites, %d:%d Tanks, %d:%d Jeeps)",
pSector->ubAdminsInBattle, pSector->ubNumAdmins,
pSector->ubTroopsInBattle, pSector->ubNumTroops,
pSector->ubElitesInBattle, pSector->ubNumElites,
pSector->ubTanksInBattle, pSector->ubNumTanks,
pSector->ubJeepsInBattle, pSector->ubNumJeeps );
yp += 10;
mprintf( 280, yp, L"%d Groups: (%d:%d Admins, %d:%d Troops, %d:%d Elites, %d:%d Tanks, %d:%d Jeeps)", ubNumGroups,
ubAdminsInBattle, ubNumAdmins,
ubTroopsInBattle, ubNumTroops,
ubElitesInBattle, ubNumElites,
ubTanksInBattle, ubNumTanks,
ubJeepsInBattle, ubNumJeeps );
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;
while( DequeueSpecificEvent(&Event, KEY_DOWN|KEY_UP) )
{
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 )
{
StrategicAddMilitiaToSector( gsSelSectorX, gsSelSectorY, GREEN_MILITIA, 15 );
StrategicAddMilitiaToSector( gsSelSectorX, gsSelSectorY, REGULAR_MILITIA, 4 );
StrategicAddMilitiaToSector( gsSelSectorX, gsSelSectorY, ELITE_MILITIA, 1 );
gfRenderMap = TRUE;
EliminateAllEnemies( (UINT8)gsSelSectorX, (UINT8)gsSelSectorY );
}
else if( gsHiSectorX && gsHiSectorY )
{
StrategicAddMilitiaToSector( gsHiSectorX, gsHiSectorY, GREEN_MILITIA, 15 );
StrategicAddMilitiaToSector( gsHiSectorX, gsHiSectorY, REGULAR_MILITIA, 4 );
StrategicAddMilitiaToSector( gsHiSectorX, gsHiSectorY, ELITE_MILITIA, 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, 0, 0, 0 );
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, 0, 0, 0 );
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, 0, 0, 0 );
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, 0, 0, 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 ) && ( gsSelSectorY != 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;
//usEnemyPopTable[ ENEMY_RANK_TANK ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumTanks;
}
// count moving enemies
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam != OUR_TEAM && !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;
//usEnemyPopTable[ ENEMY_RANK_TANK ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumTanks;
}
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 ubTanks, UINT8 ubJeeps )
{
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 || ubTanks || ubJeeps );
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 + pSector->ubNumTanks - 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->usGroupTeam != OUR_TEAM && !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 == gModSettings.ubSAISpawnSectorX && pFinalWaypoint->y == gModSettings.ubSAISpawnSectorY )
{
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 == gModSettings.ubSAISpawnSectorX && pFinalWaypoint->y == gModSettings.ubSAISpawnSectorY )
{
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