| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: AcademyStats.cpp //////////////////////////////////////////////////////
- //-----------------------------------------------------------------------------
- //
- // Electronic Arts Los Angeles
- //
- // Confidential Information
- // Copyright (C) 2003 - All Rights Reserved
- //
- //-----------------------------------------------------------------------------
- //
- // Project: RTS3
- //
- // File name: AcademyStats.cpp
- //
- // Created: Kris Morness, July 2003
- //
- // Desc: Keeps track of various statistics in order to provide advice to
- // the player about how to improve playing.
- //
- //-----------------------------------------------------------------------------
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/AcademyStats.h"
- #include "Common/Energy.h"
- #include "Common/Player.h"
- #include "Common/PlayerList.h"
- #include "Common/PlayerTemplate.h"
- #include "Common/SpecialPower.h"
- #include "Common/ThingTemplate.h"
- #include "Common/Xfer.h"
- #include "GameClient/ControlBar.h"
- #include "GameClient/GameText.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/Module/ContainModule.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- const char *TheAcademyClassificationTypeNames[] =
- {
- "ACT_NONE",
- "ACT_UPGRADE_RADAR",
- "ACT_SUPERPOWER",
- NULL
- };
- #define FRAMES_BETWEEN_UPDATES 30
- //------------------------------------------------------------------------------------------------
- AcademyStats::AcademyStats()
- {
- }
- //------------------------------------------------------------------------------------------------
- void findDozerCommandSet( Object *object, void *userData )
- {
- const CommandSet *dozerCommandSet = (const CommandSet*)userData;
- if( dozerCommandSet )
- {
- return;
- }
- if( object && object->isKindOf( KINDOF_DOZER ) )
- {
- dozerCommandSet = TheControlBar->findCommandSet( object->getCommandSetString() );
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::init( const Player *player )
- {
- if( !TheGameLogic )
- {
- return; // GUIEdit crashes on this, so bail
- }
- m_nextUpdateFrame = TheGameLogic->getFrame() + FRAMES_BETWEEN_UPDATES;
- m_firstUpdate = TRUE;
- m_unknownSide = FALSE;
- //Init the player and cache some important information.
- m_player = player;
- const PlayerTemplate *plyrTemplate = player->getPlayerTemplate();
- if( !plyrTemplate ||
- plyrTemplate->getBaseSide().compareNoCase( "USA" ) &&
- plyrTemplate->getBaseSide().compareNoCase( "China" ) &&
- plyrTemplate->getBaseSide().compareNoCase( "GLA" ) )
- {
- //Admittedly, this is a massive violation of data driven design. Shame on me!
- //Unknown side... don't provide ANY advice. Simplicity reasons.
- m_unknownSide = TRUE;
- }
- //Find the command set for our dozer... so we can extract information about things
- //we can build.
- m_dozerCommandSet = NULL;
- player->iterateObjects( findDozerCommandSet, (void*)m_dozerCommandSet );
- m_commandCenterTemplate = NULL;
- m_supplyCenterTemplate = NULL;
- if( m_dozerCommandSet )
- {
- for( int i = 0; i < MAX_COMMANDS_PER_SET; i++ )
- {
- const CommandButton *button = m_dozerCommandSet->getCommandButton( i );
- if( button )
- {
- const ThingTemplate *thing = button->getThingTemplate();
- if( thing )
- {
- if( thing->isKindOf( KINDOF_FS_SUPPLY_CENTER ) )
- {
- m_supplyCenterTemplate = thing;
- m_supplyCenterCost = m_supplyCenterTemplate->calcCostToBuild( player );
- }
- else if( thing->isKindOf( KINDOF_COMMANDCENTER ) )
- {
- //Wow, this is bogus... but we need this template pointer in order to fire special powers from the
- //shortcut... ugh.
- m_commandCenterTemplate = thing;
- }
- }
- }
- }
- }
- //+-----------------------+
- //| Tier 1 (Basic advice) |
- //+-----------------------+
- //1) Did player build at least one of each structure type available?
- //CUT!!!
- //2) Did player run out of money before building a supply center?
- m_spentCashBeforeBuildingSupplyCenter = FALSE;
- m_supplyCentersBuilt = 0;
- if( !m_supplyCenterTemplate )
- {
- m_supplyCenterCost = 1000;
- }
- //3) Did player build radar (if applicable)?
- m_researchedRadar = FALSE;
- //4) Did player build any dozers/workers?
- m_peonsBuilt = 0;
- //5) Did player ever capture a structure?
- m_structuresCaptured = 0;
- //6) Did player spend any generals points?
- m_generalsPointsSpent = 0;
- //7) Did player ever use a generals power or superweapon?
- m_specialPowersUsed = 0;
- //8) Did player garrison any structures?
- m_structuresGarrisoned = 0;
- //9) How idle was the player in building military units?
- m_idleBuildingUnitsMaxFrames = 0;
- m_lastUnitBuiltFrame = 0;
- //10) Did player drag select units?
- m_dragSelectUnits = 0;
- //11) Did player upgrade anything?
- m_upgradesPurchased = 0;
- //12) Was player out of power for more than 10 minutes?
- m_powerOutMaxFrames = 0;
- m_oldestPowerOutFrame = 0;
- m_hadPowerLastCheck = 0;
- //13) Extra gatherers built?
- m_gatherersBuilt = 0;
- //14) Heros built?
- m_heroesBuilt = 0;
- //+------------------------------+
- //| Tier 2 (Intermediate advice) |
- //+------------------------------+
- //15) Selected a strategy center battle plan?
- m_hadAStrategyCenter = FALSE;
- m_choseAStrategyForCenter = FALSE;
- //16) Placed units inside tunnel network?
- m_hadATunnelNetwork = FALSE;
- m_unitsEnteredTunnelNetwork = 0;
- //17) Player used control groups?
- m_controlGroupsUsed = 0;
- //18) Built secondary income building?
- m_secondaryIncomeUnitsBuilt = 0;
- //19) Cleared out garrisoned buildings?
- m_clearedGarrisonedBuildings = 0;
- //20) Did the Player pick up salvage (as GLA)?
- m_salvageCollected = 0;
-
- //21) Did the player ever use the "Guard" ability?
- m_guardAbilityUsedCount = 0;
-
- //22) Did the player build more than one Supply Center (that is, did he expand out)?
- //Uses m_supplyCentersBuilt!
- //+--------------------------+
- //| Tier 3 (Advanced advice) |
- //+--------------------------+
- //25) Did the player use the new alternate interface in the options?
- //Uses TheGlobalData->m_useAlternateMouse
- //26) Player did not use the new "double click location attack move/guard"
- m_doubleClickAttackMoveOrdersGiven = 0;
- //27) Built barracks within 5 minutes?
- m_builtBarracksWithinFiveMinutes = FALSE;
- //28) Built war factory within 10 minutes?
- m_builtWarFactoryWithinTenMinutes = FALSE;
- //29) Built tech structure within 15 minutes?
- m_builtTechStructureWithinFifteenMinutes = FALSE;
- //30) No income for 2 minutes?
- m_lastIncomeFrame = 0;
- m_maxFramesBetweenIncome = 0;
- //31) Did the Player ever use Dozers/Workers to clear out traps/mines/booby traps?
- m_mines = 0;
- m_minesCleared = 0;
- //32) Captured any sniped vehicles?
- m_vehiclesRecovered = 0;
- m_vehiclesSniped = 0; //Neutral team stat
- //33) Did the player ever build a "disguisable" unit and never used the disguise ability?
- m_disguisableVehiclesBuilt = 0;
- m_vehiclesDisguised = 0;
- //34) Did the player never build a "stealth" upgrade?
- //CUT!!!
- //35) Did the player ever create a "Firestorm" with his MiGs or Inferno Cannons?
- m_firestormsCreated = 0;
- }
- //------------------------------------------------------------------------------------------------
- static void updateAcademyStats( Object *obj, void *userData )
- {
- AcademyStats *academy = (AcademyStats*)userData;
- if( !obj || !academy )
- {
- return;
- }
- if( academy->isFirstUpdate() )
- {
- academy->recordProduction( obj, NULL );
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::update()
- {
- if( m_unknownSide )
- {
- return;
- }
- UnsignedInt now = TheGameLogic->getFrame();
-
- if( m_nextUpdateFrame >= now )
- {
- m_nextUpdateFrame = now + FRAMES_BETWEEN_UPDATES;
- m_player->iterateObjects( updateAcademyStats, (void*)this );
- //2) Did player run out of money before building a supply center?
- if( !m_supplyCentersBuilt && !m_spentCashBeforeBuildingSupplyCenter )
- {
- const Money *money = m_player->getMoney();
- if( money )
- {
- UnsignedInt amount = money->countMoney();
- if( amount < m_supplyCenterCost )
- {
- m_spentCashBeforeBuildingSupplyCenter = TRUE;
- }
- }
- }
- //12) Was player out of power for more than 10 minutes?
- const Energy *power = m_player->getEnergy();
- if( power )
- {
- Bool hasPower = power->hasSufficientPower();
- if( hasPower != m_hadPowerLastCheck )
- {
- if( !hasPower )
- {
- //We just lost power
- m_oldestPowerOutFrame = now;
- }
- else
- {
- //We just gained power... see how long we were without.
- UnsignedInt frames = now - m_oldestPowerOutFrame;
- if( frames > m_powerOutMaxFrames )
- {
- m_powerOutMaxFrames = frames;
- }
- }
- m_hadPowerLastCheck = hasPower;
- }
- }
-
- if( isFirstUpdate() )
- {
- setFirstUpdate( FALSE );
- }
-
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::recordProduction( const Object *obj, const Object *constructer )
- {
- UnsignedInt now = TheGameLogic->getFrame();
- //2) Did player run out of money before building a supply center?
- //22) Did the player build more than one Supply Center (that is, did he expand out)?
- if( obj->isKindOf( KINDOF_FS_SUPPLY_CENTER ) )
- {
- m_supplyCentersBuilt++;
- }
- //4) Did player build any dozers/workers?
- if( obj->isKindOf( KINDOF_DOZER ) )
- {
- m_peonsBuilt++;
- }
- //9) How idle was the player in building military units?
- if( obj->isKindOf( KINDOF_INFANTRY ) || obj->isKindOf( KINDOF_VEHICLE ) )
- {
- if( !obj->isKindOf( KINDOF_DOZER ) && !obj->isKindOf( KINDOF_HARVESTER ) )
- {
- //How long has it been since we built our last unit?
- UnsignedInt idleFrames = now - m_lastUnitBuiltFrame;
- //If it was longer than our max time... then record it.
- if( idleFrames > m_idleBuildingUnitsMaxFrames )
- {
- m_idleBuildingUnitsMaxFrames = idleFrames;
- }
- //Record the frame we built our unit.
- m_lastUnitBuiltFrame = now;
- }
- }
- //13) Extra gatherers built?
- if( obj->isKindOf( KINDOF_HARVESTER ) )
- {
- m_gatherersBuilt++;
- }
- //14) Heros built?
- if( obj->isKindOf( KINDOF_HERO ) )
- {
- m_heroesBuilt++;
- }
- //15) Selected a strategy center battle plan?
- if( obj->isKindOf( KINDOF_FS_STRATEGY_CENTER ) )
- {
- m_hadAStrategyCenter = TRUE;
- }
- //16) Placed units inside tunnel network?
- if( obj->getContain() && obj->getContain()->isTunnelContain() )
- {
- m_hadATunnelNetwork = TRUE;
- }
- //18) Built secondary income building?
- if( obj->isKindOf( KINDOF_MONEY_HACKER ) || obj->isKindOf( KINDOF_FS_BLACK_MARKET ) || obj->isKindOf( KINDOF_FS_SUPPLY_DROPZONE ) )
- {
- m_secondaryIncomeUnitsBuilt++;
- }
- //27) Built tech structure within 15 minutes?
- if( obj->isKindOf( KINDOF_FS_BARRACKS ) )
- {
- if( TheGameLogic->getFrame() <= 300 * LOGICFRAMES_PER_SECOND )
- {
- m_builtBarracksWithinFiveMinutes = TRUE;
- }
- }
- //28) Built tech structure within 15 minutes?
- if( obj->isKindOf( KINDOF_FS_WARFACTORY ) )
- {
- if( TheGameLogic->getFrame() <= 600 * LOGICFRAMES_PER_SECOND )
- {
- m_builtWarFactoryWithinTenMinutes = TRUE;
- }
- }
- //29) Built tech structure within 15 minutes?
- if( obj->isKindOf( KINDOF_FS_ADVANCED_TECH ) )
- {
- if( TheGameLogic->getFrame() <= 900 * LOGICFRAMES_PER_SECOND )
- {
- m_builtTechStructureWithinFifteenMinutes = TRUE;
- }
- }
- //33) Did the player ever build a "disguisable" unit and never used the disguise ability?
- if( obj->isKindOf( KINDOF_DISGUISER ) )
- {
- m_disguisableVehiclesBuilt++;
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::recordUpgrade( const UpgradeTemplate *upgrade, Bool granted )
- {
- //3) Did player build radar (if applicable)?
- if( upgrade->getAcademyClassificationType() == ACT_UPGRADE_RADAR )
- {
- m_researchedRadar = TRUE;
- }
- //11) Did player upgrade anything?
- if( !granted )
- {
- m_upgradesPurchased++;
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::recordSpecialPowerUsed( const SpecialPowerTemplate *spTemplate )
- {
- if( spTemplate->getAcademyClassificationType() == ACT_SUPERPOWER )
- {
- m_specialPowersUsed++;
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::recordIncome()
- {
- UnsignedInt now = TheGameLogic->getFrame();
- UnsignedInt delta = m_lastIncomeFrame - now;
- if( delta > m_maxFramesBetweenIncome )
- {
- m_maxFramesBetweenIncome = delta;
- }
- m_lastIncomeFrame = now;
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::evaluateTier1Advice( AcademyAdviceInfo *info, Int numAvailableTips )
- {
- UnsignedInt maxAdviceTips = MAX_ADVICE_TIPS;
-
- //-allAdvice feature
- //if( !TheGlobalData->m_allAdvice )
- //{
- // maxAdviceTips = 1;
- //}
- UnsignedInt now = TheGameLogic->getFrame();
- //numAvailableTips is used to determine if we are going to randomly choose a tip
- //or determine if a tip is available (if -1)
- Bool choosing = numAvailableTips != -1;
- Int availableTips = 0;
- //1) Did player build at least one of each structure type available?
- //CUT!!!
- //2) Did player run out of money before building a supply center?
- if( m_spentCashBeforeBuildingSupplyCenter )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildSupplyCenterEarlier" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //3) Did player build radar (if applicable)?
- if( !m_researchedRadar )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:TryBuildingRadar" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //4) Did player build any dozers/workers?
- if( m_peonsBuilt < 2 )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildMorePeons" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //5) Did player ever capture a structure?
- if( !m_structuresCaptured )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:TryCapturingStructures" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //6) Did player spend any generals points?
- if( !m_generalsPointsSpent )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:SpendGeneralsPoints" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //7) Did player ever use a generals power or superweapon?
- if( !m_specialPowersUsed )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:TryUsingSuperweapons" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //8) Did player garrison any structures?
- if( !m_structuresGarrisoned )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:TryGarrisoningAStructure" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //9) How idle was the player in building military units?
- UnsignedInt idleFrames = now - m_lastUnitBuiltFrame;
- if( idleFrames > m_idleBuildingUnitsMaxFrames )
- {
- m_idleBuildingUnitsMaxFrames = idleFrames;
- }
- if( m_idleBuildingUnitsMaxFrames > 300 * LOGICFRAMES_PER_SECOND || !m_lastUnitBuiltFrame )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:IdleBuildingUnits" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //10) Did player drag select units?
- if( !m_dragSelectUnits )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:TryDragSelectingUnits" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //11) Did player upgrade anything?
- if( !m_upgradesPurchased )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:ResearchUpgrades" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //12) Was player out of power for more than 10 minutes?
- if( !m_hadPowerLastCheck )
- {
- UnsignedInt frames = now - m_oldestPowerOutFrame;
- if( frames > m_powerOutMaxFrames )
- {
- m_powerOutMaxFrames = frames;
- }
- }
- if( m_powerOutMaxFrames > 600 * LOGICFRAMES_PER_SECOND )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:RanOutOfPower" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //13) Extra gatherers built?
- if( !m_gatherersBuilt )
- {
- //Don't count free ones that come with supply centers!
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildMoreGatherers" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //14) Heros built?
- if( !m_heroesBuilt )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildAHero" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- if( !choosing && availableTips > 0 )
- {
- //We're done counting available tips, so now that we know the
- //number, we can randomly choose.
- evaluateTier1Advice( info, availableTips );
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::evaluateTier2Advice( AcademyAdviceInfo *info, Int numAvailableTips )
- {
- UnsignedInt maxAdviceTips = MAX_ADVICE_TIPS;
-
- //-allAdvice feature
- //if( !TheGlobalData->m_allAdvice )
- //{
- // maxAdviceTips = 1;
- //}
- //numAvailableTips is used to determine if we are going to randomly choose a tip
- //or determine if a tip is available (if -1)
- Bool choosing = numAvailableTips != -1;
- Int availableTips = 0;
- //15) Selected a strategy center battle plan?
- if( m_hadAStrategyCenter && !m_choseAStrategyForCenter )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:PickStrategyCenterPlan" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //16) Placed units inside tunnel network?
- if( m_hadATunnelNetwork && !m_unitsEnteredTunnelNetwork )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:UseTunnelNetwork" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //17) Player used control groups?
- if( !m_controlGroupsUsed )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:UseControlGroups" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //18) Built secondary income building?
- if( !m_secondaryIncomeUnitsBuilt )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:UseSecondaryIncomeMethods" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //19) Cleared out garrisoned buildings?
- if( !m_clearedGarrisonedBuildings )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:ClearBuildings" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //20) Did the Player pick up salvage (as GLA)?
- if( m_player->getPlayerTemplate() && !m_player->getPlayerTemplate()->getBaseSide().compareNoCase( "GLA" ) )
- {
- if( !m_salvageCollected )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:PickUpSalvage" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- }
- //21) Did the player ever use the "Guard" ability?
- if( !m_guardAbilityUsedCount )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:UseGuardAbility" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //22) Did the player build more than one Supply Center (that is, did he expand out)?
- if( m_supplyCentersBuilt < 2 )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:MultipleSupplyCenters" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //23) Did the player ever garrison a vehicle?
- //CUT!!!
- //24) Did the player ever use the hotkey to grab all of one unit type (change to use any hotkeys)?
- //CUT!!!
- if( !choosing && availableTips > 0 )
- {
- //We're done counting available tips, so now that we know the
- //number, we can randomly choose.
- evaluateTier2Advice( info, availableTips );
- }
- }
- //------------------------------------------------------------------------------------------------
- void AcademyStats::evaluateTier3Advice( AcademyAdviceInfo *info, Int numAvailableTips )
- {
- UnsignedInt maxAdviceTips = MAX_ADVICE_TIPS;
-
- //-allAdvice feature
- //if( !TheGlobalData->m_allAdvice )
- //{
- // maxAdviceTips = 1;
- //}
- UnsignedInt now = TheGameLogic->getFrame();
-
- //numAvailableTips is used to determine if we are going to randomly choose a tip
- //or determine if a tip is available (if -1)
- Bool choosing = numAvailableTips != -1;
- Int availableTips = 0;
- //25) Did the player use the new alternate interface in the options?
- if( !TheGlobalData->m_useAlternateMouse )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:AlternateMouseInterface" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //26) Player did not use the new "double click location attack move/guard"
- if( !m_doubleClickAttackMoveOrdersGiven )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:DoubleClickAttackMoveGuard" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //27) Built barracks within 5 minutes?
- if( !m_builtBarracksWithinFiveMinutes )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildBarracksSooner" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //28) Built warfactory within 10 minutes?
- if( !m_builtWarFactoryWithinTenMinutes )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildWarFactorySooner" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //29) Built tech structure within 15 minutes?
- if( !m_builtTechStructureWithinFifteenMinutes )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:BuildTechStructureSooner" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //30) No income for 2 minutes?
- UnsignedInt delta = m_lastIncomeFrame - now;
- if( delta > m_maxFramesBetweenIncome )
- {
- m_maxFramesBetweenIncome = delta;
- }
- if( m_maxFramesBetweenIncome > LOGICFRAMES_PER_SECOND * 120 || !m_lastIncomeFrame )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:NoIncome" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //31) Did the Player ever use Dozers/Workers to clear out traps/mines/booby traps?
- if( ThePlayerList->getLocalPlayer()->getAcademyStats()->getMines() > 0 && !m_minesCleared )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:NoIncome" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- //32) Captured any sniped vehicles?
- if( ThePlayerList->getNeutralPlayer()->getAcademyStats()->getVehiclesSniped() > 0 )
- {
- if( !m_vehiclesRecovered )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:UnmannedVehicles" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- }
- //33) Did the player ever build a "disguisable" unit and never used the disguise ability?
- if( m_disguisableVehiclesBuilt )
- {
- if( !m_vehiclesDisguised )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:DisguisedUnits" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- }
- //35) Did the player ever create a "Firestorm" with his MiGs or Inferno Cannons?
- if( m_player->getPlayerTemplate() && !m_player->getPlayerTemplate()->getBaseSide().compareNoCase( "China" ) )
- {
- if( !m_firestormsCreated )
- {
- availableTips++;
- Int rand = GameClientRandomValue( 0, numAvailableTips - 1 );
- Int limit = maxAdviceTips - info->numTips;
- if( choosing && rand < limit )
- {
- info->advice[ info->numTips ].concat( TheGameText->fetch( "ACADEMY:Firestorm" ) );
- info->numTips++;
- }
- numAvailableTips--;
- }
- }
- if( !choosing && availableTips > 0 )
- {
- //We're done counting available tips, so now that we know the
- //number, we can randomly choose.
- evaluateTier3Advice( info, availableTips );
- }
- }
- //------------------------------------------------------------------------------------------------
- Bool AcademyStats::calculateAcademyAdvice( AcademyAdviceInfo *info )
- {
- UnsignedInt maxAdviceTips = MAX_ADVICE_TIPS;
-
- //-allAdvice feature
- //if( !TheGlobalData->m_allAdvice )
- //{
- // maxAdviceTips = 1;
- //}
- if( m_unknownSide )
- {
- return FALSE;
- }
- //Sanity
- if( !info )
- {
- DEBUG_CRASH( ("AcademyStats::calculateAcademyAdvice() was passed in NULL AcademyAdviceInfo.") );
- return FALSE;
- }
- //It's possible to play a perfect game and not need any advice.
- info->numTips = 0;
- //Build the header for each string.
- for( Int i = 0; i < maxAdviceTips; i++ )
- {
- info->advice[ i ].format( UnicodeString( L"\n\n" ) );
- }
- //First look at tier 1 basic advice and pick any advice we could benefit from.
- evaluateTier1Advice( info );
- //Now look at tier 2 intermediate advice.
- if( info->numTips < maxAdviceTips )
- {
- evaluateTier2Advice( info );
- if( info->numTips < maxAdviceTips )
- {
- //Finally look at tier 3 advanced advice.
- evaluateTier3Advice( info );
- }
- }
- //Do we have any advice to give?
- return info->numTips != 0;
- }
- //------------------------------------------------------------------------------------------------
- // CRC
- //------------------------------------------------------------------------------------------------
- void AcademyStats::crc( Xfer *xfer )
- {
- } // end crc
- //------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version */
- //------------------------------------------------------------------------------------------------
- void AcademyStats::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- xfer->xferUnsignedInt( &m_nextUpdateFrame );
- xfer->xferBool( &m_firstUpdate );
- xfer->xferBool( &m_unknownSide );
- //+-----------------------+
- //| Tier 1 (Basic advice) |
- //+-----------------------+
- //1) Did player build at least one of each structure type available?
- //CUT!!!
- //2) Did player run out of money before building a supply center?
- xfer->xferBool( &m_spentCashBeforeBuildingSupplyCenter );
- xfer->xferUnsignedInt( &m_supplyCentersBuilt );
- xfer->xferUnsignedInt( &m_supplyCenterCost );
- //3) Did player build radar (if applicable)?
- xfer->xferBool( &m_researchedRadar );
- //4) Did player build any dozers/workers?
- xfer->xferUnsignedInt( &m_peonsBuilt );
- //5) Did player ever capture a structure?
- xfer->xferUnsignedInt( &m_structuresCaptured );
- //6) Did player spend any generals points?
- xfer->xferUnsignedInt( &m_generalsPointsSpent );
- //7) Did player ever use a generals power or superweapon?
- xfer->xferUnsignedInt( &m_specialPowersUsed );
- //8) Did player garrison any structures?
- xfer->xferUnsignedInt( &m_structuresGarrisoned );
- //9) How idle was the player in building military units?
- xfer->xferUnsignedInt( &m_idleBuildingUnitsMaxFrames );
- xfer->xferUnsignedInt( &m_lastUnitBuiltFrame );
- //10) Did player drag select units?
- xfer->xferUnsignedInt( &m_dragSelectUnits );
- //11) Did player upgrade anything?
- xfer->xferUnsignedInt( &m_upgradesPurchased );
- //12) Was player out of power for more than 10 minutes?
- xfer->xferUnsignedInt( &m_powerOutMaxFrames );
- xfer->xferUnsignedInt( &m_oldestPowerOutFrame );
- xfer->xferBool ( &m_hadPowerLastCheck );
- //13) Extra gathers built?
- xfer->xferUnsignedInt( &m_gatherersBuilt );
- //14) Heros built?
- xfer->xferUnsignedInt( &m_heroesBuilt );
- //+------------------------------+
- //| Tier 2 (Intermediate advice) |
- //+------------------------------+
- //15) Selected a strategy center battle plan?
- xfer->xferBool( &m_hadAStrategyCenter );
- xfer->xferBool( &m_choseAStrategyForCenter );
- //16) Placed units inside tunnel network?
- xfer->xferUnsignedInt( &m_unitsEnteredTunnelNetwork );
- xfer->xferBool( &m_hadATunnelNetwork );
- //17) Player used control groups?
- xfer->xferUnsignedInt( &m_controlGroupsUsed );
- //18) Built secondary income unit (hacker, dropzone, blackmarket)?
- xfer->xferUnsignedInt( &m_secondaryIncomeUnitsBuilt );
- //19) Cleared out garrisoned buildings?
- xfer->xferUnsignedInt( &m_clearedGarrisonedBuildings );
- //20) Did the Player pick up salvage (as GLA)?
- xfer->xferUnsignedInt( &m_salvageCollected );
- //21) Did the player ever use the "Guard" ability?
- xfer->xferUnsignedInt( &m_guardAbilityUsedCount );
- //22) Did the player build more than one Supply Center (that is, did he expand out)?
- //Uses m_supplyCentersBuilt!
- //23) Did the player ever garrison a vehicle?
- //CUT!!!
- //24) Did the player ever use the hotkey to grab all of one unit type (change to use any hotkeys)?
- //CUT!!!
- //+--------------------------+
- //| Tier 3 (Advanced advice) |
- //+--------------------------+
- //25) Did the player use the new alternate interface in the options?
- //Uses TheGlobalData->m_useAlternateMouse
- //26) Player did not use the new "double click location attack move/guard"
- xfer->xferUnsignedInt( &m_doubleClickAttackMoveOrdersGiven );
- //27) Built barracks within 5 minutes?
- xfer->xferBool( &m_builtBarracksWithinFiveMinutes );
- //28) Built war factory within 10 minutes?
- xfer->xferBool( &m_builtWarFactoryWithinTenMinutes );
- //29) Built tech structure within 15 minutes?
- xfer->xferBool( &m_builtTechStructureWithinFifteenMinutes );
- //30) No income for 2 minutes?
- xfer->xferUnsignedInt( &m_lastIncomeFrame );
- xfer->xferUnsignedInt( &m_maxFramesBetweenIncome );
- //31) Did the Player ever use Dozers/Workers to clear out traps/mines/booby traps?
- xfer->xferUnsignedInt( &m_mines ); //Neutral player stat
- xfer->xferUnsignedInt( &m_minesCleared );
- //32) Captured any sniped vehicles?
- xfer->xferUnsignedInt( &m_vehiclesRecovered );
- xfer->xferUnsignedInt( &m_vehiclesSniped );
- //33) Did the player ever build a "disguisable" unit and never used the disguise ability?
- xfer->xferUnsignedInt( &m_disguisableVehiclesBuilt );
- xfer->xferUnsignedInt( &m_vehiclesDisguised );
- //34) Did the player never build a "stealth" upgrade?
- //CUT!!!
- //35) Did the player ever create a "Firestorm" with his MiGs or Inferno Cannons?
- xfer->xferUnsignedInt( &m_firestormsCreated );
- } // end xfer
- //------------------------------------------------------------------------------------------------
- // Load post process
- //------------------------------------------------------------------------------------------------
- void AcademyStats::loadPostProcess( void )
- {
- } // end loadPostProcess
|