The "Don't Be Scared of the" Python Playpen Thread

Yudishtira

Spiritual/Creative
Joined
Nov 2, 2012
Messages
2,861
Location
Brisbane
A safe place for beginners to be encouraged to mod C2C Python.

Currently testing this enhancement to the Montreal Biodome.
Code:
					u_lion = gc.getInfoTypeForString("UNIT_SUBDUED_LION")
					u_panther = gc.getInfoTypeForString("UNIT_SUBDUED_PANTHER")
					u_wolf = gc.getInfoTypeForString("UNIT_SUBDUED_WOLF")
					u_bear = gc.getInfoTypeForString("UNIT_SUBDUED_BEAR")
					u_polarbear = gc.getInfoTypeForString("UNIT_SUBDUED_POLARBEAR")
					u_btiger = gc.getInfoTypeForString("UNIT_SUBDUED_BENGALTIGER")
					u_cheetah = gc.getInfoTypeForString("UNIT_SUBDUED_CHEETAH")
					u_jaguar = gc.getInfoTypeForString("UNIT_SUBDUED_JAGUAR")
					u_stagdeer = gc.getInfoTypeForString("UNIT_SUBDUED_STAG_DEER")
					u_moose = gc.getInfoTypeForString("UNIT_SUBDUED_MOOSE")
					u_caribou = gc.getInfoTypeForString("UNIT_SUBDUED_CARIBOU")
					u_giraffe = gc.getInfoTypeForString("UNIT_SUBDUED_GIRAFFE")
					u_zebra = gc.getInfoTypeForString("UNIT_SUBDUED_ZEBRA")
					u_rhino = gc.getInfoTypeForString("UNIT_SUBDUED_RHINO")
					u_bbear = gc.getInfoTypeForString("UNIT_SUBDUED_BLACKBEAR")
					u_horse = gc.getInfoTypeForString("UNIT_SUBDUED_HORSE")
					u_donkey = gc.getInfoTypeForString("UNIT_SUBDUED_DONKEY")
					u_camel = gc.getInfoTypeForString("UNIT_SUBDUED_CAMEL")
					u_llama = gc.getInfoTypeForString("UNIT_SUBDUED_LLAMA")
					u_elephant = gc.getInfoTypeForString("UNIT_SUBDUED_ELEPHANT")
					u_ante = gc.getInfoTypeForString("UNIT_SUBDUED_ANTEATER")
					u_badger = gc.getInfoTypeForString("UNIT_SUBDUED_BADGER")
					u_bpython = gc.getInfoTypeForString("UNIT_SUBDUED_BALLPYTHON")
					u_bape = gc.getInfoTypeForString("UNIT_SUBDUED_BARBARYAPE")
					u_boar = gc.getInfoTypeForString("UNIT_SUBDUED_BOAR")
					u_warthog = gc.getInfoTypeForString("UNIT_SUBDUED_WARTHOG")
					u_capuch = gc.getInfoTypeForString("UNIT_SUBDUED_CAPUCHIN")
					u_cassowary = gc.getInfoTypeForString("UNIT_SUBDUED_CASSOWARY")
					u_chimp = gc.getInfoTypeForString("UNIT_SUBDUED_CHIMPANZEE")
					u_cobra = gc.getInfoTypeForString("UNIT_SUBDUED_COBRA")
					u_dtort = gc.getInfoTypeForString("UNIT_SUBDUED_DESERT_TORTOISE")
					u_eagle = gc.getInfoTypeForString("UNIT_SUBDUED_EAGLE")
					u_emu = gc.getInfoTypeForString("UNIT_SUBDUED_EMU")
					u_flami = gc.getInfoTypeForString("UNIT_SUBDUED_FLAMINGO")
					u_gtort = gc.getInfoTypeForString("UNIT_SUBDUED_GALAPOGOS_TORTOISE")
					u_gazel = gc.getInfoTypeForString("UNIT_SUBDUED_GAZELLE")
					u_gorilla = gc.getInfoTypeForString("UNIT_SUBDUED_GORILLA")
					u_grizzly = gc.getInfoTypeForString("UNIT_SUBDUED_GRIZZLY")
					u_hyena = gc.getInfoTypeForString("UNIT_SUBDUED_HYENA")
					u_iguana = gc.getInfoTypeForString("UNIT_SUBDUED_IGUANA")
					animal = CyGame().getSorenRandNum(40, "Which Animal")

					if animal == 0:
						pNewUnit = pPlayer.initUnit( u_bear, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 2:
						pNewUnit = pPlayer.initUnit( u_lion, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 3:
						pNewUnit = pPlayer.initUnit( u_panther, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 4:
						pNewUnit = pPlayer.initUnit( u_polarbear, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 5:
						pNewUnit = pPlayer.initUnit( u_btiger, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 6:
						pNewUnit = pPlayer.initUnit( u_cheetah, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 7:
						pNewUnit = pPlayer.initUnit( u_jaguar, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 8:
						pNewUnit = pPlayer.initUnit( u_stagdeer, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 9:
						pNewUnit = pPlayer.initUnit( u_moose, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 10:
						pNewUnit = pPlayer.initUnit( u_caribou, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 11:
						pNewUnit = pPlayer.initUnit( u_giraffe, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 12:
						pNewUnit = pPlayer.initUnit( u_zebra, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 13:
						pNewUnit = pPlayer.initUnit( u_rhino, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 14:
						pNewUnit = pPlayer.initUnit( u_bbear, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 15:
						pNewUnit = pPlayer.initUnit( u_horse, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 16:
						pNewUnit = pPlayer.initUnit( u_camel, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 17:
						pNewUnit = pPlayer.initUnit( u_elephant, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 18:
						pNewUnit = pPlayer.initUnit( u_badger, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 19:
						pNewUnit = pPlayer.initUnit( u_bape, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 20:
						pNewUnit = pPlayer.initUnit( u_warthog, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 21:
						pNewUnit = pPlayer.initUnit( u_cassowary, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 22:
						pNewUnit = pPlayer.initUnit( u_cobra, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 23:
						pNewUnit = pPlayer.initUnit( u_eagle, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 24:
						pNewUnit = pPlayer.initUnit( u_flami, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 25:
						pNewUnit = pPlayer.initUnit( u_gazel, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 26:
						pNewUnit = pPlayer.initUnit( u_grizzly, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 27:
						pNewUnit = pPlayer.initUnit( u_iguana, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 28:
						pNewUnit = pPlayer.initUnit( u_donkey, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 29:
						pNewUnit = pPlayer.initUnit( u_llama, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 30:
						pNewUnit = pPlayer.initUnit( u_ante, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 31:
						pNewUnit = pPlayer.initUnit( u_bpython, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 32:
						pNewUnit = pPlayer.initUnit( u_boar, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 33:
						pNewUnit = pPlayer.initUnit( u_capuch, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 34:
						pNewUnit = pPlayer.initUnit( u_chimp, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 35:
						pNewUnit = pPlayer.initUnit( u_dtort, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 36:
						pNewUnit = pPlayer.initUnit( u_emu, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 37:
						pNewUnit = pPlayer.initUnit( u_gtort, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 38:
						pNewUnit = pPlayer.initUnit( u_gorilla, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					elif animal < 39:
						pNewUnit = pPlayer.initUnit( u_hyena, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
					else:
						pNewUnit = pPlayer.initUnit( u_wolf, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )

(If it works) it adds 36 (more to come) more animals that the Biodome can spawn.
 
Or you could, in the init function or when the biodome is built and onLoad if the biodome exists, loop through all the units looking for the units with their names starting with "UNIT_SUBDUED" or "UNIT_TAMED" and create an array containing the id. Then roll a random number based on the length of that array and use it as an index to create the new unit. That way you don't have to change the code when more animals are added. :D
 
Or you could, in the init function or when the biodome is built and onLoad if the biodome exists, loop through all the units looking for the units with their names starting with "UNIT_SUBDUED" or "UNIT_TAMED" and create an array containing the id. Then roll a random number based on the length of that array and use it as an index to create the new unit. That way you don't have to change the code when more animals are added. :D

Brilliant. It's also important to do it this way because if an animal listed is removed it would cause a problem for the system if the poor modder who removed it didn't realize he needed to update this python file. Also would be the only way to make it work with an option such as you're designing that turns many animals on or off.

Even I, however, would like to see how that would be done in python coding. I've no idea how python would initiate and handle an array. (Or maybe I have a clue but I'm assuming it's more complicated than I think... I dunno.)
 
Or you could, in the init function or when the biodome is built and onLoad if the biodome exists, loop through all the units looking for the units with their names starting with "UNIT_SUBDUED" or "UNIT_TAMED" and create an array containing the id. Then roll a random number based on the length of that array and use it as an index to create the new unit. That way you don't have to change the code when more animals are added. :D

I couldn't, but maybe you could. The question is: will you?;)
 
It has been on my to do list for a long long time. Since we added it in fact. There just have been other priorities.

The code for the Biodome is in the merged module PlatyPingWonders.py.

We have two choices for the array and memory usage. Either always have the array or only create it when the Biodome is built. The first is the simplest.

Step 1 - define a global array and add an init function to fill it.
In the Assets/Config folder find PlatyPingWonders.XML and add <init/>
Spoiler :
Code:
<mod id="PlatyPingWonders" module="PlatyPingWonders">
 	<event type="BeginPlayerTurn" function="onBeginPlayerTurn"/>
  	<event type="EndPlayerTurn" function="onEndPlayerTurn"/>
  	<event type="buildingBuilt" function="onBuildingBuilt"/>
  	<event type="techAcquired" function="onTechAcquired"/>
 	<event type="combatResult" function="onCombatResult"/>
 	<event type="unitBuilt" function="onUnitBuilt"/>
 	<event type="unitSpreadReligionAttempt" function="onUnitSpreadReligionAttempt"/>

 	<init/>
</mod>

In the python add an empty array as global and then fill it in the init function
Spoiler :
Code:
# globals
###################################################
#~ def init():
becomes
Code:
# globals
agBiodomeAnimalList= None
###################################################
def init():
	global agBiodomeAnimalList
	agBiodomeAnimalList= []

	for iUnit in xrange(gc.getNumUnitInfos()):
		UnitInfo = gc.getUnitInfo(iUnit)
		sType = UnitInfo.getType()
		if sType.find("UNIT_SUBDUED") > -1:
			agBiodomeAnimalList.append(iUnit)

2. Use the list in onEndPlayerTurn

Code:
		b_Biodome = gc.getInfoTypeForString("BUILDING_BIODOME")
		if b_Biodome > -1 and [B]len(agBiodomeAnimalList) > 0[/B]:
			(loopCity, iter) = pPlayer.firstCity(False)
			while(loopCity):
				if loopCity.getNumActiveBuilding(b_Biodome) > 0:
				
					iX = loopCity.getX()
					iY = loopCity.getY()
[B]					animal = CyGame().getSorenRandNum(len(agBiodomeAnimalList), "Which Animal")

					pNewUnit = pPlayer.initUnit( animal, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION )
[/B]

I am not sure that is right yet as I have not tested it or checked that I have used the correct format or function names but I have had my coffee ;)

editAttached is the code if someone can test it - I have appointments all morning and need to get ready for them.
 
Of course there is a problem with the above code:- it will sometimes generate an animal that should only be generated by the Pliocene Park ie the mammoths, ground sloths etc. Unfortunately we did not include PLIOCENE in the unit name so we can't do the inclusion or exlusion of those animals in such a simple way.:(
 
In the Assets/Config folder find PlatyPingWonders.XML and add <init/>

<mod id="PlatyPingWonders" module="PlatyPingWonders">
<event type="BeginPlayerTurn" function="onBeginPlayerTurn"/>
<event type="EndPlayerTurn" function="onEndPlayerTurn"/>
<event type="buildingBuilt" function="onBuildingBuilt"/>
<event type="techAcquired" function="onTechAcquired"/>
<event type="combatResult" function="onCombatResult"/>
<event type="unitBuilt" function="onUnitBuilt"/>
<event type="unitSpreadReligionAttempt" function="onUnitSpreadReligionAttempt"/>

<init/>
</mod>
So THIS is where python begins then is in an xml file such as this? Python 'mods' are defined and their functions declared here? (Yes I'm really this lost when it comes to how python actually works from the beginning...)

global ABiodomeAnimalList ;
I don't quite understand this declaration. What's the use of the term 'global' achieving here? Is this a python built-in feature term that has special meaning?


Then you have:
ABiodomeAnimalList = []
and that's not ended with a ';' sooooo... why can it just sit out there? I presume this is where we define the global variable declared as ABiodomeAnimalList AS an array of so far undetermined length?


for iUnit in xrange(gc.getNumUnitInfos()):
You've just used iUnit without declaring it in any way... is that declared elsewhere or is this a declaration itself, woven into the for statement as it get's started? And could you have thus called it anything? Like iPurplemonsters or whatever you wish? I suppose xrange is a python standard used in setting up the beginning of a for loop and defining the number of iterations then?

And then this:
UnitInfo = gc.getUnitInfo(iUnit)
is where you both declare and define the value (within the given iteration) of UnitInfo as being the Unit with the current 'iUnit' iteration count right? Of course at this point then UnitInfo is just a proxy statement for the whole gc.getUnitInfo(iUnit) statement so just makes it faster to use from this point... you wouldn't actually have to even make this statement if I'm guessing... you could just use gc.getUnitInfo(iUnit).whatever all the way through from there correct?


.find looks to be a useful command (it's a bit more verbose in the dll coding.) I wonder if it wouldn't be better to be looking for the subdued combat class though just in case the naming is flawed somehow.

'> -1' is a bool true? Or is that specifically the 'false' return for a .find command?

And then the use of .append makes it appear to be that an array declaration like this in python actually works much more like a vector than an SDK array... you can define the size of it as you go which is quite interesting - is there some kind of 'once closed it can't further be defined' kind of rule that takes place anywhere in that?

The rest seemed straightforward to what I do understand of python. Thanks in advance for your answers.
 
Of course there is a problem with the above code:- it will sometimes generate an animal that should only be generated by the Pliocene Park ie the mammoths, ground sloths etc. Unfortunately we did not include PLIOCENE in the unit name so we can't do the inclusion or exlusion of those animals in such a simple way.:(

Yes and I suggest there are some subdued animals (eg. pigeons) that you don't want the Biodome to spawn. Then there is the issue of some animals should spawn more often than others, which I suppose you do by having another list/array matching the first, but this time of integers from 1 (rare) to 5 or more for more common animals.

Another way would be to put the common animals into the original array multiple times based on how commonly they should spawn... Less elegant, but this way the random number remains the index into the list (which it needs to be as far as I am aware).

But there is no XML variable for how commonly an animal should Biodome-spawn, so I think that means you'd have to create one. Yes that seems to solve the whole problem:goodjob:. However it is a lot more work, and needs a lot more testing, and has the drawback that the list of animals and frequencies can only be found by trawling through XML, rather than in one place where it is hardcoded as at present.

ETA: This last problem could be solved by writing the array of animals and frequencies to a new log file while creating it.
 
Yes and I suggest there are some subdued animals (eg. pigeons) that you don't want the Biodome to spawn. Then there is the issue of some animals should spawn more often than others, which I suppose you do by having another list/array matching the first, but this time of integers from 1 (rare) to 5 or more for more common animals.

But there is no XML variable for how commonly an animal should Biodome-spawn, so I think that means you'd have to create one. Yes that seems to solve the whole problem:goodjob:. However it is a lot more work, and needs a lot more testing, and has the drawback that the list of animals and frequencies can only be found by trawling through XML, rather than in one place where it is hardcoded as at present.

Easier to make a dll coded process to handle the whole thing if you're going to go as far as making a tag for it.
 
So THIS is where python begins then is in an xml file such as this? Python 'mods' are defined and their functions declared here? (Yes I'm really this lost when it comes to how python actually works from the beginning...)

The config XML files are the BUG modular python stuff. You are telling BUG in the init.XML which modules you are loading and in the module.XML you are telling BUG which program events that module uses. BUG then links them together.

If we did not have BUG then there would be no need for these XML files and you would just put them the Event Manager like Platyping does.

I don't quite understand this declaration. What's the use of the term 'global' achieving here? Is this a python built-in feature term that has special meaning?

The = None sets aside some "global" memory. Although it is not totally global just global to the file containing the code. You can access it in other files if you prefix it with the file name and inport that file inside the other.

It is global because it is defined outside the defs.

The = [] defines it as one of the list types.

The global statement tells python that when you are changing the value of the variable inside the def you are changing the global variable not a local to the def variable.

Then you have:

and that's not ended with a ';' sooooo... why can it just sit out there? I presume this is where we define the global variable declared as ABiodomeAnimalList AS an array of so far undetermined length?

Python does not use ; to end statements the end of line does that. Many languages are like that.

You've just used iUnit without declaring it in any way... is that declared elsewhere or is this a declaration itself, woven into the for statement as it get's started? And could you have thus called it anything? Like iPurplemonsters or whatever you wish?

Python is scripted not compiled, though it can be. Using a variable on the left of an = defines it. There is no need to define it otherwise. Unless you intend to use it as a global or force a type on it.

I suppose xrange is a python standard used in setting up the beginning of a for loop and defining the number of iterations then?

It is a loop over any list object.

.find looks to be a useful command (it's a bit more verbose in the dll coding.) I wonder if it wouldn't be better to be looking for the subdued combat class though just in case the naming is flawed somehow.

'> -1' is a bool true? Or is that specifically the 'false' return for a .find command?

It finds the position of the specified string inside a string. -1 means it did not find it. 0 would mean that it was found at character 1 for example.

And then the use of .append makes it appear to be that an array declaration like this in python actually works much more like a vector than an SDK array... you can define the size of it as you go which is quite interesting -

You are "just" adding to a list. They don't even have to be the same type of thing you are adding to the list but in this case all I am doing is adding the id value for the unit type so I can use it later.

If you know the size of the array you are going to use it is better (faster) to define it at start rather than using the append.
is there some kind of 'once closed it can't further be defined' kind of rule that takes place anywhere in that?
Not that I know of.
 
So what is the ';' doing in this line?
global ABiodomeAnimalList ;

(Thanks by the way for the explanations - that helps tremendously!)
 
It isn't in the actual code ;). The code I put here was before I did the actual python, or even had coffee, so there are some typos.
 
lol

Ok, so help me out here too..

It is global because it is defined outside the defs.
hmm... so what are the 'defs' exactly?
 
The defs are functions or methods. If they are in a class they are methods of that class. Their scope is the class or file they are in.
 
Code:
if True:
[TAB]i += 1
[TAB]i += 5

Code:
if True:
[TAB]i += 1; i += 5

The 2 codes are similar.
That is what ";" is used for in python.
Naturally, ";" without anything behind has no meaning, but is not an error either.

@DH
You might as well shift it to onCityDoTurn, and get rid of the city loop.
 
Top Bottom