Bazaar developer reference

CvHomelandAI::ExecuteExplorerMoves()

Defined in
CvHomelandAI.cpp, line 2351
Class
CvHomelandAI
Hook name
CivHooks::CvHomelandAI_ExecuteExplorerMoves
Lua events
GameEvents.UnitGetSpecialExploreTarget

Hooks

static bool BeforeCvHomelandAI_ExecuteExplorerMoves(CvHomelandAI* self);static void AfterCvHomelandAI_ExecuteExplorerMoves(CvHomelandAI* self);static void ReplaceCvHomelandAI_ExecuteExplorerMoves(void (*original)(CvHomelandAI*), CvHomelandAI* self);CivRegisterBefore<CivHooks::CvHomelandAI_ExecuteExplorerMoves>(host, &BeforeCvHomelandAI_ExecuteExplorerMoves);CivRegisterAfter<CivHooks::CvHomelandAI_ExecuteExplorerMoves>(host, &AfterCvHomelandAI_ExecuteExplorerMoves);CivRegisterReplace<CivHooks::CvHomelandAI_ExecuteExplorerMoves>(host, &ReplaceCvHomelandAI_ExecuteExplorerMoves);

Code

2350/// Moves units to explore the map2351void CvHomelandAI::ExecuteExplorerMoves()2352{2353	bool bFoundNearbyExplorePlot = false;2354	CvEconomicAI* pEconomicAI = m_pPlayer->GetEconomicAI();23552356	pEconomicAI->UpdatePlots();23572358#if defined(PATH_PLAN_LAST)2359	WeightedPlotVector aBestPlotList;2360	aBestPlotList.reserve(100);2361#endif23622363	CvTwoLayerPathFinder& kPathFinder = GC.getPathFinder();2364	FStaticVector< CvHomelandUnit, 64, true, c_eCiv5GameplayDLL >::iterator it;2365	for(it = m_CurrentMoveUnits.begin(); it != m_CurrentMoveUnits.end(); ++it)2366	{2367		UnitHandle pUnit = m_pPlayer->getUnit(it->GetID());2368		if(!pUnit || pUnit->TurnProcessed())2369		{2370			continue;2371		}23722373		ICvEngineScriptSystem1* pkScriptSystem = gDLL->GetScriptSystem();2374		if(pkScriptSystem)2375		{2376			CvLuaArgsHandle args;2377			args->Push(pUnit->getOwner());2378			args->Push(pUnit->GetID());23792380			bool bResult;2381			LuaSupport::CallHook(pkScriptSystem, "UnitGetSpecialExploreTarget", args.get(), bResult);23822383			if(bResult)2384			{2385				continue;2386			}2387		}23882389		if (!m_pPlayer->isHuman() && pUnit->CanStartMission(CvTypes::getMISSION_SELL_EXOTIC_GOODS(), -1, -1))2390		{2391			// Far enough from home to get a good reward?2392			float fRewardFactor = pUnit->calculateExoticGoodsDistanceFactor(pUnit->plot());2393			if (fRewardFactor >= 0.5f)2394			{2395				pUnit->PushMission(CvTypes::getMISSION_SELL_EXOTIC_GOODS());2396				if(GC.getLogging() && GC.getAILogging())2397				{2398					CvString strLogString;2399					strLogString.Format("UnitID: %d used Sell Exotic Goods, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2400					LogHomelandMessage(strLogString);2401				}2402			}2403		}24042405		int iUnitX = pUnit->getX();2406		int iUnitY = pUnit->getY();24072408		CvPlot* pkStepPlot = NULL;2409		CvPlot* pGoodyPlot = pEconomicAI->GetUnitTargetGoodyPlot(pUnit.pointer(), &pkStepPlot);2410		if (pGoodyPlot)2411		{2412			if(GC.getLogging() && GC.getAILogging())2413			{2414				CvString strLogString;2415				strLogString.Format("UnitID: %d has goody target, X: %d, Y: %d", pUnit->GetID(), pGoodyPlot->getX(), pGoodyPlot->getY());2416				LogHomelandMessage(strLogString);2417			}2418		}24192420		if(pGoodyPlot && (pGoodyPlot->isGoody(m_pPlayer->getTeam()) || (pGoodyPlot->HasBarbarianCamp()) && !pGoodyPlot->isVisibleEnemyDefender(pUnit.pointer())))2421		{2422			bool bCanFindPath = false;2423			if (pkStepPlot)	// Do we already have our first step point?2424			{2425				if (IsValidExplorerEndTurnPlot(pUnit.pointer(), pkStepPlot))2426					bCanFindPath = true;24272428				// The economic AI should recalculate next time through, but just in case, let's say that we've used the step plot2429				pEconomicAI->ClearUnitTargetGoodyStepPlot(pUnit.pointer());2430			}24312432			if (!pkStepPlot || !bCanFindPath)2433			{2434				bCanFindPath = kPathFinder.GenerateUnitPath(pUnit.pointer(), iUnitX, iUnitY, pGoodyPlot->getX(), pGoodyPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER /*iFlags*/, true/*bReuse*/);2435				if(bCanFindPath)2436				{2437					pkStepPlot = kPathFinder.GetPathEndTurnPlot();2438				}2439			}24402441			if (bCanFindPath)2442			{2443				if(pkStepPlot)2444				{2445					CvAssert(!pUnit->atPlot(*pkStepPlot));2446					if(GC.getLogging() && GC.getAILogging())2447					{2448						CvString strLogString;2449						strLogString.Format("UnitID: %d Moving to goody hut, X: %d, Y: %d, from X: %d Y: %d", pUnit->GetID(), pkStepPlot->getX(), pkStepPlot->getY(), pUnit->getX(), pUnit->getY());2450						LogHomelandMessage(strLogString);2451					}2452					pUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), pkStepPlot->getX(), pkStepPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER, false, false, MISSIONAI_EXPLORE, pkStepPlot);2453					pUnit->finishMoves();2454					UnitProcessed(pUnit->GetID());2455				}2456				else2457				{2458					if(GC.getLogging() && GC.getAILogging())2459					{2460						CvString strLogString;2461						strLogString.Format("UnitID: %d No end turn plot to goody from, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2462						LogHomelandMessage(strLogString);2463					}2464				}24652466				continue;24672468			}2469			else2470			{2471				if(GC.getLogging() && GC.getAILogging())2472				{2473					CvString strLogString;2474					strLogString.Format("UnitID: %d Can't find path to goody from, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2475					LogHomelandMessage(strLogString);2476				}2477			}2478		}24792480		CvPlot* pBestPlot = NULL;2481		int iBestPlotScore = 0;24822483#if defined(PATH_PLAN_LAST)2484		aBestPlotList.clear();2485#endif2486		TeamTypes eTeam = pUnit->getTeam();2487		int iBaseSightRange = pUnit->getUnitInfo().GetBaseSightRange();24882489		int iMovementRange = pUnit->movesLeft() / GC.getMOVE_DENOMINATOR();24902491		// if iMovesLeft value is greater than zero but not enough to be a positive integer when divided by move_denominator2492		// then just give them an extra movement. Who could it hurt, right?2493		if (pUnit->movesLeft() > 0 && iMovementRange == 0)2494		{2495			iMovementRange = 1;2496		}24972498		for(int iX = -iMovementRange; iX <= iMovementRange; iX++)2499		{2500			for(int iY = -iMovementRange; iY <= iMovementRange; iY++)2501			{2502				CvPlot* pEvalPlot = plotXYWithRangeCheck(iUnitX, iUnitY, iX, iY, iMovementRange);2503				if(!pEvalPlot)2504				{2505					continue;2506				}25072508				if(!IsValidExplorerEndTurnPlot(pUnit.pointer(), pEvalPlot))2509				{2510					continue;2511				}25122513#if !defined(PATH_PLAN_LAST)2514				bool bCanFindPath = kPathFinder.GenerateUnitPath(pUnit.pointer(), pUnit->getX(), pUnit->getY(), pEvalPlot->getX(), pEvalPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER /*iFlags*/, true/*bReuse*/);2515				if(!bCanFindPath)2516				{2517					continue;2518				}25192520				CvAStarNode* pNode = kPathFinder.GetLastNode();2521				int iDistance = pNode->m_iData2;2522				if(iDistance > 1)2523				{2524					continue;2525				}2526#endif25272528				DomainTypes eDomain = pUnit->getDomainType();2529				int iScore = CvEconomicAI::ScoreExplorePlot(pEvalPlot, eTeam, iBaseSightRange, eDomain);2530				if(iScore > 0)2531				{2532					if (eDomain == DOMAIN_LAND)2533					{2534						if (pEvalPlot->isHills())2535						{2536							iScore += 50;2537						}2538						if (pUnit->IsEmbarkAllWater() && !pEvalPlot->isShallowWater())2539						{2540							iScore += 200;2541						}2542					}2543					else if (eDomain == DOMAIN_SEA)2544					{2545						if(pUnit->canSellExoticGoods(pEvalPlot))2546						{2547							float fRewardFactor = pUnit->calculateExoticGoodsDistanceFactor(pEvalPlot);2548							if (fRewardFactor >= 0.75f)2549							{2550								iScore += 150;2551							}2552							else if (fRewardFactor >= 0.5f)2553							{2554								iScore += 75;2555							}2556						}25572558						if(pEvalPlot->isAdjacentToLand())2559						{2560							iScore += 200;2561						}2562					}25632564#if defined(PATH_PLAN_LAST)2565					aBestPlotList.push_back(pEvalPlot, iScore);2566#endif2567				}25682569#if !defined(PATH_PLAN_LAST)2570				if(iScore > iBestPlotScore)2571				{2572					pBestPlot = pEvalPlot;2573					iBestPlotScore = iScore;2574					bFoundNearbyExplorePlot = true;2575				}2576#endif2577			}2578		}25792580#if defined(PATH_PLAN_LAST)2581		uint uiListSize;2582		if ((uiListSize = aBestPlotList.size()) > 0)2583		{2584			aBestPlotList.SortItems();	// highest score will be first.2585			for (uint i = 0; i < uiListSize; ++i )	2586			{2587				CvPlot* pPlot = aBestPlotList.GetElement(i);2588				bool bCanFindPath = kPathFinder.GenerateUnitPath(pUnit.pointer(), iUnitX, iUnitY, pPlot->getX(), pPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER /*iFlags*/, true/*bReuse*/);2589				if(!bCanFindPath)2590				{2591					continue;2592				}25932594				CvAStarNode* pNode = GC.getPathFinder().GetLastNode();2595				int iDistance = pNode->m_iData2;2596				if(iDistance <= 1)2597				{2598					pBestPlot = pPlot;2599					break;2600				}2601			}2602		}2603#endif26042605		if(!pBestPlot && iMovementRange > 0)2606		{2607			FFastVector<int>& aiExplorationPlots = pEconomicAI->GetExplorationPlots();2608			if (aiExplorationPlots.size() > 0)2609			{2610				FFastVector<int>& aiExplorationPlotRatings = pEconomicAI->GetExplorationPlotRatings();26112612				aBestPlotList.clear();2613				aBestPlotList.reserve(aiExplorationPlots.size());26142615				iBestPlotScore = 0;26162617				for(uint ui = 0; ui < aiExplorationPlots.size(); ui++)2618				{2619					int iPlot = aiExplorationPlots[ui];2620					if(iPlot < 0)2621					{2622						continue;2623					}26242625					CvPlot* pEvalPlot = GC.getMap().plotByIndex(iPlot);2626					if(!pEvalPlot)2627					{2628						continue;2629					}26302631					int iPlotScore = 0;26322633					if(!IsValidExplorerEndTurnPlot(pUnit.pointer(), pEvalPlot))2634					{2635						continue;2636					}26372638					int iRating = aiExplorationPlotRatings[ui];26392640#if defined(PATH_PLAN_LAST)2641					int iDistance = plotDistance(iUnitX, iUnitY, pEvalPlot->getX(), pEvalPlot->getY());2642					int iEstimateTurns = iDistance / iMovementRange;2643					if(iEstimateTurns == 0)2644					{2645						iPlotScore = 1000 * iRating;2646					}2647					else2648					{2649						iPlotScore = (1000 * iRating) / iEstimateTurns;2650					}26512652					aBestPlotList.push_back(pEvalPlot, iPlotScore);2653#else2654					// hitting the path finder, may not be the best idea. . .2655					bool bCanFindPath = GC.getPathFinder().GenerateUnitPath(pUnit.pointer(), iUnitX, iUnitY, pEvalPlot->getX(), pEvalPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER /*iFlags*/, true/*bReuse*/);2656					if(!bCanFindPath)2657					{2658						continue;2659					}26602661					CvAStarNode* pNode = GC.getPathFinder().GetLastNode();2662					int iDistance = pNode->m_iData2;2663					if(iDistance == 0)2664					{2665						iPlotScore = 1000 * iRating;2666					}2667					else2668					{2669						iPlotScore = (1000 * iRating) / iDistance;2670					}26712672					if(iPlotScore > iBestPlotScore)2673					{2674						CvPlot* pEndTurnPlot = GC.getPathFinder().GetPathEndTurnPlot();2675						if(pEndTurnPlot == pUnit->plot())2676						{2677							pBestPlot = NULL;2678							iBestPlotScore = iPlotScore;2679						}2680						else if(IsValidExplorerEndTurnPlot(pUnit.pointer(), pEndTurnPlot))2681						{2682							pBestPlot = pEndTurnPlot;2683							iBestPlotScore = iPlotScore;2684						}2685						else2686						{2687							// not a valid destination2688							continue;2689						}2690					}2691#endif2692				}26932694#if defined(PATH_PLAN_LAST)2695				if ((uiListSize = aBestPlotList.size()) > 0)2696				{2697					aBestPlotList.SortItems();		// Highest score will be first.2698					for (uint i = 0; i < uiListSize ; ++i )	2699					{2700						CvPlot* pPlot = aBestPlotList.GetElement(i);2701						bool bCanFindPath = GC.getPathFinder().GenerateUnitPath(pUnit.pointer(), iUnitX, iUnitY, pPlot->getX(), pPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER /*iFlags*/, true/*bReuse*/);2702						if(!bCanFindPath)2703						{2704							continue;2705						}27062707						CvPlot* pEndTurnPlot = GC.getPathFinder().GetPathEndTurnPlot();2708						if(pEndTurnPlot == pUnit->plot())2709						{2710							continue;2711						}2712						else if(IsValidExplorerEndTurnPlot(pUnit.pointer(), pEndTurnPlot))2713						{2714							pBestPlot = pEndTurnPlot;2715							break;2716						}2717						else2718						{2719							// not a valid destination2720							continue;2721						}2722					}2723				}2724#endif2725			}2726		}27272728		if(pBestPlot)2729		{2730			CvAssertMsg(!pUnit->atPlot(*pBestPlot), "Exploring unit is already at the best place to explore");2731			pUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), pBestPlot->getX(), pBestPlot->getY(), MOVE_TERRITORY_NO_ENEMY | MOVE_MAXIMIZE_EXPLORE | MOVE_UNITS_IGNORE_DANGER, false, false, MISSIONAI_EXPLORE, pBestPlot);27322733			// Only mark as done if out of movement2734			if(pUnit->getMoves() <= 0)2735			{2736				UnitProcessed(pUnit->GetID());2737			}27382739			if(GC.getLogging() && GC.getAILogging())2740			{2741				CvString strLogString;2742				if(bFoundNearbyExplorePlot)2743				{2744					strLogString.Format("UnitID: %d Explored to nearby target, To X: %d, Y: %d, From X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY(), iUnitX, iUnitY);2745				}2746				else2747				{2748					strLogString.Format("UnitID: %d Explored to distant target, To X: %d, Y: %d, From X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY(), iUnitX, iUnitY);2749				}2750				LogHomelandMessage(strLogString);2751			}2752		}2753		else2754		{2755			if(pUnit->isHuman())2756			{2757				if(GC.getLogging() && GC.getAILogging())2758				{2759					CvString strLogString;2760					strLogString.Format("UnitID: %d Explorer (human) found no target, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2761					LogHomelandMessage(strLogString);2762				}2763				pUnit->SetAutomateType(NO_AUTOMATE);2764				UnitProcessed(pUnit->GetID());2765			}2766			else2767			{2768				// If this is a land explorer and there is no ignore unit path to a friendly city, then disband him2769				if(pUnit->AI_getUnitAIType() == UNITAI_EXPLORE)2770				{2771					if(GC.getLogging() && GC.getAILogging())2772					{2773						CvString strLogString;2774						strLogString.Format("UnitID: %d Explorer (AI) found no target, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2775						LogHomelandMessage(strLogString);2776					}27772778					CvCity* pLoopCity;2779					int iLoop;2780					bool bFoundPath = false;2781					for(pLoopCity = m_pPlayer->firstCity(&iLoop); pLoopCity != NULL; pLoopCity = m_pPlayer->nextCity(&iLoop))2782					{2783						if(GC.getIgnoreUnitsPathFinder().DoesPathExist(*(pUnit), pUnit->plot(), pLoopCity->plot()))2784						{2785							bFoundPath = true;2786							break;2787						}2788					}2789					if(!bFoundPath)2790					{2791						CvString strLogString;2792						strLogString.Format("UnitID: %d Disbanding explorer, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2793						LogHomelandMessage(strLogString);27942795						UnitProcessed(pUnit->GetID());2796						pUnit->kill(true);2797						m_pPlayer->GetEconomicAI()->IncrementExplorersDisbanded();2798					}2799				}2800				else if(pUnit->AI_getUnitAIType() == UNITAI_EXPLORE_SEA)2801				{2802					if(GC.getLogging() && GC.getAILogging())2803					{2804						CvString strLogString;2805						strLogString.Format("UnitID: %d Sea explorer (AI) found no target, X: %d, Y: %d", pUnit->GetID(), pUnit->getX(), pUnit->getY());2806						LogHomelandMessage(strLogString);2807					}2808				}2809			}2810		}2811	}2812}

Calls

Called by