Problem selecting an alternate unit from XML with UnitType

Lemon Merchant

Not Quite Sonic
Retired Moderator
Joined
Jun 27, 2008
Messages
8,773
Location
Red Sector A
I shudder to use the term "********", but I'm beginning to believe that I am. :(

What I'm trying to do is adapt SaibotLieh's Female Great People Mod into the SDK. I have a working Python function, but the event reporter reports the wrong name when a female GP is produced. This is the Python Function:
Spoiler :

Code:
from CvPythonExtensions import *
import CvUtil
import CvScreensInterface
import CvDebugTools
import PyHelpers
import Popup as PyPopup
import sys
import CvAdvisorUtils


gc = CyGlobalContext()
localText = CyTranslator()
PyPlayer = PyHelpers.PyPlayer
PyInfo = PyHelpers.PyInfo


def onGreatPersonBorn(argsList):
    'Unit Promoted'
    pUnit, iPlayer, pCity = argsList
    player = PyPlayer(iPlayer)
    if pUnit.isNone() or pCity.isNone():
        return
    
// BAT Code Begins

    iUnitType = pUnit.getUnitType()
    UnitInfo = gc.getUnitInfo(iUnitType)
    sUnitType = UnitInfo.getType()
    sFemaleUnitType = sUnitType+'_FEMALE'
    iFemaleUnitType = gc.getInfoTypeForString(sFemaleUnitType)
    iMaleUnitType = gc.getInfoTypeForString(sUnitType)
    UnitX = pUnit.getX()
    UnitY = pUnit.getY()
    pUnit.kill(false, iPlayer)

    if iFemaleUnitType > -1:
        Owner = gc.getPlayer(iPlayer)
        if Owner.isCivic(gc.getInfoTypeForString("CIVIC_EMANCIPATION")):
            iFemaleChance = 50
        else:
            iFemaleChance = 95  ### High value for testing.  Should be 20
                    
        iRnd = CyGame().getSorenRandNum(100, "Female unit")
        if iRnd < iFemaleChance:

            [COLOR=Blue]### Make a girl[/COLOR]
            pUnit = Owner.initUnit(iFemaleUnitType,UnitX,UnitY,UnitAITypes.NO_UNITAI,DirectionTypes.DIRECTION_SOUTH)
            szUnitName = pUnit.getName()
            pUnit.setName(szUnitName)

        else:
            [COLOR=Blue]### Or make a boy[/COLOR]
            pUnit = Owner.initUnit(iMaleUnitType,UnitX,UnitY,UnitAITypes.NO_UNITAI,DirectionTypes.DIRECTION_SOUTH)
            szUnitName = pUnit.getName()
            pUnit.setName(szUnitName)


I'm basically trying to get the same-ish code working in the SDK, without much success. (I'm having just a wee bit o' trouble with C++, so far.) I've added the following code to CvPlayer.cpp. Basically, the code checks to see if the created Great Person is a female. If not, then roll the dice and see if one is produced. There is a better chance of creating a female GP if running Emancipation, hence the Civics check. If a female GP is generated, the unit type needs to be converted from UNIT_ARTIST (for example) to UNIT_ARTIST_FEMALE. That is where I'm getting stuck, as you can see:
Spoiler :

Code:
void CvPlayer::createGreatPeople(UnitTypes eGreatPersonUnit, bool bIncrementThreshold, bool bIncrementExperience, int iX, int iY)
{
    // BAT Tweak Begin
    int FemaleChance;
        
    CvUnit* pGPTempUnit = getUnit(eGreatPersonUnit);
    CvUnitInfo& kUnit = GC.getUnitInfo(eGreatPersonUnit);  [COLOR="Blue"]// Some of this is probably redundant[/COLOR]
    CvWString szUnitType(kUnit.getType());
    PlayerTypes ePlayer = pGPTempUnit->getOwnerINLINE();

    if (!kUnit.isFemale())
    {
        CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)pGPTempUnit->getOwnerINLINE());
        int eCivicNum = GC.getInfoTypeForString("CIVIC_EMANCIPATION");
        
        if (kPlayer.isCivic((CivicTypes) eCivicNum))
        {
            FemaleChance = 50;
        }
        else
        {
            FemaleChance = 95;  [COLOR=Blue]// High value for testing purposes[/COLOR]

        int iRnd = GC.getGameINLINE().getSorenRandNum(100, "Unit female chance");
        
        if (iRnd < FemaleChance)
        {
            
            CvWString szFemaleUnitType = szUnitType + "_FEMALE";
            
            [COLOR=Blue]//Here's where it breaks.  The next line won't compile[/COLOR]
            
            int eUnitType = GC.getInfoTypeForString(szFemaleUnitType);
            
            [COLOR=Blue]// I need to be able to get the unit info for UNIT_ARTIST_FEMALE in szFemaleUnitType, and then assign it to the eGreatPersonUnit type.  But how?  int eUnitType doesn't work.[/COLOR]
            
            eGreatPersonUnit = [COLOR=Red]What goes here?  How do I assign the unit type?[/COLOR]
        }
    }
    
    // BAT Tweak End
    
    CvUnit* pGreatPeopleUnit = initUnit(eGreatPersonUnit, iX, iY);
    if (NULL == pGreatPeopleUnit)
    {
        FAssert(false);
        return;
    }

