mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Development Trunk (now obsolete): https://ja2svn.dyndns.org/source/ja2/branches/Wanne/JA2%201.13%20MP A detailed list of all the features (changes) is visible in the history log of the development trunk: INFO: There will be no further development in the development source trunk, so is obsolete from now on! This commit contains the following features (bugfixes are not listed): - New Feature: Show merc ranks in Strategy Screen before merc name o Toggle on/off in the ingame options screen o For each experience level (0-10) there are defined rank names in the language specific text files o Additional language text that is not translated yet is marked with // TODO.Translate - New Feature: Faster Bobby Ray Shipments o This feature is selectable in the ja2_options.ini o When activated Bobby Ray shipments will be really fast -> Overnight Express: 5 - 7 hours -> Air Service: 10, 12 or 14 hours -> Standard Service: 15, 18 or 21 hours o In a multiplayer game, this feature is disabled (because shipment arrive immediately in the destination sector) - New Feature: AP cost for manipulating the merc inventory o This feature is selectable in the start new game screen o For example, putting a weapon from hand in the backpack costs APs o The AP costs are defined in the APBPConstants.ini o In a multiplayer game, this feature is disabled - New Feature: Added possibility to set individual Gear Kit names o Set individual names in the optional new tag <mGearKitName> inside the <GEARKIT> root element (File: TableData\MercStartingGear.xml) - New Feature: Externalized the maximum purchase amount (JA2 vanilla: 10) for Bobby Rays purchases per shipment o Define the max. amount in the ja2_options.ini: BOBBY_RAY_MAX_PURCHASE_AMOUNT, Range: 10 - 100) o Nice scrolling bars to scroll through all the purchases - New Feature: Now it is possible to walk on "water" tiles or handle those tiles like "normal" tiles o (instead of showing the swimming animation and counting the APs for swimming), when the soldier is located on the second level (level > 0) - New Feature: Externalized AIM Veterans laptop site o Add maximum of 4 pages o Add new AIM to veterans page, and remove AIM from veterans page. o New XML file: OldAIMArchive.xml (language specific XML files: *.OldAIMArchive.xml) - New Feature: Added possibility to choose from 254 IMP faces o Modified IMPPortraits.xml o Added new GameDir folder "IMPFaces" which contains the IMP face portraits o Moved IMP faces in the new "IMPFaces" folder - New Feature: ARSP - All Resolution Support Project o See here: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=298698&page=1 o Support any kind of screen resolution. This works by choosing the matching full supported resolution (640x480, 800x600, 1024x768) and then centering the graphics o See ja2.ini for defining the screen resolution - New Feature: AI Turn Speed Up (FF-MOD) o see here: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=298699#Post298699 o When this feature is activated it allows fast enemy turns o New entry in ja2.ini to enable this feature: HIGHSPEED_TIMER = TRUE o Turn on/off auto fast turns in ingame options o New ja2_options.ini settings for fine tuning: [Clock Settings] ini block - New Feature: "Lock" / "Release" mouse cursor in tactical windowed mode, so the mouse can stay within window boundary o This is very helpful for doing scrolling with the mouse (by moving the mouse to the window edge) in windowed mode o You can toggle on/off the feature by pressing CTRL + Z. It is also possible to press CTRL + Y. So the user can decide which fits better :) o Whenever you toggle on/off a screen message appears on the tactical log to notify the player - New Feature: Weapon overheating o Basically, every shot fired from a gun increases its temperature. On higher temperatures, the gun jams more frequently o On/off toggle in the ingame options o Graphical thermometer indication on the weapon picture o New ja2_options.ini section with a few options, Section: [Tactical Weapon Overheating Settings] o XML changes (New Tags) --> AmmoTypes.xml: <temperatureModificator> --> Items.xml: <barrel>, <usOverheatingCooldownFactor> --> Weapons.xml: <usOverheatingJamThreshold>, <usOverheatingDamageThreshold>, <usOverheatingSingleShotTemperature> o Added a few barells to Items.xml (end of the file) o more infos: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=301059&page=1 - New Feature: Resting weapons on a surfaces o You can now rest your weapon on crates, low walls, rocks, debris, open windows etc. while you are crouched. Resting will give yu the superior gun handling modifiers from PRONE position. o A little 'A' on your gun indicates if you are resting it or not. o Both settings can be turned on and off in Ja2_Options.ini under 'Tactical Gameplay Settings' - New Feature: Externalized option on whether mercs can exit sector using grid exit in turn based mode o new ja2_options.ini property: GRID_EXIT_IN_TURNBASED o This ini setting does not affect leaving sectors on map edges - Rework/Update: Ammo boxes and Ammo crates o Ammo crate items added for remaining calibers. Tweaked prices to correspond to magazines, tweaked capacities and weights to be reasonable (~800 or less). o Shift-R reload now looks at both boxes and crates in sector items and merc's inventory to reload, and tops off magazines in inventory as well. Only possible outside of combat. o Ctrl-Shift-A still creates crates as per usual, with some fixes to ensure all ammo is caught on the first press. o Shift-A now creates ammo boxes in the same loop. They mostly behave like crates, but fit in mercs inventories. o Ammo boxes are available to purchase at BR and tony, sam, etc. Individual magazines/drums/etc are no longer available. o Removed ammo crate xml tag. Added ubMagType tag to Magazines array. This allows us to differentiate between magazines, bullets, boxes and crates. o Changed ammo filtering in BR's to display boxes appropriately. Added back the "Mag:" display (changed text to "Size:") o Added ja2set.dat.xml file (WF map version in WF maps folder) to be used instead of ja2set.dat file (ja2.ini setting added) For now, if you want to play vanilla instead, just change the setting in the ini (see comments in file). o Added P4-P9Items image files (up to 5k images each) and tileslots. 1.13 core items will continue to use Guns and P1-P3Items for the foreseeable future. P4-P9 can be used by customizers/modders to avoid conflicts with Guns/P1-P3 items. TODO: Need to discuss a strategy for this in the forums. o Added in Ambient/0.bad and 32.bad to avoid an exception in the code. o Updated the XML Editor o Standardized the text on all the ammo items. - New Multiplayer Feature: Sharing same FOV (field of view) in a coop/team-dm (for friendly teams) game o You will also see enemies, that your teammate sees git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5108 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2060 lines
65 KiB
C++
2060 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;
|
|
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 )
|
|
{
|
|
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
|