/// Log chosen policy void CvPolicyAI::LogPolicyChoice(PolicyTypes ePolicy) { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString strDesc; // Find the name of this civ and city playerName = m_pCurrentPolicies->GetPlayer()->getCivilizationShortDescription(); FILogFile* pLog; pLog = LOGFILEMGR.GetLog(GetLogFileName(playerName), FILogFile::kDontTimeStamp); // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; CvPolicyEntry* pPolicyEntry = GC.getPolicyInfo(ePolicy); const char* szPolicyType = (pPolicyEntry != NULL)? pPolicyEntry->GetType() : "Unknown"; strTemp.Format("CHOSEN, %s", szPolicyType); strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } }
/// Logging function to write out info on Ideology choices void CvPolicyAI::LogIdeologyChoice(CvString &decisionState, int iWeightFreedom, int iWeightAutocracy, int iWeightOrder) { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; // Find the name of this civ playerName = m_pCurrentPolicies->GetPlayer()->getCivilizationShortDescription(); FILogFile* pLog; pLog = LOGFILEMGR.GetLog(GetLogFileName(playerName), FILogFile::kDontTimeStamp); // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; strTemp.Format("%s, Freedom: %d, Order: %d, Autocracy: %d", decisionState.c_str(), iWeightFreedom, iWeightOrder, iWeightAutocracy); strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } }
/// Log chosen policy void CvPolicyAI::LogBranchChoice(PolicyBranchTypes eBranch) { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString strDesc; // Find the name of this civ and city playerName = m_pCurrentPolicies->GetPlayer()->getCivilizationShortDescription(); FILogFile* pLog; pLog = LOGFILEMGR.GetLog(GetLogFileName(playerName), FILogFile::kDontTimeStamp); // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; strTemp.Format("CHOSEN, Branch %d", eBranch); strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } }
/// Log GrandStrategy state: what are the Priorities and who is Active? void CvGrandStrategyAI::LogGrandStrategies(const FStaticVector< int, 5, true, c_eCiv5GameplayDLL >& vModifiedGrandStrategyPriorities) { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString strDesc; CvString strLogName; // Find the name of this civ and city playerName = GetPlayer()->getCivilizationShortDescription(); // Open the log file if(GC.getPlayerAndCityAILogSplit()) { strLogName = "GrandStrategyAI_Log_" + playerName + ".csv"; } else { strLogName = "GrandStrategyAI_Log.csv"; } FILogFile* pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); AIGrandStrategyTypes eGrandStrategy; // Loop through Grand Strategies for(int iGrandStrategyLoop = 0; iGrandStrategyLoop < GC.getNumAIGrandStrategyInfos(); iGrandStrategyLoop++) { // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; eGrandStrategy = (AIGrandStrategyTypes) iGrandStrategyLoop; // GrandStrategy Info CvAIGrandStrategyXMLEntry* pEntry = GC.getAIGrandStrategyInfo(eGrandStrategy); const char* szAIGrandStrategyType = (pEntry != NULL)? pEntry->GetType() : "Unknown Type"; if(GetActiveGrandStrategy() == eGrandStrategy) { strTemp.Format("*** %s, %d, %d", szAIGrandStrategyType, GetGrandStrategyPriority(eGrandStrategy), vModifiedGrandStrategyPriorities[eGrandStrategy]); } else { strTemp.Format("%s, %d, %d", szAIGrandStrategyType, GetGrandStrategyPriority(eGrandStrategy), vModifiedGrandStrategyPriorities[eGrandStrategy]); } strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } } }
void CvLoggerCSV::WriteCSVLog(const char* strLogName, const char* strHeader) { FILogFile *pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); CvAssert(pLog != NULL); pLog->Msg(strHeader); }
/// Log all possible policy choices void CvPolicyAI::LogPossiblePolicies() { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString strDesc; // Find the name of this civ and city playerName = m_pCurrentPolicies->GetPlayer()->getCivilizationShortDescription(); FILogFile* pLog; pLog = LOGFILEMGR.GetLog(GetLogFileName(playerName), FILogFile::kDontTimeStamp); // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; int iNumBranches = GC.getNumPolicyBranchInfos(); // Dump out the weight of each possible policy for(int iI = 0; iI < m_AdoptablePolicies.size(); iI++) { int iWeight = m_AdoptablePolicies.GetWeight(iI); if(m_AdoptablePolicies.GetElement(iI) < iNumBranches) { strTemp.Format("Branch %d, %d", m_AdoptablePolicies.GetElement(iI), iWeight); } else { PolicyTypes ePolicy = (PolicyTypes)(m_AdoptablePolicies.GetElement(iI) - iNumBranches); CvPolicyEntry* pPolicyEntry = GC.getPolicyInfo(ePolicy); const char* szPolicyType = (pPolicyEntry != NULL)? pPolicyEntry->GetType() : "Unknown"; strTemp.Format("%s, %d", szPolicyType, iWeight); } strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } } }
unsigned long CvRandom::get(unsigned long ulNum, const char* pszLog) { if(!gDLL->IsGameCoreThread() && gDLL->IsGameCoreExecuting() && m_bSynchronous) { OutputDebugString("Warning: GUI is accessing the synchronous random number generator while the game core is running."); } m_ulCallCount++; unsigned long long ullNewSeed = ((RANDOM_A * m_ullRandomSeed) + RANDOM_C); unsigned long ul = ((unsigned long)((((ullNewSeed >> RANDOM_SHIFT) & MAX_UNSIGNED_INT) * (ulNum)) / (MAX_UNSIGNED_INT + 1LL))); if(GC.getLogging()) { int iRandLogging = GC.getRandLogging(); if(iRandLogging > 0 && (m_bSynchronous || (iRandLogging & RAND_LOGGING_ASYNCHRONOUS_FLAG) != 0)) { CvGame& kGame = GC.getGame(); if(kGame.getTurnSlice() > 0 || ((iRandLogging & RAND_LOGGING_PREGAME_FLAG) != 0)) { FILogFile* pLog = LOGFILEMGR.GetLog("RandCalls.csv", FILogFile::kDontTimeStamp, "Game Turn, Turn Slice, Range, Value, Seed, Instance, Type, Location\n"); if(pLog) { char szOut[1024] = {0}; sprintf_s(szOut, "%d, %d, %u, %u, %I64u, %8x, %s, %s\n", kGame.getGameTurn(), kGame.getTurnSlice(), ulNum, ul, m_ullRandomSeed, (void*)this, m_bSynchronous?"sync":"async", (pszLog != NULL)?pszLog:"Unknown"); pLog->Msg(szOut); #if defined(MOD_CORE_DEBUGGING) if(MOD_CORE_DEBUGGING) { //gStackWalker.SetLog(pLog); //gStackWalker.ShowCallstack(); } #endif } } } } m_ullRandomSeed = ullNewSeed; return ul; }
/// Log all potential builds void CvProjectProductionAI::LogPossibleBuilds() { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString cityName; CvString strDesc; CvString strLogName; CvAssert(m_pCity); if(!m_pCity) return; // Find the name of this civ and city playerName = GET_PLAYER(m_pCity->getOwner()).getCivilizationShortDescription(); cityName = m_pCity->getName(); // Open the log file FILogFile* pLog; pLog = LOGFILEMGR.GetLog(m_pCity->GetCityStrategyAI()->GetLogFileName(playerName, cityName), FILogFile::kDontTimeStamp); CvAssert(pLog); if(!pLog) return; // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", " + cityName + ", "; // Dump out the weight of each buildable item for(int iI = 0; iI < m_Buildables.size(); iI++) { CvProjectEntry* pProjectEntry = GC.GetGameProjects()->GetEntry(m_Buildables.GetElement(iI)); strDesc = (pProjectEntry != NULL)? pProjectEntry->GetDescription() : "Unknown"; strTemp.Format("Project, %s, %d", strDesc.GetCString(), m_Buildables.GetWeight(iI)); strOutBuf = strBaseString + strTemp; pLog->Msg(strOutBuf); } } }
// TODO Make this function more useful. void CvPlayerAI::AI_LogEvent(int iEvent, int iOption) { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString playerName; CvString strDesc; CvString strLogName; CvString strTemp; // Find the name of this civ and city playerName = getCivilizationShortDescription(); // Open the log file if(GC.getPlayerAndCityAILogSplit()) { strLogName = "EventAILog_" + playerName + ".csv"; } else { strLogName = "EventAILog.csv"; } FILogFile* pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); // Get the leading info for this line strBaseString.Format("%03d, EVENT, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName; strTemp.Format("%d, %d", iEvent, iOption); strOutBuf = strBaseString + ", " + strTemp; pLog->Msg(strOutBuf); } }
/// Log our guess as to other Players' Active Grand Strategy void CvGrandStrategyAI::LogGuessOtherPlayerGrandStrategy(const FStaticVector< int, 5, true, c_eCiv5GameplayDLL >& vGrandStrategyPriorities, PlayerTypes ePlayer) { if(GC.getLogging() && GC.getAILogging()) { CvString strOutBuf; CvString strBaseString; CvString strTemp; CvString playerName; CvString otherPlayerName; CvString strDesc; CvString strLogName; // Find the name of this civ and city playerName = GetPlayer()->getCivilizationShortDescription(); // Open the log file if(GC.getPlayerAndCityAILogSplit()) { strLogName = "GrandStrategyAI_Guess_Log_" + playerName + ".csv"; } else { strLogName = "GrandStrategyAI_Guess_Log.csv"; } FILogFile* pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); AIGrandStrategyTypes eGrandStrategy; int iPriority; // Loop through Grand Strategies for(int iGrandStrategyLoop = 0; iGrandStrategyLoop < GC.getNumAIGrandStrategyInfos(); iGrandStrategyLoop++) { // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; eGrandStrategy = (AIGrandStrategyTypes) iGrandStrategyLoop; iPriority = vGrandStrategyPriorities[iGrandStrategyLoop]; CvAIGrandStrategyXMLEntry* pEntry = GC.getAIGrandStrategyInfo(eGrandStrategy); const char* szGrandStrategyType = (pEntry != NULL)? pEntry->GetType() : "Unknown Strategy"; // GrandStrategy Info if(GetActiveGrandStrategy() == eGrandStrategy) { strTemp.Format("*** %s, %d", szGrandStrategyType, iPriority); } else { strTemp.Format("%s, %d", szGrandStrategyType, iPriority); } otherPlayerName = GET_PLAYER(ePlayer).getCivilizationShortDescription(); strOutBuf = strBaseString + otherPlayerName + ", " + strTemp; if(GetGuessOtherPlayerActiveGrandStrategy(ePlayer) == eGrandStrategy) { // Confidence in our guess switch(GetGuessOtherPlayerActiveGrandStrategyConfidence(ePlayer)) { case GUESS_CONFIDENCE_POSITIVE: strTemp.Format("Positive"); break; case GUESS_CONFIDENCE_LIKELY: strTemp.Format("Likely"); break; case GUESS_CONFIDENCE_UNSURE: strTemp.Format("Unsure"); break; default: strTemp.Format("XXX"); break; } strOutBuf += ", " + strTemp; } pLog->Msg(strOutBuf); } // One more entry for NO GRAND STRATEGY // Get the leading info for this line strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; iPriority = vGrandStrategyPriorities[GC.getNumAIGrandStrategyInfos()]; // GrandStrategy Info strTemp.Format("NO_GRAND_STRATEGY, %d", iPriority); otherPlayerName = GET_PLAYER(ePlayer).getCivilizationShortDescription(); strOutBuf = strBaseString + otherPlayerName + ", " + strTemp; pLog->Msg(strOutBuf); } }
void CvCityAI::AI_chooseProduction(bool bInterruptWonders) { VALIDATE_OBJECT CvPlayerAI& kOwner = GET_PLAYER(getOwner()); CvCitySpecializationAI* pSpecializationAI = kOwner.GetCitySpecializationAI(); bool bBuildWonder = false; // See if this is the one AI city that is supposed to be building wonders if(pSpecializationAI->GetWonderBuildCity() == this) { // Is it still working on that wonder and we don't want to interrupt it? if(!bInterruptWonders) { const BuildingTypes eBuilding = getProductionBuilding(); CvBuildingEntry* pkBuilding = (eBuilding != NO_BUILDING)? GC.getBuildingInfo(eBuilding) : NULL; if(pkBuilding && kOwner.GetWonderProductionAI()->IsWonder(*pkBuilding)) { return; // Stay the course } } // So we're the wonder building city but it is not underway yet... // Has the designated wonder been poached by another civ? BuildingTypes eNextWonder = pSpecializationAI->GetNextWonderDesired(); if(!canConstruct(eNextWonder)) { // Reset city specialization kOwner.GetCitySpecializationAI()->SetSpecializationsDirty(SPECIALIZATION_UPDATE_WONDER_BUILT_BY_RIVAL); } else { // to prevent us from continuously locking into building wonders in one city when there are other high priority items to build int iFlavorWonder = kOwner.GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)GC.getInfoTypeForString("FLAVOR_WONDER")); int iFlavorGP = kOwner.GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)GC.getInfoTypeForString("FLAVOR_GREAT_PEOPLE")); int iFlavor = (iFlavorWonder > iFlavorGP ) ? iFlavorWonder : iFlavorGP; if (GC.getGame().getJonRandNum(11, "Random roll for whether to continue building wonders") <= iFlavor) bBuildWonder = true; } } if(bBuildWonder) { CvCityBuildable buildable; buildable.m_eBuildableType = CITY_BUILDABLE_BUILDING; buildable.m_iIndex = pSpecializationAI->GetNextWonderDesired(); buildable.m_iTurnsToConstruct = getProductionTurnsLeft((BuildingTypes)buildable.m_eBuildableType, 0); pushOrder(ORDER_CONSTRUCT, buildable.m_iIndex, -1, false, false, false, false); if(GC.getLogging() && GC.getAILogging()) { CvString playerName; FILogFile* pLog; CvString strBaseString; CvString strOutBuf; m_pCityStrategyAI->LogCityProduction(buildable, false); playerName = kOwner.getCivilizationShortDescription(); pLog = LOGFILEMGR.GetLog(kOwner.GetCitySpecializationAI()->GetLogFileName(playerName), FILogFile::kDontTimeStamp); strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns()); strBaseString += playerName + ", "; strOutBuf.Format("%s, WONDER - Started %s, Turns: %d", getName().GetCString(), GC.getBuildingInfo((BuildingTypes)buildable.m_iIndex)->GetDescription(), buildable.m_iTurnsToConstruct); strBaseString += strOutBuf; pLog->Msg(strBaseString); } } else { m_pCityStrategyAI->ChooseProduction(false); AI_setChooseProductionDirty(false); } return; }
unsigned short CvRandom::get(unsigned short usNum, const char* pszLog) { recordCallStack(); m_ulCallCount++; unsigned long ulNewSeed = ((RANDOM_A * m_ulRandomSeed) + RANDOM_C); unsigned short us = ((unsigned short)((((ulNewSeed >> RANDOM_SHIFT) & MAX_UNSIGNED_SHORT) * ((unsigned long)usNum)) / (MAX_UNSIGNED_SHORT + 1))); if(GC.getLogging()) { int iRandLogging = GC.getRandLogging(); if(iRandLogging > 0 && (m_bSynchronous || (iRandLogging & RAND_LOGGING_ASYNCHRONOUS_FLAG) != 0)) { #if !defined(FINAL_RELEASE) if(!gDLL->IsGameCoreThread() && gDLL->IsGameCoreExecuting() && m_bSynchronous) { CvAssertMsg(0, "App side is accessing the synchronous random number generator while the game core is running."); } #endif CvGame& kGame = GC.getGame(); if(kGame.getTurnSlice() > 0 || ((iRandLogging & RAND_LOGGING_PREGAME_FLAG) != 0)) { FILogFile* pLog = LOGFILEMGR.GetLog("RandCalls.csv", FILogFile::kDontTimeStamp, "Game Turn, Turn Slice, Range, Value, Seed, Instance, Type, Location\n"); if(pLog) { char szOut[1024] = {0}; sprintf_s(szOut, "%d, %d, %u, %u, %u, %8x, %s, %s\n", kGame.getGameTurn(), kGame.getTurnSlice(), (uint)usNum, (uint)us, getSeed(), (uint)this, m_bSynchronous?"sync":"async", (pszLog != NULL)?pszLog:"Unknown"); pLog->Msg(szOut); #if !defined(FINAL_RELEASE) if((iRandLogging & RAND_LOGGING_CALLSTACK_FLAG) != 0) { #ifdef _DEBUG if(m_bExtendedCallStackDebugging) { // Use the callstack from the extended callstack debugging system const FCallStack& callStack = m_kCallStacks.back(); std::string stackTrace = callStack.toString(true, 6); pLog->Msg(stackTrace.c_str()); } else #endif { #ifdef WIN32 // Get callstack directly FCallStack callStack; FDebugHelper::GetInstance().GetCallStack(&callStack, 0, 8); std::string stackTrace = callStack.toString(true, 6); pLog->Msg(stackTrace.c_str()); #endif } } #endif } } } } m_ulRandomSeed = ulNewSeed; return us; }
void CvTreasury::LogExpenditure(CvString strExpenditure, int iAmount, int iColumn) { if(!(GC.getLogging() && GC.getAILogging())) { return; } // don't log minor civs for now if(m_pPlayer->isMinorCiv()) { return; } static bool bFirstRun = true; bool bBuildHeader = false; CvString strHeader; if(bFirstRun) { bFirstRun = false; bBuildHeader = true; } CvString strLog; // Find the name of this civ and city CvString strPlayerName; strPlayerName = m_pPlayer->getCivilizationShortDescription(); CvString strLogName; // Open the log file if(GC.getPlayerAndCityAILogSplit()) { strLogName = "ExpenditureLog_" + strPlayerName + ".csv"; } else { strLogName = "ExpenditureLog.csv"; } FILogFile* pLog; pLog = LOGFILEMGR.GetLog(strLogName, FILogFile::kDontTimeStamp); CvString str; // civ name TreasuryHelpers::AppendToLog(strHeader, strLog, "Civ Name", strPlayerName); // turn TreasuryHelpers::AppendToLog(strHeader, strLog, "Turn", GC.getGame().getGameTurn()); // treasury at turn start TreasuryHelpers::AppendToLog(strHeader, strLog, "Treasury Before Purchase", m_pPlayer->GetTreasury()->GetGold()); // Cost of Plot if (iColumn == 1){ TreasuryHelpers::AppendToLog(strHeader, strLog, "Cost of Plot:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "Cost of Plot:", 0); } // City Expenditure and Amount if (iColumn == 2){ TreasuryHelpers::AppendToLog(strHeader, strLog, "City Bought:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "City Spent:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "City Bought:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "City Spent:", 0); } // Unit Upgrade and cost if (iColumn == 3){ TreasuryHelpers::AppendToLog(strHeader, strLog, "Unit Upgraded:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Spent on Upgrade:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "Unit Upgrade:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Spent on Upgrade:", 0); } // City State Gifted and Amount if (iColumn == 4){ TreasuryHelpers::AppendToLog(strHeader, strLog, "City State Gold Gifted:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Gold Gift Amount:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "City State Gold Gifted:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Gold Gift Amount:", 0); } // City State Improved and Amount if (iColumn == 5){ TreasuryHelpers::AppendToLog(strHeader, strLog, "City State Improved:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Gold for Improvement Amount:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "City State Improved:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Gold for Improvement Amount:", 0); } // City State Bought and Amount if (iColumn == 6){ TreasuryHelpers::AppendToLog(strHeader, strLog, "City State Bought:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Bought for:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "City State Bought:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Bought for:", 0); } // Emergency City Expenditure Unit and Amount if (iColumn == 7){ TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Unit:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Unit Cost:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Unit:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Unit Cost:", 0); } // Emergency City Expenditure Unit and Amount if (iColumn == 8){ TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Building:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Building Cost:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Building:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Emergency Building Cost:", 0); } // Research Agreement and Amount if (iColumn == 9){ TreasuryHelpers::AppendToLog(strHeader, strLog, "Research Agreement with:", strExpenditure); TreasuryHelpers::AppendToLog(strHeader, strLog, "Research Agreement Cost:", iAmount); } else{ TreasuryHelpers::AppendToLog(strHeader, strLog, "Research Agreement with:", ""); TreasuryHelpers::AppendToLog(strHeader, strLog, "Research Agreement Cost:", 0); } if(bBuildHeader) { pLog->Msg(strHeader); } pLog->Msg(strLog); }