• Civ7 is already available! Happy playing :).

Troubles with AI diplomacy code

Afforess

The White Wizard
Joined
Jul 31, 2007
Messages
12,239
Location
Austin, Texas
I have had the greatest difficulty getting some new AI diplomacy code I added to work. I added the ability for players to trade workers to other players, and it works perfectly, workers show up in the diplomacy screen and can be traded just fine, except that the AI can't use it. I'm trying to write the AI diplomacy code, but despite numerous walkthroughs, debug dll's and logging statements, I have been unable to get it to work. The AI will never contact me asking for a worker, even when I have one.

Here's my code, it's a bit long. For testing purposes, the Contact and Rand Contact values are set to 1 in the XML so the AI SHOULD be contacting me every turn.

Code:
void CvPlayerAI::AI_doDiplo()
{
...

                                        if (GET_TEAM(getTeam()).getLeaderID() == getID())
                                        {
                                            if (AI_getContactTimer(((PlayerTypes)iI), CONTACT_TRADE_WORKERS) == 0)
                                            {
                                                if (GC.getGameINLINE().getSorenRandNum(GC.getLeaderHeadInfo(getPersonalityType()).getContactRand(CONTACT_TRADE_WORKERS), "AI Diplo Trade Workers") == 0)
                                                {
                                                    CvUnit* pWorker;
                                                    CvUnit* pTempUnit;
                                                    bool bFirst = false;
                                                    bool bFoundWorker = false;
                                                    int iNeededWorkers = 0;
                                                        
                                                    //figure out if we need workers or not. Logging statements show that the code always makes it this far
                                                    for (CvArea* pLoopArea = GC.getMapINLINE().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMapINLINE().nextArea(&iLoop))
                                                    {
                                                        if (pLoopArea->getCitiesPerPlayer(getID()) > 0)
                                                        {
                                                            iNeededWorkers += AI_neededWorkers(pLoopArea);
                                                        }
                                                    }
                                                    //if we need workers
                                                    //logging shows that the code gets here safely...
                                                    if (iNeededWorkers > 0)
                                                    {//Please tell me there must be a more efficient way to do this....
                                                        for (CvUnit* pLoopUnit = firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = nextUnit(&iLoop))
                                                        {
                                                            if (pLoopUnit->canTradeUnit(getID()))
                                                            {
                                                                setTradeItem(&item, TRADE_WORKER, pLoopUnit->getID());
                                                                //if they can trade the worker to us
                                                                //The code can not seem to make it past this part, commenting it out helps, but it snags elsewhere too
                                                                if (GET_PLAYER((PlayerTypes)iI).canTradeItem(getID(), item, true))
                                                                {
                                                                    if (!bFirst)
                                                                    {
                                                                        bFirst = true;
                                                                        pTempUnit = pLoopUnit;
                                                                    }
                                                                    if (AI_workerTradeVal(pLoopUnit) > AI_workerTradeVal(pTempUnit))
                                                                    {
                                                                        pTempUnit = pLoopUnit;
                                                                        bFoundWorker = true;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        if (bFoundWorker)
                                                        {
                                                            pWorker = pTempUnit;
                                                            if (pWorker != NULL)
                                                            {
                                                                iTheirValue = AI_workerTradeVal(pWorker);
                                                                iGold = (GET_PLAYER((PlayerTypes)iI).AI_maxGoldTrade(getID()));
                                                                if (iGold >= iTheirValue && iTheirValue > 0)
                                                                {
                                                                    setTradeItem(&item, TRADE_GOLD, iTheirValue);
                                                                    //if we can trade the gold to them
                                                                    if (canTradeItem((PlayerTypes)iI, item, true))
                                                                    {
                                                                        ourList.clear();
                                                                        theirList.clear();

                                                                        setTradeItem(&item, TRADE_GOLD, iTheirValue);
                                                                        ourList.insertAtEnd(item);
                                                                            
                                                                        setTradeItem(&item, TRADE_WORKER, pWorker->getID());
                                                                        theirList.insertAtEnd(item);

                                                                        if (GET_PLAYER((PlayerTypes)iI).isHuman())
                                                                        {
                                                                            if (!(abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()]))
                                                                            {
                                                                                AI_changeContactTimer(((PlayerTypes)iI), CONTACT_TRADE_WORKERS, GC.getLeaderHeadInfo(getPersonalityType()).getContactDelay(CONTACT_TRADE_WORKERS));
                                                                                pDiplo = new CvDiploParameters(getID());
                                                                                FAssertMsg(pDiplo != NULL, "pDiplo must be valid");
                                                                                pDiplo->setDiploComment((DiploCommentTypes)GC.getInfoTypeForString("AI_DIPLOCOMMENT_OFFER_DEAL"));
                                                                                pDiplo->setAIContact(true);
                                                                                pDiplo->setOurOfferList(theirList);
                                                                                pDiplo->setTheirOfferList(ourList);
                                                                                AI_beginDiplomacy(pDiplo, (PlayerTypes)iI);
                                                                                abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()] = true;
                                                                            }
                                                                            else
                                                                            {
                                                                                GC.getGameINLINE().implementDeal(getID(), ((PlayerTypes)iI), &ourList, &theirList);
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }

In order to figure out what's going on, you will probabily need to see the CanTradeItem(...) function code for workers, here's that:

Code:
case TRADE_WORKER:
        {
            pUnitTraded = getUnit(item.m_iData);
            pTheirCapitalCity = GET_PLAYER(eWhoTo).getCapitalCity();
            if (GC.getGameINLINE().isOption(GAMEOPTION_ADVANCED_DIPLOMACY))
            {
                if (GET_TEAM(getTeam()).isHasEmbassy(GET_PLAYER(eWhoTo).getTeam()))
                {
                    if (pUnitTraded != NULL)
                    {
                    //    pTradingCity = pUnitTraded->plot()->getPlotCity();
                        if (GC.getUnitInfo(pUnitTraded->getUnitType()).isWorkerTrade() && pUnitTraded->canMove()/* && (pTradingCity != NULL) */&& (pTheirCapitalCity != NULL))
                        {
                        //    if (pTradingCity->getOwnerINLINE() == getID())
                        //    {
                            //    if (pTradingCity->isConnectedTo(pTheirCapitalCity))
                            //    {
                            //        if (pTradingCity->isRevealed(GET_PLAYER(eWhoTo).getTeam(), true))
                            //        {
                                        if (!GET_TEAM(GET_PLAYER(eWhoTo).getTeam()).isUnitClassMaxedOut(pUnitTraded->getUnitClassType(), GET_TEAM(GET_PLAYER(eWhoTo).getTeam()).getUnitClassMaking(pUnitTraded->getUnitClassType())))
                                        {
                                            if (!GET_PLAYER(eWhoTo).isUnitClassMaxedOut(pUnitTraded->getUnitClassType(), GET_PLAYER(eWhoTo).getUnitClassMaking(pUnitTraded->getUnitClassType())))
                                            {
                                                return true;
                                            }
                                        }
                                //    }
                                //}
                        //    }
                        }
                    }
                }
            }
        }
        break;

I commented a large part out because I decided I didn't care for it.

Also, canTradeUnit() is a custom function. Here is that:

Code:
bool CvUnit::canTradeUnit(PlayerTypes eReceivingPlayer)
{
    CvArea* pWaterArea = NULL;
    CvCity* pCapitalCity;
    int iLoop;
    bool bShip = false;
    bool bCoast = false;

    pCapitalCity = GET_PLAYER(eReceivingPlayer).getCapitalCity();

    if (eReceivingPlayer == NO_PLAYER || eReceivingPlayer > MAX_PLAYERS)
    {
        return false;
    }
    
    if (getCargo() > 0)
    {
        return false;
    }
    
    if (getDomainType() == DOMAIN_SEA)
    {
        bShip = true;
        for (CvCity* pLoopCity = GET_PLAYER(eReceivingPlayer).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(eReceivingPlayer).nextCity(&iLoop))
        {
            if (((pWaterArea = pLoopCity->waterArea()) != NULL && !pWaterArea->isLake()))
            {
                bCoast = true;
            }
        }
    }
    
    if (bShip && !bCoast)
    {
        return false;
    }

    return true;
}

Since workers are land units, it should be turning up true every time, but I added it just to be thorough, in case someone ever made workboats tradable.

I would be extremely appreciative if someone could spot my error in the Diplomacy code.
 
Top Bottom