...blah, blah, blah...


I'm almost there, but I'm totally baffled. I've been at this all evening and I'm going bonkers. No matter what I do, I can't make this function work. I think it's a pointer problem, but I'm still a little fuzzy on them, and it's been a long time since I sat C courses in my college days. :crazyeye:

Can anyone help? I'm even willing to admit that I'm just a plain ol' dumb girl if someone can give me a leg up on this. :D

Thanks.
-LM
 
This:

Code:
eGreatPersonUnit = What goes here?  How do I assign the unit type?

Should be this

Code:
eGreatPersonUnit = (UnitTypes)eUnitType ;
 
It's probably a good idea to check that you got a valid unit type, too. There are a few other things that you can take advantage of to make this function simpler. None of this is right or wrong, merely shorter or stylistic. There is always at least one reason to break every guideline. :)

  1. You can get from a UnitTypes (eGreatPersonUnit) to a CvUnitInfo directly without creating a CvUnit from it.
  2. You can assign a default value to a variable and then overwrite it with a new value based on some condition.
  3. The function is part of CvPlayer so the kPlayer is unnecessary. This is the "object" in Object Oriented Programming and not an easy concept.

    I'm not positive about the line that builds the new unit type string (szFemaleUnitType) so give it a shot and see what the compiler says. Same for the call to getInfoTypeForString().

    Code:
    void CvPlayer::createGreatPeople(UnitTypes eGreatPersonUnit, bool bIncrementThreshold, bool bIncrementExperience, int iX, int iY)
    {
    // BAT - Female Great People - start
    	CvUnitInfo& kUnit = GC.getUnitInfo(eGreatPersonUnit);  // [1]
    
    	if (!kUnit.isFemale())
    	{
    		CivicTypes eCivic = (CivicTypes)GC.getInfoTypeForString("CIVIC_EMANCIPATION");
    		int iFemaleChance = 25;  // [2]
    		
    		if (isCivic(eCivic))  // [3]
    		{
    			iFemaleChance = 50;
    		}
    		iFemaleChance = 95;  // temporary high default for testing
    		
    		int iRoll = GC.getGameINLINE().getSorenRandNum(100, "Unit female chance");
    		
    		if (iRoll < iFemaleChance)
    		{
    			CvString szFemaleUnitType = kUnit.getType() + "_FEMALE";
    			int iUnitType = GC.getInfoTypeForString(szFemaleUnitType.GetCString());
    			
    			if (iUnitType != -1)
    			{
    				eGreatPersonUnit = (UnitTypes)iUnitType;
    			}
    		}
    	}
    // BAT - Female Great People - end

    Side note: I see spaces for indenting. Is that to post on the forum or are you using spaces in your actual code? If the latter, please make sure your editor is setup to use tabs instead of spaces. While mixing the two in C++ won't break the code as it will in Python, it's better to be consistent. ;)
 
And what does a girl do on a perfectly nice Wednesday evening in Dublin? Why, she holes up in her hotel room and compiles a DLL! :lol:

Thanks EF, it works now. I had to make a couple of changes, but here is the functioning code:

Code:
// BAT - Female Great People - start
    CvUnitInfo& kUnit = GC.getUnitInfo(eGreatPersonUnit);  // [1]

    if (!kUnit.isFemale())
    {
        CivicTypes eCivic = (CivicTypes)GC.getInfoTypeForString("CIVIC_EMANCIPATION");
        int iFemaleChance = 20;  // [2]
        
        if (isCivic(eCivic))  // [3]
        {
            iFemaleChance = 50;
        }
        [COLOR=Red]// Removed extra iFemaleChance assignment. [/COLOR]
        
        int iRoll = GC.getGameINLINE().getSorenRandNum(100, "Unit female chance");
        
        if (iRoll < iFemaleChance)
        {
            CvString szFUnitType = kUnit.getType();
           [COLOR=Red] CvString szFemaleUnitType = szFUnitType + "_FEMALE";[/COLOR]  [COLOR=Red]// Added because of type conversion error[/COLOR]
            int iUnitType = GC.getInfoTypeForString(szFemaleUnitType.GetCString());
            
            if (iUnitType != -1)
            {
                eGreatPersonUnit = (UnitTypes)iUnitType;
            }
        }
    }
// BAT - Female Great People - end

I'll blab more when I get back. You've been warned! :p
 
Back
Top Bottom