Need help merging

You said you tried the third file (which is the correct one to use), and it's now giving you an entirely new error. This is good. I posted the fix for that error, but now you want to go back to the first error which is gone? I'm confused. :confused:


Actually i am more confused, no offense, am i supposed to take the NUMBER back out of the thingy as in post # 50?:crazyeye:
 
You're getting there! I can see how this can be somewhat confusing if the terminology and coding are all new.

You want to use the third file and leave the NUMBER in there. I think the poster in post 50 misunderstood what was going on, you need something in the number slot to specify what unit AI to give the new unit.

You could think about the function as one of those coin operated washing machines which requires a bunch of quarters to slid in at once (see here if you don't know what I'm talking about). In this case, you have to place something in each of the five slots required by the function, and in this case they need to be five things of particular types ... so you can only put a "quarter" in the first slot, the second and third have to be "dimes", etc. If you put in the right five things, then the code will run and you'll get a shiny unit out.
 
You're getting there! I can see how this can be somewhat confusing if the terminology and coding are all new.

You want to use the third file and leave the NUMBER in there. I think the poster in post 50 misunderstood what was going on, you need something in the number slot to specify what unit AI to give the new unit.

OK then # 3 it is, then were back to post # 49??:(

Now i still need help guys, thx so far.
 
You want to use the third file and leave the NUMBER in there. I think the poster in post 50 misunderstood what was going on, you need something in the number slot to specify what unit AI to give the new unit.

:confused: but the API says, that it needs a type of unitAI, and not an int.

OK then # 3 it is, then were back to post # 49??:(

Now i still need help guys, thx so far.

Why do you not take the last file from #57?
 
:confused: but the API says, that it needs a type of unitAI, and not an int.



Why do you not take the last file from #57?

Main reason was jdog5000 said the number was supposed to be there, and i think he wrote the code alooong time ago.:confused: He's been too busy with the Unofficial patch stuff and cant help out as much anymore. He said he has been monitoring this thread, and looks like you guys are right on the money, its just going to take alittle longer. (I hope less).
 
Things like UnitAITypes and DirectionTypes are represented in C++ as integers (numbers) constrained to a specific set of values. Each value is given a name (constant), and these show up in Python as objects. When C++ wants one of these values, you must use the Python constants and not the numbers AFAIK.

So instead of 3 for the fourth parameter you need to use UnitAITypes.UNITAI_WORKER.
 
Things like UnitAITypes and DirectionTypes are represented in C++ as integers (numbers) constrained to a specific set of values. Each value is given a name (constant), and these show up in Python as objects. When C++ wants one of these values, you must use the Python constants and not the numbers AFAIK.

So instead of 3 for the fourth parameter you need to use UnitAITypes.UNITAI_WORKER.

OK, 3 should be worker, what about 1 or 2?

One that really puzzles me is lines like this:

Code:
if( not iCounter == UnitTypes.NO_UNIT ) : pyNewPlayer.initUnit(iCounter,cityX,cityY,2+game.getSorenRandNum(5+extraUnits,'BarbarianCiv: give military infantry'),DirectionTypes.DIRECTION_NORTH)

what would i do in these cases?
 
You can find the other values at the Python API. In the bottom-left frame click Type List and then scroll down to UnitAITypes and click it.

That line you posted looks wrong as someone pointed out above. It is calculating some number of extra units and then picking a random UnitAIType based on that value. Perhaps the API for initUnit() changed since that code was written?
 
You can find the other values at the Python API. In the bottom-left frame click Type List and then scroll down to UnitAITypes and click it.

That line you posted looks wrong as someone pointed out above. It is calculating some number of extra units and then picking a random UnitAIType based on that value. Perhaps the API for initUnit() changed since that code was written?

I wonder what would happen then if i just deleted those lines??
 
OK, i changed the 1,2,3 's to the UnitAITypes as mentioned, but i didnt change those lines with the calculating number in then, and i got this: (again)

Traceback (most recent call last):

File "CvEventInterface", line 25, in onEvent

File "CvCustomEventManager", line 162, in handleEvent

File "CvCustomEventManager", line 173, in _handleDefaultEvent

File "BarbarianCiv", line 104, in onEndGameTurn

File "BarbarianCiv", line 207, in checkBarbCities

File "BarbarianCiv", line 523, in createBarbCiv

