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}