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

Quick Modding Questions Thread

Discussion in 'Civ4 - Creation & Customization' started by kiwitt, Jan 27, 2010.

  1. Mouthwash

    Mouthwash Escaped Lunatic

    Joined:
    Sep 26, 2011
    Messages:
    9,053
    Location:
    Hiding
    Can someone explain how to merge the GEM mod and BUG (less urgently, BAT)? Genghis_Kai's guide was very straightforward, easy to follow, and doesn't work. The UI is completely missing.

    Also, I switched around literature and drama on the tech tree (so that literature leads to philosophy and drama to music), but that doesn't seem to affect their physical location on it; their paths just awkwardly cross one another. How do I do this?
     
    Last edited: Nov 4, 2019
  2. Zeta Nexus

    Zeta Nexus N E X U S

    Joined:
    Jan 23, 2014
    Messages:
    3,441
    Location:
    In a constant brainstorm...
    I can answer this 2nd part only:
    Each tech has X and Y coordinates in TechInfo.xml. You have to edit those.
     
  3. LPlate2

    LPlate2 Chieftain

    Joined:
    Dec 27, 2018
    Messages:
    60
    Hi,

    I'm getting an error from this assert,
    Spoiler :
    Code:
    void CvPlayer::changeBuildingClassMaking(BuildingClassTypes eIndex, int iChange)
    {
       FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
       FAssertMsg(eIndex < GC.getNumBuildingClassInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
    
       if (iChange != 0)
       {
           m_paiBuildingClassMaking[eIndex] = (m_paiBuildingClassMaking[eIndex] + iChange);
           FAssert(getBuildingClassMaking(eIndex) >= 0);
    
           if (getID() == GC.getGameINLINE().getActivePlayer())
           {
               gDLL->getInterfaceIFace()->setDirty(Help_DIRTY_BIT, true);
           }
       }
    }


    when I trigger pNamePlayer.acquireCity(pCity,false,false) based on onBuildingBuilt.
    How do I fix it so this is not a problem?
    What is the meaning of the last two entries in acquireCity, i.e. the false, false above?

    -----------------------------
    I get a similar assert error,
    Spoiler :

    Assert Failed

    File: .\.\CvPlayer.cpp
    Line: 11988
    Expression: getUnitClassMaking(eIndex) >= 0
    Message:

    when I trigger acquireCity based on onUnitBuilt.

    It suggests to me that my problem is that after the building/unit is built, the relevant production queue is empty and this is causing the error when acquirecity tries to run.
    How do I avoid these errors?
     
    Last edited: Nov 9, 2019
  4. Zeta Nexus

    Zeta Nexus N E X U S

    Joined:
    Jan 23, 2014
    Messages:
    3,441
    Location:
    In a constant brainstorm...
    So there is this popup after discovering a tech that asks you if you want to change to the newly available civic. Can I disable this popup somehow?
     
  5. LPlate2

    LPlate2 Chieftain

    Joined:
    Dec 27, 2018
    Messages:
    60
    Look in the CivilizationIV.ini file for NoTechSplash

    ; Set to 1 for no tech splash screens
    NoTechSplash = 1
     
  6. lfgr

    lfgr King

    Joined:
    Feb 6, 2010
    Messages:
    716
    @LPlate2

    I assume you get the third assert ("FAssert(getBuildingClassMaking(eIndex) >= 0);") in your first example.
    My theory is the following:
    acquireCity() actually removes (via CvCity::kill()) the city and replaces it with a new one. onBuildingBuilt is called from CvCity::popOrder(), which also does some other stuff with the city after calling onBuildingBuilt. However, as the city is already destroyed via acquireCity(), the game tries to access garbage memory. However, I'm not completely sure why changeBuildingClassMaking() is called after onBuildingBuilt.

    So you probably simply can't change the owner of a city in onBuildingBuilt (in the same city), you have to do it via some workaround. For example, when you build the Mercurian Gate in FfH, the Mercurians don't get that city directly. Instead, Basium (the unit) has a "convert city" spell for the mercurian gate city that the AI always uses immediately.
     
  7. Zeta Nexus

    Zeta Nexus N E X U S

    Joined:
    Jan 23, 2014
    Messages:
    3,441
    Location:
    In a constant brainstorm...
    Are you refering to this popup?
    Spoiler :
     
  8. lfgr

    lfgr King

    Joined:
    Feb 6, 2010
    Messages:
    716
    Looks like you have to mod the DLL to suppress that popup. Look for BUTTONPOPUP_CHANGECIVIC in CvTeam::setHasTech().
     
  9. Zeta Nexus

    Zeta Nexus N E X U S

    Joined:
    Jan 23, 2014
    Messages:
    3,441
    Location:
    In a constant brainstorm...
    Thx! At least I know I cannot do that :shake:
     
  10. LPlate2

    LPlate2 Chieftain

    Joined:
    Dec 27, 2018
    Messages:
    60
    Thanks @Ifgr, I'll create a temporary building in the city, when the condition is met and then apply the acquirecity at the start of a player's turn, if the city has that building. That should work to avoid my issue with onBuildingBuilt and onUnitBuilt.
     
  11. Unendingfear

    Unendingfear Chieftain

    Joined:
    Dec 28, 2010
    Messages:
    34
    Location:
    Nowhere
    How do I go about getting a building to modify the value of terrain that isn't water/river tiles? I'm very new to modding Civ IV and I've been combing through the code but I haven't been able to find any similarly functioning lines. I had no issue working it in Civ V (IE. copy code from the Petra), but I can't quite seem to find anything that functions in that way for IV. Specifically, I'm trying to create a special civilization for a personal mod, and I want to add a monument replacement that adds + 1 :food: to snow and tundra tiles. Is this even possible in the Civ IV engine?
     
  12. Zeta Nexus

    Zeta Nexus N E X U S

    Joined:
    Jan 23, 2014
    Messages:
    3,441
    Location:
    In a constant brainstorm...
    Not, if you can mod only xml stuff.
    Yes, if you can work with the dll.
    Maybe python is sufficient too but I doubt.
     
    Unendingfear likes this.
  13. Unendingfear

    Unendingfear Chieftain

    Joined:
    Dec 28, 2010
    Messages:
    34
    Location:
    Nowhere
    Okay thanks for clarifying. I'm only familiar with xml editing.
     
  14. LPlate2

    LPlate2 Chieftain

    Joined:
    Dec 27, 2018
    Messages:
    60
    Hi,

    Couple of questions:
    1) What python command do I use in order to make information appear in the Event Log, in the top left of the screen?
    2) What python command do I use to have information appear in the end of game report?
     
  15. Vokarya

    Vokarya Deity

    Joined:
    Mar 25, 2011
    Messages:
    6,115
    I use CyInterface().addMessage to generate messages that appear both on-screen and in the event log.

    I have never tried to add information to the end-of-game report. The Revolutions mod uses CyGame().addreplaymessage but I don't see that function in the Python Class Reference so it might have been added to the DLL and so whether or not you can actually use it will depend on what DLL you are using.
     
  16. LPlate2

    LPlate2 Chieftain

    Joined:
    Dec 27, 2018
    Messages:
    60
    Hi,

    I am using CyInterface().addMessage but this is only giving me the onscreen messages (which do not last).
    Code:
                   CyInterface().addMessage(CyGame().getActivePlayer(),True,10,"%s" %(myResult),'',1,'',ColorTypes(8),-1,-1,True,True)
    
    Do I need to set one or more of the True to False, to get the messages to appear on the Event Log or change one of the -1 values?

    ---
    I'm also open to modding the DLL I use, if someone can advise where to edit to get information included in the final game reports.
     
  17. lfgr

    lfgr King

    Joined:
    Feb 6, 2010
    Messages:
    716
  18. Vokarya

    Vokarya Deity

    Joined:
    Mar 25, 2011
    Messages:
    6,115
    This is the Python line that I include when I am trying to debug Python code:
    Code:
    CyInterface().addMessage(iPlayer, True, 2, str(), None, 0, None, ColorTypes(44), 0, 0, True, True)
    I am generally using this with an onBuildingBuilt trigger so iPlayer is already defined as pCity.getOwner(). The message goes in quotes between the parentheses after str.
     
  19. LPlate2

    LPlate2 Chieftain

    Joined:
    Dec 27, 2018
    Messages:
    60
    That did it. Thanks.
     
  20. Leoreth

    Leoreth 心の怪盗団 Moderator

    Joined:
    Aug 23, 2009
    Messages:
    33,378
    Gender:
    Male
    Location:
    Leblanc
    How do I correctly expose an AI method in the DLL to Python?

    Specifically, I want to expose CvPlayerAI::AI_getAttitudeVal(PlayerTypes ePlayer, boolean bForced). I cannot simply call it in a CyPlayer wrapping method because it is not a member of CvPlayer. I see that other exposed AI methods, such as CvPlayerAI::AI_getAttitude(PlayerTypes ePlayer, boolean bForced), have been added to CvPlayer.h with the "virtual" keyword and then set to 0. I assume this is to let the compiler know that the implementation will be supplied later by CvPlayerAI instead.

    However, if I add
    Code:
    virtual int AI_getAttitudeVal(PlayerTypes ePlayer, boolean bForced = false) const = 0;
    to CvPlayer.h then loading a savegame crashes with a read access violation. As of writing this I realised that I never started a new game after this change, but even when just making this simple change (i.e. no other changes compared to a working DLL) I get a crash on load. Is it a save compatibility thing? Regardless I am surprised by this behaviour. Can someone explain?
     
  21. devolution

    devolution Prince

    Joined:
    Oct 7, 2016
    Messages:
    321
    Gender:
    Male
    Location:
    Stavanger, Norway
    Hi @Leoreth

    I don't think we can add a new virtual to CvPlayer.h since that would affect the memory layout of the DLL in way that the exe can't deal with (pure virtual or not does not matter). Since CvPlayerAI is derived from CvPlayer, a new virtual chain in CvPlayer would have to "shift and\or expand the vtable, depending on number and relative positioning of the new virtuals" (kludgy explanation, I know). We could have done this if we could recompile the exe but for now we are stuck with the fixed offsets in the CvPlayer(AI) vtable that the exe knows about and knows how to call correctly.

    See these commit from @f1rpo for a "cleaner" workaround with respect to separating game mechanics and AI:
    https://github.com/f1rpo/AdvCiv/commit/3028ffa87b59a735f369fabe624741a377e02c0e
    https://github.com/f1rpo/AdvCiv/commit/fedca1cf525955e008cfd75ce5ae3dd68de17570

    You can freely add non-virtual member functions to CvPlayer though.

    When implementing new AI features a common workaround for not having the ability to add virtual functions is to static_cast the pointer or reference from CvPlayer to CvPlayerAI. We can safely perform this downcast since all CvPlayer instances actually are CvPlayerAI instances even if we have "the wrong pointer\reference" in any given context. This will give you access to new functionality that is implemented in CvPlayerAI without requiring new virtual functions in the ancestor class. It is ugly, I agree but those are the cards that we've been dealt :(

    TL;DR summary:

    - Put your python wrapper in CvPlayer and expose it to python
    - The wrapper downcasts CvPlayer to CvPlayerAI and invokes AI_getAttitudeVal(...)
    - The wrapper returns the result to your python method
     
    Last edited: Nov 20, 2019

Share This Page