TypeError: initUnit() takes at most 5 arguments (6 given)
ERR: Python function onEvent failed, module CvEventInterface
 
I have had a thought...

Could it be the case that strategyonly's file is actually trying to use the wrong initUnit function?

The PyPlayer object defined in PyHelpers.py has an initUnit method.
It is a wrapper for the regular CyPlayer.initUnit.
The parameters are different.

I think this is the case because:
1) the object name being used is pyNewPlayer (same "py" prefix)
2) it only takes 4 parameters
3) the 4th parameter is not a unitAI or direction, it is a count of how many units of that type to create

This would seem to resolve all the wierdness that is going on, including in particular the use of random numbers with ranges including a value called "extraUnits" for the 4th parameter (or just regular integers). All of the created units use UnitAITypes.NO_UNITAI and DirectionTypes.NO_DIRECTION.

If this is the case, the entire fix is to have pyNewPlayer be a PyPlayer instead of a CyPlayer.

Something like this:
Code:
pyNewPlayer = PyPlayer(iPlayer)
instead of the code that looks something like this:
Code:
pyNewPlayer = gc.getPlayer(iPlayer)
 
So then what would i change in ones like this:

Spoiler :
Code:
if( not iCounter == UnitTypes.NO_UNIT ) : pyNewPlayer.initUnit(iCounter,cityX,cityY,2+game.getSorenRandNum(5+extraUnits,'BarbarianCiv: give military infantry'),DirectionTypes.DIRECTION_NORTH)

then this:

Spoiler :
Code:
if( not iScout == UnitTypes.NO_UNIT ) : pyNewPlayer.initUnit(iScout,capital.getX(),capital.getY(),UNITAI_ANIMAL,DirectionTypes.DIRECTION_NORTH)
 
Sadly, what it means is that the original version (without adding or changing arguments) should have been correct.

