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

[PYTHON] Python Newbie Question

Discussion in 'Civ4 - SDK/Python' started by OzzyKP, Jun 16, 2019.

  1. OzzyKP

    OzzyKP Emperor

    Joined:
    Dec 16, 2000
    Messages:
    1,721
    Location:
    Washington, DC USA
    I'm making my first attempt to do something in Python and... I'm lost.

    I'd like to have a worker created, owned by a particular AI civ when a corporation spreads to a city. My hope is to have corporations spread & operate independently, and have them build rail lines on their own.

    I have never done anything in Python before (or much coding period), so I'd love some advice & help. This is the best I've come up with:

    Code:
        def onCorporationSpread(self, argsList):
            'Corporation Has Spread to a City'
            iCorporation, iOwner, pSpreadCity = argsList
            iRailCorp = gc.getInfoTypeForString('CORPORATION_1')
            player = PyPlayer(iOwner)
        
            if iCorporation == iRailCorp
                CyInterface().addImmediateMessage("Railroad Corp has expanded into your city and will get to work building the rails", "")
                newUnit = playerY.initUnit(gc.getInfoTypeForString('UNIT_WORKER'), UnitAITypes.NO_UNITAI)
    
    At this point I was just hoping to spawn a unit to show that I could make Python do anything at all, I hadn't even begun to worry about assigning it to a certain player. I copy and pasted pieces from other mods, and I've tried it a few different ways, but nothing ever happens. Clearly I'm missing some basic understanding of python.

    On the plus side, nothing crashes! It just doesn't do anything.
     
  2. devolution

    devolution Prince

    Joined:
    Oct 7, 2016
    Messages:
    432
    Gender:
    Male
    Location:
    Stavanger, Norway
    Are you sure that the callback is even triggering ? Which mod (or perhaps "stock" BTS) are you using ?
     
  3. OzzyKP

    OzzyKP Emperor

    Joined:
    Dec 16, 2000
    Messages:
    1,721
    Location:
    Washington, DC USA
    Heh, im such a newbie I don’t know what your first sentence even means. But no, I’m not sure if anything.

    I added this to my Fractured States mod which I don’t think has any other python changes, just XML so far.
     
  4. Spillsandstains

    Spillsandstains Warlord

    Joined:
    Mar 31, 2008
    Messages:
    234
    newUnit = playerY.initUnit

    I know more about the geography of the planetary mantle than I do python, but isn't "playerY" wrong; it's declared as just "player" above
     
  5. OzzyKP

    OzzyKP Emperor

    Joined:
    Dec 16, 2000
    Messages:
    1,721
    Location:
    Washington, DC USA
    Hmm, good question. I don't know, I pulled the code from somewhere but I really don't understand it. You suggest changing "
    newUnit = playerY.initUnit(gc.getInfoTypeForString('UNIT_WORKER'), UnitAITypes.NO_UNITAI)" to "
    newUnit = PyPlayer.initUnit(gc.getInfoTypeForString('UNIT_WORKER'), UnitAITypes.NO_UNITAI)" ?

    I guess I could try the other way around too. *shrug* I'll give it a shot. Dropping the term "declared" means you know more about python than I do, heh, so blind ol' Ozzy will accept your one-eyed advice.
     
  6. Spillsandstains

    Spillsandstains Warlord

    Joined:
    Mar 31, 2008
    Messages:
    234
    yeah give it a try old bean! hope it works then I can nick it. either way round will work I think, "player = PyPlayer(iOwner)" bit is making a thingy* the game recognizes into a quick and easy reference ("player") for you to work with, but you have to keep it consistent.

    *this is real computer terminology innit
     
  7. f1rpo

    f1rpo plastics

    Joined:
    May 22, 2014
    Messages:
    935
    Location:
    Germany
    I don't program much in Python, but since no experienced Python modder is answering (anymore) and I see a few problems ... here goes:

    There's a colon missing:
    if iCorporation == iRailCorp
    -->
    if iCorporation == iRailCorp:

    The indentation has to be tabs only. (It probably is; the forum converts tabs to spaces.)

    initUnit indeed needs to be called on the player object:
    player.initUnit(...
    The documentation string in CyPlayerInterface1.cpp says that the function requires these four arguments
    UnitTypes iIndex, plotX, plotY, UnitAITypes iIndex
    and that this will
    "place Unit at X,Y"
    and:
    "NOTE: Always use UnitAITypes.NO_UNITAI"
    So it would have to be:
    player.initUnit(gc.getInfoTypeForString("UNIT_WORKER"), pSpreadCity.getX(), pSpreadCity.getY(), UnitAITypes.NO_UNITAI)

    In a quick test, addImmediateMessage briefly showed me an on-screen message but didn't store it in the Event Log. For proper UI support, I'd use (all in one line):
    CyInterface().addMessage(iOwner, True, gc.getEVENT_MESSAGE_TIME(), "Railroad Corp has expanded into your city and will get to work building the rails", "", InterfaceMessageTypes.MESSAGE_TYPE_INFO, gc.getUnitInfo(gc.getInfoTypeForString("UNIT_WORKER")).getButton(), gc.getInfoTypeForString("COLOR_WHITE"), pSpreadCity.getX(), pSpreadCity.getY(), True, True)
    Several examples for how to use addMessage can be found in EntryPoints\CvRandomEventInterface.py, also for how to load the text from a game text XML file with translations. See the Python API for the (in some cases) self-explanatory argument names.
    This will show the message to all human players, but I guess you only want to show it to the city owner if that player happens to be human, so
    if iOwner == gc.getActivePlayer().getID():
    should be checked beforehand.

    For tracing/ debugging, addImmediateMessage could be useful, though easy to miss. Alternatives: CvUtil.pyPrint("hello") or simply print("hello"), which write to PythonDbg.log.
    Errors are written to PythonErr.log, provided that LoggingEnabled = 1 is set in My Games\Beyond the Sword\CivilizationIV.ini. (I think that's the only setting needed for Python logs, but I'm not quite sure.) The Logs folder should also be in My Games\Beyond the Sword.

    I've tested the above in a BUG-based mod by adding the code to CvEventManager.py (as I think you did too). The recommended way for adding event handlers with BUG is a bit more complicated (through an XML file in BUG's Config folder instead of changing CvEventManager.py), but I haven't really used that myself and it can be changed at some later point.
     
  8. Dancing Hoskuld

    Dancing Hoskuld Deity

    Joined:
    Jul 5, 2004
    Messages:
    23,544
    Gender:
    Male
    Location:
    Canberra, Australia
    It doesn't need to be tabs but it must be exactly whatever is used for indentation elsewhere in that bit code.

    We had a problem where 3 spaces were used for indentation but one of the programmers used tabs which were also 3 spaces on their machine so the code looked fine but the tab size on the player's machine was different so the Python did not work on their machine. It took ages to discover that was the problem :lol:
     
    f1rpo likes this.
  9. Nightinggale

    Nightinggale Deity

    Joined:
    Feb 2, 2009
    Messages:
    4,580
    Notepad++. View->Show Symbols->Show White Space and TAB.

    It's not that I turn it on when there is a problem. Instead I never turn it off. Experience have told me it's the best way to save time when hunting annoying bugs like the one mentioned here.
     

Share This Page