1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

[Warlords] How to set a city goal

Discussion in 'Civ4 - Creation & Customization' started by Paolo80, Dec 26, 2019.

  1. Paolo80

    Paolo80 Chieftain

    Joined:
    Dec 20, 2019
    Messages:
    41
    Gender:
    Male
    Hi guys,

    I have a question on modding.

    I want to force units (not only human player, but also AI players) to attack a specific city. In other words I want every player try to conquest the same city.

    How can I do? I have to modify some python files?

    Thanks everyone for help
     
  2. f1rpo

    f1rpo plastics

    Joined:
    May 22, 2014
    Messages:
    735
    Location:
    Germany
    Some of the XML files contain values that guide AI decisions, e.g. "iAIWeight" and "iFlavor". Apart from that, AI behavior is handled almost exclusively by the DLL (in this case mainly AI_findTargetCity, AI_targetCityValue in CvGameCoreDLL\CvPlayerAI.cpp), with only a handful of functions exposed to Python (I think just those at the end of Warlord’s CyPlayerInterface1.cpp). Without modifying (and recompiling) the DLL, I’m afraid you could only give that specific city (Rome, I gather from your other posts) a high population, many wonders and resources; holy city should also help. However, the AI will probably still prefer targeting nearby cities. Getting the AI into a war with the Roman Empire probably isn't that difficult; the scenario can set at-war status initially, or the Romans could be a minor civ perpetually at war with everyone.
     
  3. Paolo80

    Paolo80 Chieftain

    Joined:
    Dec 20, 2019
    Messages:
    41
    Gender:
    Male
    Maybe I could set an high city value. In other words, I could set the city x,y score 1000 or 10000 to force AI to attack it. Is it possible changing only python files? Maybe I could set an high city population and fix it for all the game turns.
     
    Last edited: Jan 2, 2020
  4. f1rpo

    f1rpo plastics

    Joined:
    May 22, 2014
    Messages:
    735
    Location:
    Germany
    You can set a high initial population through the scenario file, or set the population at any time through Python. E.g. in onBeginPlayerTurn (CvEventManager.py), you could use a line like:
    gc.getPlayer(iPlayer).getCapitalCity().setPopulation(30)
    I haven't tested that; and you'd need a condition that checks whether iPlayer is the Romans. Maybe just
    if iPlayer == 1:
    if the Romans are in player slot 1.
    I think 1 population increases the target value by 0.75 on average:
    Code:
    iValue += ((pCity->getPopulation() * (50 + pCity->calculateCulturePercent(getID()))) / 100);
    I.e. population counts half if the attacker has 0 city culture. And at the end:
    Code:
    if (bRandomize)
    {
       iValue += GC.getGameINLINE().getSorenRandNum(((pCity->getPopulation() / 2) + 1), "AI Target City Value");
    }
    bRandomize is true except when computing the trade value of a city. So this adds a random number between 1 and 0.5*population. You could probably set a high city culture value for each player, but since the DLL code uses the culture percentage, that wouldn’t really help.

    I’ve just noticed that multiple wonders don’t actually increase the target value:
    Code:
    if (pCity->hasActiveWorldWonder())
    {
       iValue += 2;
    }
    This has been improved in BtS:
    Code:
    if (pCity->hasActiveWorldWonder())
    {
       iValue += 1 + pCity->getNumWorldWonders();
    }
    So, for BtS, one could create numerous wonders in XML that have no abilities and give Rome all those dummy wonders. However, even BtS counts just +1 for each wonder ...

    For Warlords, a resource without abilities could work:
    Code:
    for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
    {
       pLoopPlot = plotCity(pCity->getX_INLINE(), pCity->getY_INLINE(), iI);
       if (pLoopPlot != NULL)
       {
          if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
          {
             iValue++;
          }
    The getBonusType call checks whether the resource is revealed to the attacker. But the human player isn’t supposed to see them. One could let all AI civs start with a new technology that merely reveals the dummy resource and cannot be researched. The tech and resource would probably appear in Civilopedia though.

    One last idea: This condition
    Code:
    if (pCity->isEverOwned(getID()))
    {
       iValue += 3;
    }
    could perhaps be made true through a Python call to CyPlayer.acquireCity for another +3 target value.

    Even if the AI does choose Rome as its target city, AI city attackers may still end up attacking other cities along their path to Rome; but I guess that isn’t necessarily a bad thing.
     
  5. Paolo80

    Paolo80 Chieftain

    Joined:
    Dec 20, 2019
    Messages:
    41
    Gender:
    Male
    About last condition isEverOwned, could you write me python code to made true through ìCyPlayer.acquireCity?
     
  6. f1rpo

    f1rpo plastics

    Joined:
    May 22, 2014
    Messages:
    735
    Location:
    Germany
    Not easily. I don't normally use Python for this sort of thing. :(
    A quick, naive attempt (in CvEventManager.py):
    Code:
    def onBeginGameTurn(self, argsList):
           'Called at the beginning of the end of each turn'
           iGameTurn = argsList[0]
           if iGameTurn == 0:
               romans = gc.getPlayer(1) # Assumes that the Romans have player id 1
               romanCapital = romans.getCapitalCity()
               for i in range(gc.getMAX_CIV_PLAYERS()):
                   p = gc.getPlayer(i)
                   if p.isAlive() and i != romans.getID():
                       p.acquireCity(romanCapital, False, True)  # bConquest=False, bTrade=True
               romans.acquireCity(romanCapital, False, True)
    A lot of things could be wrong with this. The syntax might be incorrect; it might kill the Romans (it shouldn't if they start with multiple cities); I'm not sure if the scenario setup is already complete at the start of game turn 0; acquiring the city will probably trigger your victory condition (that could hopefully be fixed by adding "not bTrade" to the victory check); the owner changes might look weird to the human player or even crash; the Roman capital will move (will have to move the Palace back to Rome through CyCity.setHasRealBuilding). I guess, as a starting point, it's better than nothing. A more experienced Python modder could probably improvise something better. Still, I expect that this will require some experimentation and might not work at all in the end.
     
  7. Paolo80

    Paolo80 Chieftain

    Joined:
    Dec 20, 2019
    Messages:
    41
    Gender:
    Male
    I wrote this code:

    pCity1 = CyMap().plot(32, 23)

    if iGameTurn == 1:
    for cPlayer in range(gc.getMAX_PLAYERS()):
    pPlayer = gc.getPlayer(cPlayer)
    if pPlayer.isAlive() and cPlayer != 4:
    pPlayer.acquireCity(pCity1, False, True)​
    gc.getPlayer(4).acquireCity(pCity1, False, True)​

    But this gives me a python argument error.

    What's the mistake?
     
  8. f1rpo

    f1rpo plastics

    Joined:
    May 22, 2014
    Messages:
    735
    Location:
    Germany
    I'd try:
    pCity1 = CyMap().plot(32, 23).getPlotCity()
     
  9. Paolo80

    Paolo80 Chieftain

    Joined:
    Dec 20, 2019
    Messages:
    41
    Gender:
    Male
    I tried to force AI attack city using function CyTeam.AI_setWarPlan. Here the code:

    PHP:
    for iPlayer in range(gc.getMAX_PLAYERS()):
                
    player gc.getPlayer(iPlayer)
                print(
    player)
                 
    iTeam player.getTeam()
                print(
    iTeam)
                        
    pTeam gc.getTeam(iTeam)
                print(
    pTeam)
                 
    pTeam.AI_setWarPlan(playerWarPlanTypes.WARPLAN_TOTAL)
    But when I start the game, it gets this python error: "AttributeError: 'CyTeam' object has no attribute 'AI_setWarPlan'". It seems that AI_setWarPlan isn't defined. What's the mistake?
     
  10. f1rpo

    f1rpo plastics

    Joined:
    May 22, 2014
    Messages:
    735
    Location:
    Germany
    That function isn't exposed to Python; in particular, it's not in CyTeamInterface.cpp. declareWar is in there, but it looks like that will result in WARPLAN_DOGPILE.
     

Share This Page