I looked at the file you posted ("at long last", you might say). It appears that without all the messing with arguments it should have been OK. It turns out that pyNewPlayer is, in fact, a PyPlayer class object, not a CyPlayer class object (don't let your eyes glaze over just yet, keep reading). Except, of course, it isn't working.

Does the mod you are working on include a PyHelpers.py file?

If it does have one, I'm thinking this is the problem. It is an old version that does not have the proper call for initUnit in it with the direction argument specified (it was added at some point, possibly for BtS). Rename the PyHelpers.py file to something else and see what happens. The mod ought to pull the correct one out of the main BtS python files, I think. If it complains about it not being there, then copy the one from the main BtS Assets/Python folder to the mod and try again.

If it does not have one, I am out of ideas (for now, anyway).
 
Sadly, what it means is that the original version (without adding or changing arguments) should have been correct.

I looked at the file you posted ("at long last", you might say). It appears that without all the messing with arguments it should have been OK. It turns out that pyNewPlayer is, in fact, a PyPlayer class object, not a CyPlayer class object (don't let your eyes glaze over just yet, keep reading). Except, of course, it isn't working.

Does the mod you are working on include a PyHelpers.py file?

If it does have one, I'm thinking this is the problem. It is an old version that does not have the proper call for initUnit in it with the direction argument specified (it was added at some point, possibly for BtS). Rename the PyHelpers.py file to something else and see what happens. The mod ought to pull the correct one out of the main BtS python files, I think. If it complains about it not being there, then copy the one from the main BtS Assets/Python folder to the mod and try again.

If it does not have one, I am out of ideas (for now, anyway).


Yes its a very old file stuff, i believe Lopez was the original author.

I do have a PyHelpers.py file, i will post all my python:(in its original state.)


This is what i get using the original and re-naming the PyHelpers.py file.



Traceback (most recent call last):

File "CvEventInterface", line 25, in onEvent

File "CvCustomEventManager", line 162, in handleEvent

File "CvCustomEventManager", line 173, in _handleDefaultEvent

File "BarbarianCiv", line 104, in onEndGameTurn

File "BarbarianCiv", line 184, in checkBarbCities

AttributeError: 'CyCity' object has no attribute 'countTotalCulture'
ERR: Python function onEvent failed, module CvEventInterface
 
Yes its a very old file stuff, i believe Lopez was the original author.

I do have a PyHelpers.py file, i will post all my python:(in its original state.)

I looked at it (with WinMerge) - it is slightly different than the one that comes with BtS in that it has a few extra functions added to it. The initUnit is fine.

This is what i get using the original and re-naming the PyHelpers.py file.



Traceback (most recent call last):

File "CvEventInterface", line 25, in onEvent

File "CvCustomEventManager", line 162, in handleEvent

File "CvCustomEventManager", line 173, in _handleDefaultEvent

File "BarbarianCiv", line 104, in onEndGameTurn

File "BarbarianCiv", line 184, in checkBarbCities

AttributeError: 'CyCity' object has no attribute 'countTotalCulture'
ERR: Python function onEvent failed, module CvEventInterface

OK - reviewing this thread, that is where you where back on page 2 of this thread. You need to redo the whole "countTotalCulture" -> "countTotalCultureTimes100" fix.

Reviewing forward from there, I see where the snag happened.

In BarbarianCiv.py, on line 428 there is a line that says
Code:
                newPlayer.initUnit(gpType,ix,iy,UnitAITypes.NO_UNITAI)
This one line is wrong - it has no direction specified.

Where thigns went south is that the whole "add a direction argument" thing was then applied to all the lines that used the "pyNewPlayer.initUnit()" function. This was wrong. "newPlayer" and "pyNewPlayer" are not the same type of thing, the first is a CvPlayer and the second is a PyPlayer - you can learn this by how they were created on lines 345 and 346:
Code:
                newPlayer = gc.getPlayer(newPlayerIdx)
                pyNewPlayer = PyPlayer(newPlayerIdx)

There are two ways to fix line 428.
Option one, you can just add the missing argument:
Code:
                newPlayer.initUnit(gpType,ix,iy,UnitAITypes.NO_UNITAI,DirectionTypes.NO_DIRECTION)
or option two, you can get some consistency int he code by using pyNewPlayer instead (and making the 4th argument a 1 so it will create only 1 unit):
Code:
                pyNewPlayer.initUnit(gpType,ix,iy,1)

The first option may be slightly easier as there are fewer thigns to go wrong when you are just adding one argument than there are when changing the variable name and changing an argument. But I like the second one better - all the other unit creations are done with pyNewPlayer, so making this one that way may save someone the confusion of doing the same thing two different ways (with two different sets of arguments) in the future.

Re-fixing the culture thing and then fixing this one single line (either option) might get you to a working mod. If not, it will at least get you to the next completely new problem.
 
OK i put it back to the original state, changed the totalculture to:
Code:
cl = int( barbCityList[i].getCulture()/2.0 + (barbCityList[i].GetCy().countTotalCultureTimes100()/100)/10.0 )

and the new proposed line to:
Code:
pyNewPlayer.initUnit(gpType,ix,iy,1)

and took out all the direction_north stuff back to original also and now i get this:

Traceback (most recent call last):

File "CvEventInterface", line 25, in onEvent

File "CvCustomEventManager", line 162, in handleEvent

File "CvCustomEventManager", line 173, in _handleDefaultEvent

File "BarbarianCiv", line 104, in onEndGameTurn (in first bold print below)

File "BarbarianCiv", line 207, in checkBarbCities (in second bold print below)

File "BarbarianCiv", line 545, in createBarbCiv (in third bold print below)

AttributeError: PyCity instance has no attribute 'setHasRealBuildingIdx'
ERR: Python function onEvent failed, module CvEventInterface

1.

Spoiler :
Code:
def onEndGameTurn( self, argsList ) :
        'check for worthy barb cities'
        iGameTurn = argsList[0]

        [B]self.checkBarbCities()[/B]
        

    def onKbdEvent(self, argsList ):
        'keypress handler'
        eventType,key,mx,my,px,py = argsList

2.

Spoiler :
Code:
            if( popChance > (game.getSorenRandNum(999,'BarbarianCiv: Check barbs')) or force ) :
                #if( self.LOG_DEBUG ) : CyInterface().addImmediateMessage("Attempting to reincarnate civ, giving them %d cities"%(len(barbCityTree[maxListIdx])),"")
                if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Population barb roll succeeded, with %d cities, %d pop, forced? %d"%(len(barbCityTree[maxListIdx]),maxListPop,force))
                if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Current modifiers are: mod %f, ncm %d, gsm %f"%(mod,numCitiesMod,gsm))
                [B]self.createBarbCiv( barbCityTree[maxListIdx] )[/B]
                return
            elif( self.doCultureCheck and culChance > (game.getSorenRandNum(99,'BarbarianCiv: Check barbs')) or forceCul ) :
                # Check for cultured cities
                #if( self.LOG_DEBUG ) : CyInterface().addImmediateMessage("Attempting to reincarnate civ, giving them a cultured city","")
                if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Cult city barb roll succeeded, with %d adj cult, forced? %d"%(cl,forceCul))
                self.createBarbCiv( [barbCityList[maxCultureIdx]] )
                return

3.

Spoiler :
Code:
if( city.canConstruct( iBarracks ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iBarracks).getDescription(),city.getName()))
                            city.setHasRealBuildingIdx(iBarracks,True)
                    elif( barbSettleType == 2 ) : # Builder
                        if( city.canConstruct( iLibrary ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iLibrary).getDescription(),city.getName()))
                            [B]city.setHasRealBuildingIdx(iLibrary,True)[/B]
                        if( city.canConstruct( iLighthouse ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iLighthouse).getDescription(),city.getName()))
                            city.setHasRealBuildingIdx(iLighthouse,True)
                        if( city.canConstruct( iGranary ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iGranary).getDescription(),city.getName()))
                            city.setHasRealBuildingIdx(iGranary,True)
                    iTotCul = city.GetCy().countTotalCulture()
                    if( iTotCul > 0 ) :
                        city.setCulture( int(iTotCul/2.0) )
                        if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Culture of %s set to %d"%(city.getName(),city.getCulture()))
                        
                    if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - %d units placed in %s"%(city.plot().getNumUnits(),city.getName()))

