trying to use a minimalist mod to do big things

For balance, I'm trying to make something happen every time any civ acquires Theology, but it doesn't seem to like


Code:
def xpNorm():
		if CvEventInfo().getTech()  == 10:
				if PyPlayer(0).isAlive():
						PyPlayer(0).initUnit(18, 49, 56, 1)

it has a problem with the getTech line. My intention is to run it onTechAcquired. I need it to see if the acquired tech is Theology and then, if it is, generate the unit. Where am I messing up? It doesn't give me an error, it just doesn't do anything at all...
 
This is basically what you need to do. In CvEventManager:
Code:
	def onTechAcquired(self, argsList):
		'Tech Acquired'
		iTechType, iTeam, iPlayer, bAnnounce = argsList
		[B]MyModule.xpNorm(iTechType)[/B]
In MyModule (or whatever you are calling it):
Code:
def xpNorm(eTechType):
		if eTechType == 10:
				if PyPlayer(0).isAlive():
						PyPlayer(0).initUnit(18, 49, 56, 1)
Note however that you don't need to - and you should not - make a xpNorm() function for each and every player. Instead you can pass on the iPlayer value from the onTechAcquired() method with the function call to a generic xpNorm() function:
Code:
def xpNorm(eTechType, ePlayer):
        if eTechType == 10:
                player = PyPlayer(ePlayer)
                if player.isAlive():
                        iX, iY = tSpawn[ePlayer]
                        player.initUnit(18, iX, iY, 1)
Note that I assigned a PyPlayer instance to the variable player in order not to create two PyPlayer instances. Also, I'm indexing a tSpawn data structure (tuple) which would need to be defined as a constant. Its basically a tuple containing other tuples with tile coordinates. Like:
Code:
tSpawn = (
(23, 45), 
(45, 34),
(67, 85),
...
)
 
ah, that was just the ticket.

Well, I can't really do it with a tuple as they don't all get them or all work the same way. This is merely designed to help Christianity and Islam spread historically even after Judaism has had time to spread around the world and become everyone in Europe and the Middle East's state religion.

It only generates one missionary on the appropriate tech spread to each of these civs and only if they're alive and only if it's after their spawn date (only if they have one...remember, with the workboats they're still considered "alive" by the game even though they're not on the map as far as the player is concerned). Needless to say, it works a little different for each one.

I've found that even if an AI has a state religion and theocracy, and you give them their own missionary for a different religion, the AI will use it on one of their own cities. In this way (1 missionary each time a civ discovers the tech for up to 18 total over time), the religion will slowly spread over time and AI civs will convert to it if it's their favorite in the xml. The human player can use the missionary or delete the unit as they please.

Spoiler :
Code:
#generates Christian missionaries for certain civs every time theology is acquired
def xpNorm(eTechType):
		if eTechType == 10:
				if PyPlayer(0).isAlive():
						PyPlayer(0).initUnit(18, 49, 56, 1)
				if PyPlayer(5).isAlive():
						PyPlayer(5).initUnit(18, 67, 42, 1)
				if PyPlayer(7).isAlive():
						if isDate(-770):
								PyPlayer(7).initUnit(18, 60, 44, 1)
				if PyPlayer(10).isAlive():
						PyPlayer(10).initUnit(18, 68, 23, 1)
				if PyPlayer(12).isAlive():
						if isDate(400):
								PyPlayer(12).initUnit(18, 54, 54, 1)
				if PyPlayer(13).isAlive():
						if isDate(450):
								PyPlayer(13).initUnit(18, 55, 50, 1)
				if PyPlayer(14).isAlive():
						if isDate(475):
								PyPlayer(14).initUnit(18, 52, 43, 1)
				if PyPlayer(15).isAlive():
						if isDate(843):
								PyPlayer(15).initUnit(18, 63, 52, 1)
				if PyPlayer(16).isAlive():
						if isDate(1000):
								PyPlayer(16).initUnit(18, 71, 54, 1)

#generates Islamic missionaries for certain civs every time divine right is acquired
def islamNorm(eTechType):
		if eTechType == 14:
				if PyPlayer(1).isAlive():
						PyPlayer(1).initUnit(19, 68, 32, 1)
				if PyPlayer(2).isAlive():
						PyPlayer(1).initUnit(19, 77, 40, 1)
				if PyPlayer(8).isAlive():
						if isDate(-625):
								PyPlayer(8).initUnit(19, 81, 40, 1)
				if PyPlayer(11).isAlive():
						if isDate(700):
								PyPlayer(11).initUnit(19, 75, 33, 1)
 
So, every time any player discovers Theology/DR, then all players get the free units? (But still, creating a new PyPlayer instance for every method invocation is... wasteful. And this setup could also be done with data structures.)