Just incase i added the Barb.py only below.
 
OK i put it back to the original state, changed the totalculture to:
Code:
cl = int( barbCityList[i].getCulture()/2.0 + (barbCityList[i].GetCy().countTotalCultureTimes100()/100)/10.0 )

and the new proposed line to:
Code:
pyNewPlayer.initUnit(gpType,ix,iy,1)

and took out all the direction_north stuff back to original also

Well, good. It seems to run past that part now, so it should be OK.

and now i get this:

Traceback (most recent call last):

File "CvEventInterface", line 25, in onEvent

File "CvCustomEventManager", line 162, in handleEvent

File "CvCustomEventManager", line 173, in _handleDefaultEvent

File "BarbarianCiv", line 104, in onEndGameTurn (in first bold print below)

File "BarbarianCiv", line 207, in checkBarbCities (in second bold print below)

File "BarbarianCiv", line 545, in createBarbCiv (in third bold print below)

AttributeError: PyCity instance has no attribute 'setHasRealBuildingIdx'
ERR: Python function onEvent failed, module CvEventInterface

1.

Spoiler :
Code:
def onEndGameTurn( self, argsList ) :
        'check for worthy barb cities'
        iGameTurn = argsList[0]

        [B]self.checkBarbCities()[/B]
        

    def onKbdEvent(self, argsList ):
        'keypress handler'
        eventType,key,mx,my,px,py = argsList

2.

Spoiler :
Code:
            if( popChance > (game.getSorenRandNum(999,'BarbarianCiv: Check barbs')) or force ) :
                #if( self.LOG_DEBUG ) : CyInterface().addImmediateMessage("Attempting to reincarnate civ, giving them %d cities"%(len(barbCityTree[maxListIdx])),"")
                if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Population barb roll succeeded, with %d cities, %d pop, forced? %d"%(len(barbCityTree[maxListIdx]),maxListPop,force))
                if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Current modifiers are: mod %f, ncm %d, gsm %f"%(mod,numCitiesMod,gsm))
                [B]self.createBarbCiv( barbCityTree[maxListIdx] )[/B]
                return
            elif( self.doCultureCheck and culChance > (game.getSorenRandNum(99,'BarbarianCiv: Check barbs')) or forceCul ) :
                # Check for cultured cities
                #if( self.LOG_DEBUG ) : CyInterface().addImmediateMessage("Attempting to reincarnate civ, giving them a cultured city","")
                if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Cult city barb roll succeeded, with %d adj cult, forced? %d"%(cl,forceCul))
                self.createBarbCiv( [barbCityList[maxCultureIdx]] )
                return

3.

Spoiler :
Code:
if( city.canConstruct( iBarracks ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iBarracks).getDescription(),city.getName()))
                            city.setHasRealBuildingIdx(iBarracks,True)
                    elif( barbSettleType == 2 ) : # Builder
                        if( city.canConstruct( iLibrary ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iLibrary).getDescription(),city.getName()))
                            [B]city.setHasRealBuildingIdx(iLibrary,True)[/B]
                        if( city.canConstruct( iLighthouse ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iLighthouse).getDescription(),city.getName()))
                            city.setHasRealBuildingIdx(iLighthouse,True)
                        if( city.canConstruct( iGranary ) ) :
                            if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Constructing %s in %s"%(PyInfo.BuildingInfo(iGranary).getDescription(),city.getName()))
                            city.setHasRealBuildingIdx(iGranary,True)
                    iTotCul = city.GetCy().countTotalCulture()
                    if( iTotCul > 0 ) :
                        city.setCulture( int(iTotCul/2.0) )
                        if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - Culture of %s set to %d"%(city.getName(),city.getCulture()))
                        
                    if( self.LOG_DEBUG ) : CvUtil.pyPrint("  BC - %d units placed in %s"%(city.plot().getNumUnits(),city.getName()))

Just incase i added the Barb.py only below.

OK.

What it is saying is correct. The class PyCity, as defined in the file PyHelpers.py, does not have as an attribute a function called "setHasRealBuildingIdx".

What it does have is the function setNumRealBuildingIdx.

The difference is that instead of having a true/false value for the second parameter it takes a number. I would guess that originally you could only have one of any specific building in a city and at some point they changed it so that you could have more than one and this mod predates the change (the Final Frontier mod that comes with BtS can have more than one, so any such change happened in BtS or earlier - the GlobalDefines.xml or GlabalDefinesAlt.xml file has a value CITY_MAX_NUM_BUILDINGS which is normally set to 1, but can be higher as Final Frontier sets it to 8).

I would say that changing any occurrence of something like this:
Code:
city.setHasRealBuildingIdx([COLOR="Red"]iThingy[/COLOR],True)
to be something like this:
Code:
city.setNumRealBuildingIdx([COLOR="Red"]iThingy[/COLOR],1)

The reason iThingy is red is that it isn't really iThingy, it will be something different each time.

There are 5 occurances of city.setHasRealBuildingIdx in the file on lines 540, 544, 547, 550, and 569.

There are also 3 occurances of capital.setHasRealBuildingIdx which need the same fix (but to capital.* rather than city.*) on lines 563, 566, and 580.

Fixing all 8 of those should get rid of this problem. Then you get to see what the next problem will be. I figure there is about a 50% chance that you won't be done with this file yet - it would be higher but this is getting close to the end of the file.
 
Interesting thing (maybe). I was skimming the file to see what was ahead and noticed something.

I'm pretty sure the original BarbarianCiv.py file has a bug in it on line 609.
Code:
                for i in range(0, gc.getMAX_CIV_PLAYERS()) :
                    [B]if( newPlayer.canContact( 9 ) ) :[/B]
                        contactList.append( i )

The "9" should almost certainly be an "i".

As it is, if the new barbarian civ can contact player 9 then every player in the game is added to the list of players they can contact. If they can not contact player 9 then nobody is added to the list. This list is later used to pick a target for a "military type" barbarian to attack (it picks one off the list and declares war immediately if there is at least 1 player in the list).

Changing it to an "i" would hopefully make the list be the actual players that they could contact, which should be those that are close.

So even the original apparently didn't work quite the way it was supposed to.
 
There apepars to be another bug in the original:

Line 651 is nto indented as far as it should be. I ought to have 1 more tab level of indentation.
As it is, the lack of indentation should casue the definition of the function to end:
Code:
    def onFirstContact( self, argsList ) :
        'Contact'
	iTeamX,iHasMetTeamY = argsList
So the onFirstContact function is likely to do nothing and there is a bunch of loose code floating around in the end of class BarbarianCiv.

This can't be a good thing.

Edit: Well, after posting it here I discovered something. The line that starts with "iTeam" is indented with a single tab, the others use spaces. Mixing tabs and spaces is never a good idea. All (hopefully) of the other lines in the file use spaces. That one line ought to be indented with spaces as far as the next line with text on it.
 
Top Bottom