edit: Also, you can't use the isDate() function the way you do. Because it will only make the units spawn on that one game turn. And the probability of someone researching a specific tech on a specific game turn is... pretty slim. What you probably want is to make sure the game date is before/after some date - not that its the actual date.

There would be other ways of spreading religions, by the way. Other than spawning missionaries...

About the copy-pasting in your code - I think you missed one value... ;)
Spoiler :
Code:
				if PyPlayer(2).isAlive():
						PyPlayer([COLOR="Red"]1[/COLOR]).initUnit(19, 77, 40, 1)
 
Since I just can't help myself, I took the liberty of making this for you:
Code:
def isInterval(iDate1=None, iDate2=None):
		if iDate1 == None:
				iDate1 = cyGame.getStartingYear()
		if iDate2 == None:
				iDate2 = gc.getTurnYear(gc.getMaxTurns())
		return iDate1 <= gc.getGameTurnYear() <= iDate2
Use this instead of isDate() when you need to check if the current game date is before or after a date - or in between two dates. Examples of use:
Code:
isInterval(500)
isInterval(0, 1000)
isInterval(None, 450)
isInterval(451, None)
isInterval(iDate2=-2000)
isInterval(iDate1=1450)
So a None value instead of a actual integer value will automatically set the first/last date in the interval to the date corresponding to the first/last game turn. You can either declare the None value instead of using the integer value, or you can type out the argument itself and assign a value to it. (Otherwise the default value for either is None.)

This would create an interval that spans the whole game:
Code:
isInterval()
Because both dates are set to None by default.

It probably looks pretty complicated but it really isn't.
 
And instead of populating your module with these PyPlayer constructors, you could just assign constants for referencing these and use those through-out the whole module. (Probably too late for that with your code...)
Code:
pyRome, pyCeltia, pyIndia, pyCarthage, pyGreece = (PyPlayer(ePlayer) for ePlayer in range(5))
This example postulates that the mod only has these five players and that they are indexed 0-4. But pyRome would be a value PyPlayer i nstance for the first player in the mod.

Ok, the code above is pretty advanced (thanks EmperorFool :king:) but you could do it the old fashioned manual way, also:
Code:
pyRome = PyPlayer(0)
pyCeltia = PyPlayer(1)
pyIndia = PyPlayer(2)
pyCarthage = PyPlayer(3)
pyGreece = PyPlayer(4)
But anytime you can skip repeating any code is an opportunity to be captured! (Making complex code is... good for you. :lol:)
 
Yeah, that's basically the way it works. Every time DR is discovered, Arabia, Egypt, Mesopotamia nd Persia get an Islamic missionary they can use on one of their own cities or on someone else's. DR is usually not discovered before Arabia spawns (AD 700), and by then the others are all staunchly Jewish (even though I listed Islam as their favorite). Because Judaism is so powerful, percentage wise, by that time, even civs with a predisposition for another religion are reluctant to switch. This is especially true since Arabia starts at war with its neighbors (to encourage expansion throughout the middle east)...but frequently gets boxed in and eliminated, taking Islam with it...

The same goes for Christianity and Europe.

But once an AI manages to get their "favorite" religion into all their cities, they tend to switch, even if it has weaker numbers than the frontrunner.

The good thing about doing it with missionaries is that it allows the human player to strategize and make choices, while the AI's "mindless" spreading will be at a gradual rate.

The new code suggestions are going to be interesting to comb through and analyze - thanks.
 
Overloading a function to make it take different default values can be helpful, but don't overdo it. There are only three cases you'll need to check usually: is the current date before a year, after a year, or between two years. Also, it helps to put TurnYear into the name because interval by itself can mean so many things.

Code:
isTurnYearBefore(year):
    return gc.getGameTurnYear() < year

isTurnYearAfter(year):
    return gc.getGameTurnYear() > year

isTurnYearBetween(firstYear, secondYear):
    currentYear = gc.getGameTurnYear()
    return currentYear > firstYear and currentYear < secondYear

Use <= and >= as you see fit. You could even have isYearOnOrBefore(year) that uses <= instead of <. By using multiple clear function names you no longer need to document the multiple ways to use the single function and what the defaults are.
 
Overloading a function to make it take different default values can be helpful, but don't overdo it. There are only three cases you'll need to check usually: is the current date before a year, after a year, or between two years. Also, it helps to put TurnYear into the name because interval by itself can mean so many things.
Good advice overall, and the helper functions should come handy for this project also.

But right now my own MO is to push myself a little more all the time, in order to learn. Also, solving programming problems is fun. :D So I jump on any opportunity to make some code, preferably in some "clever" way. :p

Now, this thread is about keeping it simple. So my personal style of doing things - at this juncture in my programming life - wouldn't necessarily always be the best choice. But if the aim is also learning it might be good to showcase some of the cool - and useful - things that can be done. :king:
 
Back
Top Bottom