View Full Version : Python Snippets


Zebra 9
May 25, 2007, 07:46 PM
Intro:
Lately I have been doing alot of small things with python, such as setting civics so they require religions and units that require a certain leader, that sort of thing. So I decided to make this Python Snippets Thread where anyone can come and find some realy cool, and realy simple, python code snippets.
Index:Religious Civics
Civic Specific Units
Civic Specific Buildings
Leader Specific Units
Leader Specific Buildings
Lockable Civics
City Max Unit Limit
Python Activated Always War/Peace (By Dale)http://forums.civfanatics.com/uploads/91501/HBar.gif
Python Snippets For CvGameUtils.py
First I will be doing several python snippets that work from the CvGameUtils.py file. From this file we can control the civics a player adopts, the units, buildings, and projects a city can build, a s well as allowing us to control the amount of money you get from capturing cities and pillaging.Note: If you are using these snippets you may have to make some changes to PythonCallbackDefines.xml. If you are not sure about how to make the change post your question here so I (or any other modder) can help get you on your way. I will be posting the tags that must be changed soon. :cool:


Religious Civics<Back To Top>
The following snippet allows a player to adopt a civic only if they have the correct state religion. The code is as follows:

religion = Religion Type ## The Religion
civic = Civic Type ## The Civic

## If The Civ Doesn't Have The Correct Religion Tell the SDK Not To Allow The Player To Chose This Civic
if eCivic == gc.getInfoTypeForString(civic):
if gc.getPlayer(ePlayer).getStateReligion() != gc.getInfoTypeForString(religion):
return True
Now this code goes inside of the cannotDoCivic function, in an unMODed game this function looks like:

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False
Place the snippet after eCivic = argsList[1] and before return False.

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
## Place Snippet Below Here

## But Above Here
return False
To set the required state religion place the religion's type tag after religion = , but remember the type tag must be inside of quote marks.

religion = "RELIGION_JUDAISM" ## The Religion
Next to set the civic that requires that religion, place the civic's type tag after civic = , again remember the type tag must be inside of quote marks.

civic = "CIVIC_HEREDITARY_RULE" ## The Civic
If you follow those instructions you shouldn't have any problems.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Civic Specific Units<Back To Top>
The following snippet only allows a player to train a certain unit if they have adopted a certain civic:

civic = Civic Type ## The Civic
unit = Unit Type ## The Unit

## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Train This Unit
if eUnit == gc.getInfoTypeForString(unit):
if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoT ypeForString(civic)):
return True
Now this code goes inside of the cannotTrainUnit function, in an unMODed game this function looks like:

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
Place the snippet after bTestVisible = argsList[3] and before return False.

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
## Place Snippet Below Here

## But Above Here
return False
To set the required civic place the civic's type tag after civic = , but remember the type tag must be inside of quote marks.

civic = "CIVIC_HEREDITARY_RULE" ## The Civic
Next to set the unit that requires that civic, place the unit's type tag after unit = , again remember the type tag must be inside of quote marks.

unit = "UNIT_GUNSHIP" ## The Unit
If you follow those instructions you shouldn't have any problems.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Civic Specific Buildings<Back To Top>
The following snippet only allows a player to construct a certain building if they have adopted a certain civic:

civic = Civic Type ## The Civic
building = Building Type ## The Building

## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Costruct This Building
if eBuilding == gc.getInfoTypeForString(building):
if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoT ypeForString(civic)):
return True
Now this code goes inside of the cannotConstruct function, in an unMODed game this function looks like:

def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
return False
Place the snippet after bIgnoreCost = argsList[4] and before return False.

def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
## Place Snippet Below Here

## But Above Here
return False
To set the required civic place the civic's type tag after civic = , but remember the type tag must be inside of quote marks.

civic = "CIVIC_HEREDITARY_RULE" ## The Civic
Next to set the building that requires that civic, place the building's type tag after building = , again remember the type tag must be inside of quote marks.

building = "BUILDIN_FORGE" ## The Building
If you follow those instructions you shouldn't have any problems.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Leader Specific Units<Back To Top>
The following snippet only allows a player to train a certain unit if they have the correct leader:

leader = Leader Type ## The Leader
unit = Unit Type ## The Unit

## If The Civ Doesn't Have The Correct Leader Tell the SDK Not To Allow The Player To Construct This Building
if eUnit == gc.getInfoTypeForString(unit):
leaderType = gc.getLeaderHeadInfo(gc.getPlayer(pCity.getOwner() ).getLeaderType()).getType()
if leaderType != gc.getInfoTypeForString(leader):
return True
Now this code goes inside of the cannotTrain function, in an unMODed game this function looks like:

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
Place the snippet after bTestVisible = argsList[3] and before return False.

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
## Place Snippet Below Here

## But Above Here
return False
To set the required leader place the leader's type tag after leader = , but remember the type tag must be inside of quote marks.

leader = "LEADER_VICTORIAH" ## The Leader
Next to set the unit that requires the leader, place the unit's type tag after unit = , again remember the type tag must be inside of quote marks.

unit = "UNIT_ENGLISH_READCOAT" ## The Unit
If you follow those instructions you shouldn't have any problems.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Leader Specific Buildings<Back To Top>
The following snippet only allows a player to construct a certain building if they have the correct leader:

leader = Leader Type ## The Leader
building = Building Type ## The Building

## If The Civ Doesn't Have The Correct Leader Tell the SDK Not To Allow The Player To Construct This Building
if eBuilding == gc.getInfoTypeForString(building):
leaderType = gc.getLeaderHeadInfo(gc.getPlayer(pCity.getOwner() ).getLeaderType()).getType()
if leaderType != gc.getInfoTypeForString(leader):
return True
Now this code goes inside of the cannotConstruct function, in an unMODed game this function looks like:

def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
return False
Place the snippet after bIgnoreCost = argsList[4] and before return False.

def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
## Place Snippet Below Here

## But Above Here
return False
To set the required leader place the leader's type tag after leader = , but remember the type tag must be inside of quote marks.

leader = "LEADER_VICTORIAH" ## The Leader
Next to set the building that requires the leader, place the building's type tag after building = , again remember the type tag must be inside of quote marks.

building = "BUILDIN_FORGE" ## The Building
If you follow those instructions you shouldn't have any problems.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Lockable Civics<Back To Top>
The following snippet allows you to set a civic as locked. Once a player adopts a locked civic they are stuck with it (well at least until the UN):

civic = Leader Type ## The Civic

pPlayer = gc.getPlayer(ePlayer)

civicType = gc.getCivicInfo(eCivic).getType()
civicOptType = gc.getCivicInfo(eCivic).getCivicOptionType()
testCivic = gc.getCivicInfo(pPlayer.getCivics(civicOptType)).g etType()

if testCivic == civic and testCivic != civicType:
return True
Now this code goes inside of the cannotDoCivic function, in an unMODed game this function looks like:

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False
Place the snippet after eCivic = argsList[1] and before return False.

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
## Place Snippet Below Here

## But Above Here
return False
To set the locked civic place the civic's type tag after civic = , but remember the type tag must be inside of quote marks.

civic = "CIVIC_HEREDITARY_RULE" ## The Civic
If you follow those instructions you shouldn't have any problems.:thumbsup:

City Max Unit Limit<Back To Top>
The following snippet allows you to set a certain amount of units that each city can support. For example if a civ has 5 cities and each city can support 3 units the civ can build only 15 units, but if they build a 6th city they can then build 18 units.:
def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]

pPlayer = gc.getPlayer(pCity.getOwner())
numUnitsPerCity = Num Units Supported by one City ## The Number Of Units A City Supports
maxUnits = pPlayer.getNumCities() * numUnitsPerCity
if pPlayer.getNumUnits() >= maxUnits:
return True
return FalseNow this code goes inside of the cannotTrain function, in an unMODed game this function looks like:

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
Place the snippet after bTestVisible = argsList[1] and before return False.

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
## Place Snippet Below Here

## But Above Here
return False
To set the number of units supported by each city set numUnitsPerCity = to what ever you want.

numUnitsPerCity = 5 ## The Number Of Units A City
If you follow those instructions you shouldn't have any problems.:thumbsup:

Hope this helps alot of ya. I know I find these to be cool and useful.:goodjob:
<Back To Top>

Zebra 9
May 25, 2007, 07:47 PM
Python Snippets For CvEventManager.py
Next I will be doing several python snippets that work from the CvEventManager.py file. This file is where we receive information about what is happening. In this file we can find out when a city is built, a unit is constructed, a unit is moved, an improvement is destroyed, ect..


Thumbtack System (Ambreville's Idea)<Back To Top>
The following snippet allows a player to turn the unit cycling option on and off w/ the key board (ALT-C). The code is as follows:

## This line checks to see if the ALT and C keys where pressed
if theKey == InputTypes.KB_C and self.bAlt:
## This turns the Unit Cycling on or off
if gc.getActivePlayer().isOption(PlayerOptionTypes.PL AYEROPTION_NO_UNIT_CYCLING):
gc.getActivePlayer().setOption(PlayerOptionTypes.P LAYEROPTION_NO_UNIT_CYCLING, False)
else:
gc.getActivePlayer().setOption(PlayerOptionTypes.P LAYEROPTION_NO_UNIT_CYCLING, True)
Now this code goes inside of the onKbdEvent function, in an unMODed game this function looks like:

def onKbdEvent(self, argsList):
'keypress handler - return 1 if the event was consumed'

eventType,key,mx,my,px,py = argsList
game = CyGame()

if (self.bAllowCheats):
# notify debug tools of input to allow it to override the control
argsList = (eventType,key,self.bCtrl,self.bShift,self.bAlt,mx ,my,px,py,CyGame().isNetworkMultiPlayer())
if ( CvDebugTools.g_CvDebugTools.notifyInput(argsList) ):
return 0

if ( eventType == self.EventKeyDown ):
theKey=int(key)

CvCameraControls.g_CameraControls.handleInput( theKey )

# Shift - T (Debug - No MP)
if (self.bAllowCheats and theKey == int(InputTypes.KB_T)):
if ( self.bShift ):
self.beginEvent(CvUtil.EventAwardTechsAndGold)
#self.beginEvent(CvUtil.EventCameraControlPopup)
return 1

# Shift - ] (Debug - currently mouse-overd unit, health += 10
elif (self.bAllowCheats and theKey == int(InputTypes.KB_LBRACKET) and self.bShift ):
unit = CyMap().plot(px, py).getUnit(0)
if ( not unit.isNone() ):
d = min( unit.maxHitPoints()-1, unit.getDamage() + 10 )
unit.setDamage( d, PlayerTypes.NO_PLAYER )

# Shift - [ (Debug - currently mouse-overd unit, health -= 10
elif (self.bAllowCheats and theKey == int(InputTypes.KB_RBRACKET) and self.bShift ):
unit = CyMap().plot(px, py).getUnit(0)
if ( not unit.isNone() ):
d = max( 0, unit.getDamage() - 10 )
unit.setDamage( d, PlayerTypes.NO_PLAYER )

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F1)):
if ( self.bShift ):
CvScreensInterface.replayScreen.showScreen(False)
return 1
# don't return 1 unless you want the input consumed

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F2)):
if ( self.bShift ):
import CvDebugInfoScreen
CvScreensInterface.showDebugInfoScreen()
return 1

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F3)):
if ( self.bShift ):
CvScreensInterface.showDanQuayleScreen(())
return 1

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F4)):
if ( self.bShift ):
CvScreensInterface.showUnVictoryScreen(())
return 1
return 0
Place the snippet after return 1 and before return 0.

def onKbdEvent(self, argsList):
'keypress handler - return 1 if the event was consumed'

eventType,key,mx,my,px,py = argsList
game = CyGame()

if (self.bAllowCheats):
# notify debug tools of input to allow it to override the control
argsList = (eventType,key,self.bCtrl,self.bShift,self.bAlt,mx ,my,px,py,CyGame().isNetworkMultiPlayer())
if ( CvDebugTools.g_CvDebugTools.notifyInput(argsList) ):
return 0

if ( eventType == self.EventKeyDown ):
theKey=int(key)

CvCameraControls.g_CameraControls.handleInput( theKey )

# Shift - T (Debug - No MP)
if (self.bAllowCheats and theKey == int(InputTypes.KB_T)):
if ( self.bShift ):
self.beginEvent(CvUtil.EventAwardTechsAndGold)
#self.beginEvent(CvUtil.EventCameraControlPopup)
return 1

# Shift - ] (Debug - currently mouse-overd unit, health += 10
elif (self.bAllowCheats and theKey == int(InputTypes.KB_LBRACKET) and self.bShift ):
unit = CyMap().plot(px, py).getUnit(0)
if ( not unit.isNone() ):
d = min( unit.maxHitPoints()-1, unit.getDamage() + 10 )
unit.setDamage( d, PlayerTypes.NO_PLAYER )

# Shift - [ (Debug - currently mouse-overd unit, health -= 10
elif (self.bAllowCheats and theKey == int(InputTypes.KB_RBRACKET) and self.bShift ):
unit = CyMap().plot(px, py).getUnit(0)
if ( not unit.isNone() ):
d = max( 0, unit.getDamage() - 10 )
unit.setDamage( d, PlayerTypes.NO_PLAYER )

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F1)):
if ( self.bShift ):
CvScreensInterface.replayScreen.showScreen(False)
return 1
# don't return 1 unless you want the input consumed

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F2)):
if ( self.bShift ):
import CvDebugInfoScreen
CvScreensInterface.showDebugInfoScreen()
return 1

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F3)):
if ( self.bShift ):
CvScreensInterface.showDanQuayleScreen(())
return 1

elif (self.bAllowCheats and theKey == int(InputTypes.KB_F4)):
if ( self.bShift ):
CvScreensInterface.showUnVictoryScreen(())
return 1
## Place Snippet Below Here

## But Above Here
return 0
If you follow those instructions you shouldn't have any problems.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Zebra 9
May 25, 2007, 07:48 PM
Any File
Python Activated Always War/Peace<Back To Top>
Author: Dale (Gaius Octavius posted a more basic version first)
Author's Post: Here Post 72
The following snippet allows python to turn on/off always war/peace. The code is as follows:

def resetWarPeace(self, bValue):
for iPlayerLoop1 in range(gc.getMAX_PLAYERS()):
if(gc.getPlayer(iPlayerLoop1).isAlive()):
for iPlayerLoop2 in range(gc.getMAX_PLAYERS()):
if(gc.getPlayer(iPlayerLoop2).isAlive()):
gc.getTeam(gc.getPlayer(iPlayerLoop1).getTeam()).s etPermanentWarPeace(iPlayerLoop2, bValue)
Place in whatever python file you are working with. Then all you need to call is resetWarPeace(true) (for always war) or resetWarPeace(false) (for always peace).
If you have any problems or need help post here and someone is bound to help.:thumbsup:

http://forums.civfanatics.com/uploads/91501/HBar.gif

Zebra 9
Jun 08, 2007, 06:20 PM
Added a new snippet. :D :thumbsup: ;) :)

Shqype
Jun 08, 2007, 06:43 PM
Yea! I love these snippets.

http://forums.civfanatics.com/showthread.php?t=152856&page=3

I tried to get that thread stickied. Make sure you add it there.

Also, please add this thread to your signature ;)

Ambreville
Jun 08, 2007, 07:06 PM
Awesome! I'll be visiting on a regular basis. :goodjob:

Do you also offer gift-wrapping? :mischief:

Ambreville
Jun 10, 2007, 03:09 PM
Zebra -- Here's another one...

How difficult would it be to allow a specific unit (a canoe for example) to ONLY be able to move along rivers, and at a MV rate of 2 upstream, and 3 downstream?

Ambreville
Jun 11, 2007, 08:23 AM
And another...

I call that one the "Thumbtack" function. :)

Is it just me, or are there other people who feel the same way about the computer systematically selecting a unit to be played in other area than the one you're trying to focus on at the time, preferably an area exactly on the other end of the map!? :rolleyes:

This can get tedious and really frustrating.

There is nothing more annoying with CIV games when the computer jumps about, selecting some random unit as the one to be played next. One thing the games doesn't do well, is picking the next closest unit as the next one in line (unless dealing with units in the same stack).

Arguably, one can turn off the "unit cycling" option, but it's inconvenient and confusing, as well as making it obviously far more likely to "forget" to play some vital units. This is why I thought of the "thumbtack".

What does the thumbtack intend to do?

The idea is to keep the automatic unit cycling option on, and still force the game to stay focused on a given area of the map. This allows the player to focus on that specific map area until ready to move on -- without having to constantly fight with the game!

When a player deals with a map area requiring some focus, the player would be able to toggle the thumbtack on, using a hotkey, which would force the chosen map area to remain on the screen, regardless of what unit the computer selects as the next in line to be played. When done, toggle the thumbtack off, and keep on playing as usual (etc).

I think some coding for that would be ideal for big, complicated scenarios... Any interest?

Zebra 9
Jun 11, 2007, 08:51 AM
How difficult would it be to allow a specific unit (a canoe for example) to ONLY be able to move along rivers, and at a MV rate of 2 upstream, and 3 downstream?It's possible, but would be quite the hack done from python. It's more of an SDK thing.

So basically the "Thumbtack" idea would be just a way to toggle the "Unit Cycling" option on and off w/ the keyboard, right? I don't think that would be too hard.

Ambreville
Jun 11, 2007, 11:04 AM
So basically the "Thumbtack" idea would be just a way to toggle the "Unit Cycling" option on and off w/ the keyboard, right? I don't think that would be too hard.

No, no, no, the unit cycling stays on. What the thumbtack does it force the map to stay centered where the player wants, regardless of what unit the computer has selected as the next to be played. You ought to be able to toggle the thumbtack function on and off of course.

Zebra 9
Jun 12, 2007, 10:27 AM
So it could be done by turning the unit cycleing off then back on.

Ambreville
Jun 12, 2007, 10:31 AM
So it could be done by turning the unit cycleing off then back on.

No. Have you ever tried playing with unit cycling off? It sucks -- I think the interface is very confusing.

I mean for the unit cycling to remain ON. When the "thumbtack" is also ON, the map stays centered as the player needs, regardless of the next unit in line. When the thumbtack is toggled OFF, the computer zooms back to the next unit in line at that point... I thought I was being clear. :confused:

Zebra 9
Jun 12, 2007, 10:40 AM
Yes, you are being clear, but I was saying what i thought might work. I will see what I can do. :thumbsup:

Ambreville
Jun 12, 2007, 10:42 AM
Yes, you are being clear, but I was saying what i thought might work. I will see what I can do. :thumbsup:

You are correct in saying that the simple approach is just to toggle the unit cycling ON & OFF. That's what I tried to do initially. It's just I find the unit cycling in the OFF mode just wrechedly bad! ;)

Thanks for checking into my harebrained ideas!

Ambreville
Jun 13, 2007, 06:21 PM
Here another idea. I didn't find this one anywhere in this part of the forum.

Effect: What I'm looking is to make a unit become temporarily "invisible" when it fortifies itself in a space. It stays hidden from view until it moves again or until an enemy unit "bumps into" it. At that point, the hiding unit is revealed and gets a free first attack with maximum damage.

Conditions: the unit needs to have either double-Woodsman promotions OR double-Guerilla promotions. Obviously, the ambushing unit must be in the proper type of terrain/feature for the ambush to work. If there's more than one such hiding unit, they all get to attack first. (This has nothing to do with the Ambush promotion against Armor.)

A nice touch would add a line in the event log, such as "AMBUSH!!!" with some sound. :mischief:

I wanted this for my scenario (17th Century European troops vs. American Indian warriors). It would be a way for low combat value native troops to fight against musket-toting military. Native scouts and spies (not explorers) should be able to see a unit hiding in ambush, just like destroyers reveal subs, which would negate the special ambush combat bonus.

Other mod designers might be interested in something like this, say for a hidden bunker position w/machinegun or AT gun units. Airplanes can't spot them... you need a recon unit or a spy to reveal them.

I'm assuming subs already use part of what I'm looking for, but this goes only half-way. By the way, do subs get a bonus when a naval unit runs into it when it couldn't see the sub? It doesn't look so.

Interested??

Shqype
Jun 13, 2007, 07:19 PM
It sounds good, but granting an automatic maximum strength first attack may be too much, since it's not guaranteed that the ambush will be successful, and even if it is, it may only be partially so.

It is a nice idea, though.

Ambreville
Jun 13, 2007, 10:39 PM
It sounds good, but granting an automatic maximum strength first attack may be too much, since it's not guaranteed that the ambush will be successful, and even if it is, it may only be partially so.

I'm a bit confused by your sentence. The two parts of your answer seem to be conflicting. How can the max strength combat bonus be too much if there is no guarantee the ambush will work in the first place? The combat bonus compensates for the fact there is no guarantee anyone will "bump" into the hidden unit, and the unit may have to remain in place for quite some time before anything happens.

And how can the ambush be partially successful? It either is or not.

The reason why I'm thinking about a big combat bonus is that it only works if an enemy unit "bumps" into the hidden one. That's the only way I intended for the bonus to kick in. That's the main point of the ambush.

Otherwise, if you move the unit from its hiding place, it becomes visible and it therefore loses its ambush bonus. Even this way though, it's still useful because the subterfuge may still allow your unit to intercept unsupecting enemies passing by.

Does this make more sense?

-----------------------------------------------

EDIT

I know where the confusion comes from. I wrote in my original post something about a "free first attack with maximum damage". What I meant was that if an enemy unit bumps into the one waiting in ambush, the ambushing unit gets a big combat bonus at the very least, and a first strike chance (as in the Drill promotion). Better?

Zebra 9
Jun 14, 2007, 05:22 PM
That sounds like it would require SDK. It might be possible w/ the Sniper MOD (and some Python MODing).

Ambreville
Jul 03, 2007, 05:51 AM
Greetings & Salutations! :lol:

I need a mod comp that ties a unit promotion to a particular bonus. For example: I have a "Horse" promotion that allows qualifying infantry or artillery to benefit from horse transportation (in exchange for a combat penalty). This promotion should be given to a unit only when the Horse bonus is available. If not, it does not appear in the list of promotions when the unit qualifies for one. If a note appears in the Tech Tree showing that Horse is needed for the promotion, great, but I would just as happy with the comp, even without the Tech Tree notification. Would you have time to do something like this?

Thanks, and welcome back! ;)

Shqype
Jul 03, 2007, 06:09 AM
Have you ever considered learning Python?

Ambreville
Jul 03, 2007, 06:12 AM
Have you ever considered learning Python?

Shqype, are you trying to tell me something here? :mischief:

(But to answer your question, yes... and got totally confused. I'm not much of a coder I guess).

Shqype
Jul 03, 2007, 07:05 AM
It is often times better to get things done your way when you do them yourself, instead of relying on other people.

Granted, not all of us are coders, but if you've tried then that counts for something. As long as you're not one of those lazy people that don't try to do anything for themselves and expect others to do everything for them.

But I would recommend giving it another shot, assuming you've got the patience. There are some good tutorials on the forums that can help get you started.

Ambreville
Jul 03, 2007, 07:42 AM
It is often times better to get things done your way when you do them yourself, instead of relying on other people.

Granted, not all of us are coders, but if you've tried then that counts for something. As long as you're not one of those lazy people that don't try to do anything for themselves and expect others to do everything for them.

But I would recommend giving it another shot, assuming you've got the patience. There are some good tutorials on the forums that can help get you started.

Considering the amount of work I've put into my sole and only mod (and first attempt at anything like that thus far), I've accomplished and learned far more than I though I would ever in that field.

Python remains totally confusing to me and I doubt I'll be able to accomplish much in that area anytime soon. On the other hand, if Zebra9 gets tired of my ideas, I'm sure he's a big boy and can tell me himself -- no offense meant or taken on my part. ;)

Zebra 9
Jul 03, 2007, 08:30 AM
I'll let you know if I get tired of getting tons of credit for your ideas HeHe. lol :lol:

I think I've got the "Thumbtack" ability workin g I'll get it up tomorrow. :thumbsup:

I'll start working on the promo idea as an expansion for zPromotions.

Ambreville
Jul 03, 2007, 10:19 AM
I'll let you know if I get tired of getting tons of credit for your ideas HeHe. lol :lol:

Indeed, and you're welcome! :lol:

I think I've got the "Thumbtack" ability workin g I'll get it up tomorrow. :thumbsup:

I'll start working on the promo idea as an expansion for zPromotions.

Thanks alot for doing, as some might put it, everything for me! :mischief:

Gaius Octavius
Jul 08, 2007, 12:06 PM
Zebra 9, I was wondering if you could tell me what exactly is the Python call that determines a Great Person's type (artist, prophet...)

I am looking to update my Civ-Specific Great People mod to Python-only (much cleaner) using TheLopez's No-Name Great Person Renamer mod. However, there is no distinction in his code among great person type.
http://forums.civfanatics.com/showthread.php?t=168367

EDIT: Let me be more specific...

What I want the game to do is look at the unit, get its type, and select a name based on that type. For example I have:

...
def onGreatPersonBorn(self, argsList):
'Great Person Born'
pUnit, iPlayer, pCity = argsList
player = PyPlayer(iPlayer)
infoUnit = pUnit.getUnitClassType()
# Check if we should even show the popup:
if pUnit.isNone() or pCity.isNone():
return

if(len(pUnit.getNameNoDesc()) == 0):

iCivilizationType = player.player.getCivilizationType()

pUnit.setName(NameUtils.getCivilizationName(iCivil izationType, infoUnit))
...


which calls


if (infoUnit == gc.getInfoTypeForString("UNITCLASS_PROPHET")):
if(len(civilizationNameHash[strCivilizationType]["GP"]) > 0):
strGP = civilizationNameHash[strCivilizationType]["GP"][gc.getGame().getMapRand().get(len(civilizationName Hash[strCivilizationType]["GP"]), "Random Name")]
strName = string.capwords(strGP)

return strName


for a Great Prophet. There's something going wrong here, but I can't see where. At first I thought it was in the comparison check, but that seems to work.

Sorry for any thread hijack. :D

EmperorFool
Jul 08, 2007, 10:20 PM
At first I thought it was in the comparison check, but that seems to work.

Sorry to hijack your hijack, but this part is unclear to me. Your code to check the UnitClass seems fine, but if it's not detecting the type of GP correctly, you could go off of the UnitType instead.


unitType = pUnit.getUnitType()
...
if (unitType == gc.getInfoTypeForString("UNIT_PROPHET")):
...


But again, you said this part is actually working. How have you tested it? Did you print out debug statements inside the if-test? If so, also print out the len of the hash (list) of names and the random number you get.

I don't know how you're printing stuff for debug, but assume you have a function on NameUtils called debug().


if (...):
self.debug("Profit!!!")
nameList = civilizationNameHash[strCivilizationType]["GP"]
if (nameList):
self.debug("Found %d names" %len(nameList))
rand = gc.getGame().getMapRand().get(len(nameList), "Random Name")
self.debug("Got random # %d" %rand)
strGP = nameList[rand]
self.debug("Chose name %s" %strGP)
strName = string.capwords(strGP)
return strName


The other thing I noticed is that you pass iCivilizationType to NameUtils, but you use a variable called strCivilizationType to look up the correct list of names. Is there a conversion/lookup I'm missing, perhaps InfoType -> String?

You also have


player.player.getCivilizationType()


Is that a typo? If so, is it in your code or only your post?

Gaius Octavius
Jul 08, 2007, 10:41 PM
Thanks for the response. I don't have the debug printout here right now, but I'll try to get it later.

That last "player.player" looked fishy to me, too. That's how it was in TheLopez's mod, which worked. I also originally had Unit Type, not Unit Class, but then it occurred to me that class would be better since you might have multiple kinds of great people per class (long story).

EmperorFool
Jul 08, 2007, 10:48 PM
I agree that testing against unit class is the better option, but I wasn't sure if you meant that part was or was not working. If it wasn't working, I'd try unit type just to verify sanity. :)

I see that you are using


player = PyPlayer(iPlayer)


I haven't used PyPlayer before so I'm unfamiliar with it. I assume it's a Python wrapper for the player # (since that's what you give it when creating it). It probably exposes "player" as the CyPlayer obtained using something like


player = gc.getPlayer(iPlayer)


I wish there was more extensive documentation on the API. I'd have no chance without all the mods already out there from which to scavenge example code. I still can't find any information on the GUI toolkit functions. :(

Zebra 9
Jul 09, 2007, 09:34 AM
The PyPlayer returns a player object that contains alot of stuff that is not in the SDK but is actally in python. When someone uses player.player I believe it's the same as using gc.getPlayer(iPlayer). So I think you should change the PyPlayer(iPlayer) to gc.getPlayer(iPlayer), but of course I don't know what your code looks like. Now from what you are saying you want to change the units type, right? If so you will have to change the SDK so that it does it or makes a python call.

P.S I think I just thought of some way it can be done from python.

Zebra 9
Jul 09, 2007, 10:00 AM
Added the Thumbtack Snippet. Here (http://forums.civfanatics.com/showpost.php?p=5481382&postcount=2)

Ambreville
Jul 09, 2007, 10:10 AM
Added the Thumbtack Snippet. Here (http://forums.civfanatics.com/showpost.php?p=5481382&postcount=2)


Thank you!! :clap:

Gaius Octavius
Jul 09, 2007, 12:04 PM
Actually, I'm not looking to change the UnitType, just the individual name, e.g. so a Great Scientist born to England will be named Isaac Newton, Stephen Hawking and so on, instead of Plato or other non-English.

I'll try to fiddle around with it some more today and once it's working I'll post it here. :D This has lots of possibilities outside of great people. Suppose you wanted to give any unit a unique name. Normally, you'd just add the names in the <UniqueName> tag in XML. But this isn't civ-specific--suppose you want to have ship names like the Yamato or Nagato for the Japanese, and the Arizona and Missouri for America. You can't do that in XML, because any name will go for any civ.

Ambreville
Jul 09, 2007, 02:23 PM
Actually, I'm not looking to change the UnitType, just the individual name, e.g. so a Great Scientist born to England will be named Isaac Newton, Stephen Hawking and so on, instead of Plato or other non-English.

I'll try to fiddle around with it some more today and once it's working I'll post it here. :D This has lots of possibilities outside of great people. Suppose you wanted to give any unit a unique name. Normally, you'd just add the names in the <UniqueName> tag in XML. But this isn't civ-specific--suppose you want to have ship names like the Yamato or Nagato for the Japanese, and the Arizona and Missouri for America. You can't do that in XML, because any name will go for any civ.

I see where you're going with this. It's very exciting! I had toyed with a "France 1940" scenario before getting "AD1640 North America" underway. The reason for the switch was that I wanted to identify all the divisions and generals by name/number to provide a startup as historical as possible. After failing miserably in this respect (and having a hopelessly-pacifistic AI foiling my most-bellicose-expectations for the blitzkrieg), I sailed for the New World. Sigh... :lol:

Gaius Octavius
Jul 09, 2007, 02:51 PM
I just tested TheLopez's "No-Name Renamer" mod for Great People in Warlords, and it worked. (It was written for Vanilla 1.61, so I was afraid it might just be Warlords.) Since I did not change the fundamental mechanism except for adding the unit type check, I assume something's going wrong there.

I'll be back. ;)

BTW, Ambreville, there is a way to get around this problem in XML only... just create a bunch of new units like "French Battleship" and give them the civ-specific names. :D Of course, this'll add about 100 new units to the game... :crazyeye: You can see why I'm eager to switch to Python.

Ambreville
Jul 09, 2007, 02:59 PM
BTW, Ambreville, there is a way to get around this problem in XML only... just create a bunch of new units like "French Battleship" and give them the civ-specific names. :D Of course, this'll add about 100 new units to the game... :crazyeye: You can see why I'm eager to switch to Python.

Thanks for the tip. Can I do that for great generals too?

And how do I make sure a specific unit on the map has "the" correct name out of the list??

Gaius Octavius
Jul 09, 2007, 04:01 PM
Yes. This is I how I currently have the Great People mod set up. Each civ gets a UU for each great person. However, there is a bug in SDK that prevents GG's from using this properly, but luckily Mexico found it and squashed it.

I've had a lot of problems renaming units in worldbuilder, too. In my WWII mod, I originally had all the units named, but once I saved it they all disappeared. :( Unfortunately, in Warlords, there is no way to make sure that units will have the "correct" name, as they are assigned randomly from the <uniquenames> list when they are built. Mexico also developed a mod that goes back to Vanilla's sequential ordering (meaning the first one in the list is the first to be used, and so on) but I don't know if that will solve your problem.


EDIT: Never mind, Zebra! Thanks to everybody for the advice. I finally got it to work!

You'll never believe what one of the problems was: I'd renamed the file to CivSpecificGreatPeopleModNameUtils instead of CvCivSpecificGreatPeopleModNameUtils. :wallbash: I swear, I do silly things like this all the time...

Ambreville
Jul 09, 2007, 04:10 PM
I've had a lot of problems renaming units in worldbuilder, too. In my WWII mod, I originally had all the units named, but once I saved it they all disappeared. :(

Yup. Same here.

Unfortunately, in Warlords, there is no way to make sure that units will have the "correct" name, as they are assigned randomly from the <uniquenames> list when they are built. Mexico also developed a mod that goes back to Vanilla's sequential ordering (meaning the first one in the list is the first to be used, and so on) but I don't know if that will solve your problem.

I could see doing it this way, if there were a way to keep track of the order in which I placed unit types on the map. This could be hellishly complicated! :eek:

No chance this will be improved in BtS? :confused:

Gaius Octavius
Jul 09, 2007, 04:26 PM
Theoretically, you should be able to see the new names once you place them on the map, which would make keeping track of them easier. But it's still complicated.

Okay, another question for the wise Zebra 9... ;)
The unit renamer now works, but it does not rename the event message in the upper left corner, "Great Scientist has been born in Washington!" The actual Great Scientist was correctly renamed to Albert Einstein (or whatever). How do I change the event display to reflect the new name? What's the command for passing it back to the event manager?

What we really need is an index of Python functions in Civ 4.

EmperorFool
Jul 09, 2007, 05:28 PM
Congrats on getting it working!. :goodjob:

The unit renamer now works, but it does not rename the event message in the upper left corner, "Great Scientist has been born in Washington!"

I can't say for sure, but I suspect you may be stuck with this unless you want to modify the C++ DLL. The problem is that you're intercepting an event telling you that a great person was born and placed on the map. It's likely already displayed the message.

What we really need is an index of Python functions in Civ 4.

This site (http:///files/modding/PythonAPI_v160/) contains the API for most of the Python objects exposed to you. It's lacking some (like the GUI widgets), but it's a start. I learned most everything from Ruff Hi's Cobbled SG Mod. Working code is a great instructor. In fact, that mod -- a collection of a ton of other modpacks -- includes a unit renamer so you get things like "Warrior 3 from Calcutta".

Gaius Octavius
Jul 09, 2007, 05:36 PM
Congrats on getting it working!. :goodjob:
This site (http:///files/modding/PythonAPI_v160/) contains the API for most of the Python objects exposed to you. It's lacking some (like the GUI widgets), but it's a start.

Thanks for that. :king:

I can't say for sure, but I suspect you may be stuck with this unless you want to modify the C++ DLL.

Hopefully not. But Zebra 9 can do amazing things with python, so I'm hopeful. :mischief:

Zebra 9
Jul 10, 2007, 09:49 AM
I still have to check into it but I think it's SDK only. I'll check.

Well, I was just thinking, it might be possible to remove them as Great People in the XML. If I did this the SDK would not put the Message then w/ Python I could display whatever message you want. :hmm:

Gaius Octavius
Jul 12, 2007, 06:12 PM
Zebra 9, do you know if there is a way to limit how far a unit can travel from its civ's cities or cultural borders? Specifically, what I'm thinking about is limiting the exploration of an entire continent until a certain game date (whereupon the check would automatically be turned off, to increase game speed). This way you won't have lots of the map uncovered until later in the game.

I think there may be a mod that does this already...

Zebra 9
Jul 13, 2007, 01:47 PM
I believe I can do it, if not it will be possible in BtS.

cromcrom
Jul 23, 2007, 01:27 PM
I have python questiions please.

def onGreatPersonBorn(self, argsList):
'Great Person Born'
pUnit, iPlayer, pCity = argsList
player = PyPlayer(iPlayer)
infoUnit = pUnit.getUnitClassType()
# Check if we should even show the popup:
if pUnit.isNone() or pCity.isNone():
return

if(len(pUnit.getNameNoDesc()) == 0):

iCivilizationType = player.player.getCivilizationType()

pUnit.setName(NameUtils.getCivilizationName(iCivil izationType, infoUnit))



What is "argsList" first line (self, argsList):?
Why do 'Great Person Born' comes between quotes ?
Wherre do PyPlayer(iPlayer) pyPlayer come from ?

I MUST learn python in order to have my mod working. Its a brand new concept that will rock....

Please.
Thanks in advance....

Civkid1991
Jul 23, 2007, 02:15 PM
I have python questiions please...
Why do comes between quotes ?


i think that the quotes turn whats inside them into a comment

Zebra 9
Jul 23, 2007, 05:19 PM
The argsList is an argument that is passed to that python function from the SDK as a tuple. The contents of this tuple varies from 1 function to the other.

And yes 'Great Person Born' is just a comment. I dilike using any comment type other then the pound symbol (#) because they tend to look too much like strings and the triple quote sometimes makes the comment blend w/ the code making the code very confusing.

PyPlayer comes from the PyHelpers (I think that's what it's called) module which is imported at the top of the file then just below the import you have a line like PyPlayer = PyHelper.player. A PyPlayer instance gives you some controls that allow you to change some things about a player. I personally prefer the gc.getPlayer system.

Jeckel
Jul 23, 2007, 09:49 PM
The comment line in "" that comes after each function or method definition is considered good python syntax and is used by certain programs to gather information about the function. One of the standard python pdf documents explains it all, but one good example is the python IDLE editor. When you start to type a function or method and it shows you the popup with what arguments are needed it will also display that first comment line. Not that important for Civ4, but good python knowledge. :)

cromcrom
Jul 24, 2007, 04:42 AM
Thanks a lot for your time people ^^.
Now
The contents of this tuple varies from 1 function to the other.
So How do I know this content? Where does it comes from ?

What relation with this pUnit, iPlayer, pCity = argsList?

Zebra 9
Jul 24, 2007, 09:58 AM
pUnit, iPlayer, pCity = argsListThat is the code that is used to unpack the argsList tuple. You might also see code like this:pUnit = argsList[0]
iPlayer = argsList[1]
pCity = argsList[2]I havn't found any python functions in the eventmanager or game utils that didn't already have the unpack line(s). So if you keep your original files you can run a search for the function name in the appropriate file and just copy the unpack line(s).

Wow, you learn somthing new everyday. I didn't know that Jeckel. Now is that just for single quotes, I would think so?

cromcrom
Jul 24, 2007, 12:15 PM
ok, tx a lot, it is getting clearer.
I will go back study by myself, and certainly come back with new questions, AND I WILL DO THIS MOD.

Thanks again for your time, people.

Jeckel
Jul 24, 2007, 12:55 PM
No, as a matter of fact, the proper syntax is to use triple quotes for the main doc strings. For example,
def aMathFunc(iA, iB):
"""Return result of some math"""

And if you use the triple quotes, for those that don't know, you could also do somthing similar to this,
def aMathFunc(iA, iB):
"""Return result of some math

A math function in a module that takes two int numbers
and does some math to them. It will then return an int
number."""

If you are interested, here is a zip of an rtf text file (http://forums.civfanatics.com/uploads/70323/Python_Doc_Strings.zip). I grabed it from one of the main python site and is the excepted syntax for using doc strings. Its not that long or well written, but it has all the important info. :)

Zebra 9
Jul 25, 2007, 08:08 AM
Thx Jeckel. :thumbsup:

cromcrom just keep asking. ;)

cromcrom
Jul 28, 2007, 02:54 AM
Hi again.
I am looking for


isCivilizationDisableTech

I know it is a bool from cvCivilizationInfo.

Where can I find this class (if I understand well, "cvCivilizationInfo" is a class? )
please?

Zebra 9
Jul 28, 2007, 11:54 AM
Well use the CyGlobalContext (usualy it has been assingned to the gc variable) class' getCivilizationInfo function like this:tech = gc.getInfoTypeFor("TECH_WRITING")
civ = gc.getInfoTypeForString("CIVILIZATION_AMERICA")
gc.getCiviliztionInfo(civ).isCivilizationDisableTe ch(tech)Now just so you know, the isCivilizationDisableTech returns a boolean value (True or False).

cromcrom
Jul 28, 2007, 01:20 PM
Yes, all I need now is a "setCivilizationDisableTech"

Then I think I will go, in the TechResearched event, to get a list off all remaining Techs, and randomly pick a tech from it, and then "setCivilisationDisable" it, as the "disable" integer is part of the technologies description.

Ok, so where can I find CyGlobalContext ?

is it part of Python or from the SDK ? Because I can't find it nowhere in the Py files....

EmperorFool
Jul 28, 2007, 03:01 PM
You don't get the py file for it. It's part of the compiled package that is imported when you import PythonExtensions (iirc) at the top of your py file. All the main cIV py files import it, so just copy that line.

Also, this site (http:///files/modding/PythonAPI_v160/) is a good reference for all the available functions. My guess is that you cannot dynamically alter that setting as you'd like. That class has no corresponding setXXX() function.

The Info classes tend to encapsulate read-only information on the basic data for cIV, but don't quote me. :)

cromcrom
Jul 28, 2007, 11:05 PM
Thanks for answering,

main cIV py files import it, so just copy that line.
Yeah ok, but do they import it from? Does it just come from nowhere?

That class has no corresponding setXXX() function
Isn't there a way to create new functions ? I can do this all the time in the NWN2 (an RPG) editor... Wasn't the SDK released just for that?

you see why I have a problem with python now? I am . .. .. .. .ing not being lazy, spending tons of hours just trying to understand things.....

I am so upset to have to learn a whole new programming language just because of a tiny code stuff.

But that mod will be so great, I have to do it.....

EmperorFool
Jul 29, 2007, 12:18 PM
My advice is to post a new thread detailing what you want to do. Give it a topic that tells people what it's about. This thread is not going to attract the same people that might be able to answer your question, possibly.

You can add all the functions you want in Python, but the game needs to make use of them. All of the Python classes are wrappers around the C++ classes that the game core DLL uses. They provide access via Python to the core logic without forcing you to use C++. However, not everything can be done via Python. Many mods create their own DLL by modifying the game's C++ code. This is possible but more work.

Therefore, if you start by stating what you want to have happen, maybe someone has a way to do it.

Me101
Dec 11, 2007, 07:57 PM
I used your code for adding a religion requirement for certain civics. My friends and I have created a new civic temporarily called "Jihad", and we want to make it require the Islam religion. Snippet:

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
religion = "RELIGION_ISLAM"
civic = "CIVIC_JIHAD"
## If The Civ Doesn't Have The Correct Religion Tell the SDK Not To Allow The Player To Chose This Civic
if eCivic == gc.getInfoTypeForString(civic):
if gc.getPlayer(ePlayer).getStateReligion() != gc.getInfoTypeForString(religion):
return True

return False

The problem is, once I input this code into the mod's Assets/Python/CvGameUtils.py file, and then load a game to test, I cannot see the control panel on the bottom of the screen. Do you know why?

EmperorFool
Dec 12, 2007, 02:09 PM
Don't change the files in Assets. It makes recovering from errors more difficult. Instead, create a copy of the file you want to change under


C:\Documentss and Settings\
MyDocuments\
My Games\
Beyond the Sword\
CustomAssets\


Put it in the same folder structure as it was in Assets. Any files in CustomAssets override those in Assets as long as you're not playing a mod. This is covered in more depth in one of the stickied basic's of modding threads.

Regarding your code, it looks like you have the incorrect indentation under the last "if". In Python, whitespace indentation is important. I see a space where you should have a tab. Below, "^" should be a tab.


if gc.getPlayer(ePlayer).getStateReligion() != gc.getInfoTypeForString(religion):
^return True


When the game cannot understand your Python, oftne the result is a blank interface (just a map, no buttons). You can enable logging (see the CivIV.ini file in "My Games\BtS") to have the problems in your code written to a file, PythonErr.log, in that same folder's "logs" folder.

Me101
Dec 12, 2007, 02:25 PM
Wow, I'm so used to C++/Java that I didn't know that python considered whitespace important. Thank you, I think I will go read some stuff on python and whitespace now.

Me101
Dec 12, 2007, 05:03 PM
Well, I fixed the earlier problem, but now a new one has arisen. The code doesn't do anything. I have it written exactly as it should, and I don't get any interface errors.

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]

if eCivic == gc.getInfoTypeForString("CIVIC_HEREDITARY_RULE"): # The Civic That We Are Working With
if gc.getPlayer(ePlayer).getStateReligion() != gc.getInfoTypeForString("RELIGION_JUDAISM"): # The Religion That Is Required For The Civic
return True

return False

The whitespace is correct, but I can still switch to hereditary rule even if I am not jewish. What is wrong here?

EmperorFool
Dec 12, 2007, 10:07 PM
Try outputting some debug info as you go using addImmediateMessage(message, sound). The second parameter I just leave blank (not sure if None works).


def debug(msg):
"Print a debug message. Define this near the top (anywhere really) outside of any class definitions."
CyInterface().addImmediateMessage(msg, "")

...

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]

debug("player = %d" % ePlayer)
debug("civic = %d" % eCivic)

if eCivic == gc.getInfoTypeForString("CIVIC_HEREDITARY_RULE"):
debug("Hereditary Rule")
if gc.getPlayer(ePlayer).getStateReligion() != gc.getInfoTypeForString("RELIGION_JUDAISM"):
debug("Not Judaism")
return True

debug("Enjoy your new civic!")
return False


The messages will display along with other game messages but do not show up in the message log (alt-tab). They appear for a few seconds and then vanish.

But looking at the C++ source,


if(GC.getUSE_CANNOT_DO_CIVIC_CALLBACK())
{
CyArgsList argsList2; // XXX
argsList2.add(getID());
argsList2.add(eCivic);
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "cannotDoCivic", argsList2.makeFunctionArgs(), &lResult);
if (lResult == 1)
{
return false;
}
}


I realize why it doesn't work. With BtS Firaxis added flags to tell which Python callbacks like this should be called. They are in PythonCallbackDefines.xml:


<Define>
<DefineName>USE_CANNOT_DO_CIVIC_CALLBACK</DefineName>
<iDefineIntVal>0</iDefineIntVal>
</Define>


Change the 0 to a 1 and see if that works. Again, you should be modifying copies of these files in CustomAssets. If you aren't going to follow that advice, at least back up your Assets folder so you won't have to reinstall to fix a broken game. ;)

Me101
Dec 13, 2007, 11:18 AM
This is for a mod, so the assets folder is backed up in the normal BtS folder. Thank you for the advice.

Zebra 9
Dec 13, 2007, 05:37 PM
Let us know if it works. :)

Me101
Dec 13, 2007, 05:47 PM
It does, thank you very much. You may want to update this code and/or the instructions so it works with BtS. Specifically relating to above stated file.

Thanks again people.

Psychic_Llamas
Jan 02, 2008, 01:03 AM
Hey Zebra,

just want to say thanks for these snippets, they are great :D

but, a quick question,
with the leader specific units, how do i make it so that each and every leader has its own unit? im new to python, so please excuse me if this has a blatantly obvious answer :p

Grey Fox
Jan 02, 2008, 02:30 AM
About the Thumbtack system. Alt-C is a pretty bad shortcut to use since Alt selects all units on the current tile, so if any units have moves left you will select the current stack instead of turning off (or on) the unit cycling.

Zebra 9
Jan 02, 2008, 01:50 PM
Well if you want to do that you just need to duplicate the code as many times as you want. Example: leader = Leader Type ## The Leader
unit = Unit Type ## The Unit

## If The Civ Doesn't Have The Correct Leader Tell the SDK Not To Allow The Player To Construct This Building
if eUnit == gc.getInfoTypeForString(unit):
leaderType = gc.getLeaderHeadInfo(gc.getPlayer(pCity.getOwner() ).getLeaderType()).getType()
if leaderType != gc.getInfoTypeForString(leader):
return True

leader = Leader Type ## The Leader
unit = Unit Type ## The Unit

## If The Civ Doesn't Have The Correct Leader Tell the SDK Not To Allow The Player To Construct This Building
if eUnit == gc.getInfoTypeForString(unit):
leaderType = gc.getLeaderHeadInfo(gc.getPlayer(pCity.getOwner() ).getLeaderType()).getType()
if leaderType != gc.getInfoTypeForString(leader):
return True


If you think of a better key combo let me know and I'll update the code.
To do it your self just change the bold code: ## This line checks to see if the ALT and C keys where pressed
if theKey == InputTypes.KB_C and self.bAlt:
## This turns the Unit Cycling on or off
if gc.getActivePlayer().isOption(PlayerOptionTypes.PL AYEROPTION_NO_UNIT_CYCLING):
gc.getActivePlayer().setOption(PlayerOptionTypes.P LAYEROPTION_NO_UNIT_CYCLING, False)
else:
gc.getActivePlayer().setOption(PlayerOptionTypes.P LAYEROPTION_NO_UNIT_CYCLING, True):thumbsup:

Gaius Octavius
Jan 04, 2008, 11:08 AM
In making scenarios I've found a few Python snippets that are very useful. Most are reused from stock Civ 4 mods, like Desert War, but since this is a great reference thread they are worth repeating here. :D

One such snippet:

PERMANENT WAR OR PEACE

What it does: sets every nation to permanent war or peace. This is useful because you can specify in Python exactly when or where you want this to kick in, as opposed to the main menu option, which would run all the time.

for iPlayerLoop1 in range(gc.getMAX_PLAYERS()):
if(gc.getPlayer(iPlayerLoop1).isAlive()):
for iPlayerLoop2 in range(gc.getMAX_PLAYERS()):
if(gc.getPlayer(iPlayerLoop2).isAlive()):
gc.getTeam(gc.getPlayer(iPlayerLoop1).getTeam()).s etPermanentWarPeace(iPlayerLoop2, true)

You might set this to run on the first game turn, or on a specific turn when you don't want civs prematurely ending a war that's already started. It all depends on however you want to trigger it.

Dale
Jan 04, 2008, 12:12 PM
That looks familiar. ;)

BTW, a version that allows turning it on or off:


def resetWarPeace(self, bValue):
for iPlayerLoop1 in range(gc.getMAX_PLAYERS()):
if(gc.getPlayer(iPlayerLoop1).isAlive()):
for iPlayerLoop2 in range(gc.getMAX_PLAYERS()):
if(gc.getPlayer(iPlayerLoop2).isAlive()):
gc.getTeam(gc.getPlayer(iPlayerLoop1).getTeam()).s etPermanentWarPeace(iPlayerLoop2, bValue)


Then all you need to call is resetWarPeace(true) or resetWarPeace(false). :)

Zebra 9
Jan 05, 2008, 12:23 PM
Thanks guys, I try to keep adding more stuff but its not that easy as one person. :thumbsup:

I'm going to put these on the front page of the thread. :)

Gaius Octavius
Jan 07, 2008, 06:13 AM
Hi, Zebra,

I have a question about a bit of the Desert War code, to which I'm so indebted for my crash-course in Python last May. :D

I noticed it uses the global script to store and retrieve truth values for whether a specific event occurred, such as:



def setupScriptData( self ):
"""Initialise the global script data dictionary for usage."""
scriptDict = { 'bKasserinePass': False,
'bMarethLine': False,
'bOperationBarbarossa': False,
'bMiddleEast': False,
'bStalingrad': False,
'bParisLiberated': False,
'bEnglandFallen': False,
'bCapTimerOn': False,
'bEndCapTimer': False,
'bVictoryNextTurn': False,
'bVictoryAchieved': False,
'iExtraUnitCost': 0,
'iParisLiberation': -1,
'iEnglandFalls': -1,
'iCapTimer': 0,
'iVictoryTimer': 9,
'tCapturedObjectivesList': []
}
gc.getPlayer(0).setScriptData( pickle.dumps(scriptDict) )

def isOperationBarbarossa( self ):
"""Returns if the Operation Barbarossa event already took place."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
return scriptDict['bOperationBarbarossa']

def setOperationBarbarossa( self, bNewValue ):
"""Sets that the Operation Barbarossa event took place."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
scriptDict['bOperationBarbarossa'] = bNewValue
gc.getPlayer(0).setScriptData( pickle.dumps(scriptDict) )

def getExtraUnitCost( self ):
"""Returns the Extra Unit Cost that is the result of Operation Barbarossa."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
return scriptDict['iExtraUnitCost']

def setExtraUnitCost( self, iNewValue ):
"""Sets the Extra Unit Cost that is the result of Operation Barbarossa."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
scriptDict['iExtraUnitCost'] = iNewValue
gc.getPlayer(0).setScriptData( pickle.dumps(scriptDict) )


................. [and many more functions such as these] ...................




Now, it seems at first glance that it'd be just as easy to accomplish the same thing by having dummy variables which get set to 1 or 0, depending on whether the event happened, instead of all those helper functions. So why is the script used instead here? It is because the script is saved with the game, yes? (As opposed to variables, which would get reinitialized upon reload.)

Dale
Jan 07, 2008, 11:52 AM
As one who worked with Locutus on these functions, I can confidently say, "Yes". :)

Hi, Zebra,

I have a question about a bit of the Desert War code, to which I'm so indebted for my crash-course in Python last May. :D

I noticed it uses the global script to store and retrieve truth values for whether a specific event occurred, such as:



def setupScriptData( self ):
"""Initialise the global script data dictionary for usage."""
scriptDict = { 'bKasserinePass': False,
'bMarethLine': False,
'bOperationBarbarossa': False,
'bMiddleEast': False,
'bStalingrad': False,
'bParisLiberated': False,
'bEnglandFallen': False,
'bCapTimerOn': False,
'bEndCapTimer': False,
'bVictoryNextTurn': False,
'bVictoryAchieved': False,
'iExtraUnitCost': 0,
'iParisLiberation': -1,
'iEnglandFalls': -1,
'iCapTimer': 0,
'iVictoryTimer': 9,
'tCapturedObjectivesList': []
}
gc.getPlayer(0).setScriptData( pickle.dumps(scriptDict) )

def isOperationBarbarossa( self ):
"""Returns if the Operation Barbarossa event already took place."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
return scriptDict['bOperationBarbarossa']

def setOperationBarbarossa( self, bNewValue ):
"""Sets that the Operation Barbarossa event took place."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
scriptDict['bOperationBarbarossa'] = bNewValue
gc.getPlayer(0).setScriptData( pickle.dumps(scriptDict) )

def getExtraUnitCost( self ):
"""Returns the Extra Unit Cost that is the result of Operation Barbarossa."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
return scriptDict['iExtraUnitCost']

def setExtraUnitCost( self, iNewValue ):
"""Sets the Extra Unit Cost that is the result of Operation Barbarossa."""
scriptDict = pickle.loads( gc.getPlayer(0).getScriptData() )
scriptDict['iExtraUnitCost'] = iNewValue
gc.getPlayer(0).setScriptData( pickle.dumps(scriptDict) )


................. [and many more functions such as these] ...................




Now, it seems at first glance that it'd be just as easy to accomplish the same thing by having dummy variables which get set to 1 or 0, depending on whether the event happened, instead of all those helper functions. So why is the script used instead here? It is because the script is saved with the game, yes? (As opposed to variables, which would get reinitialized upon reload.)

Gaius Octavius
Jan 07, 2008, 12:26 PM
Yeah... I think I'm indebted to you two guys more than anybody else on these forums. :D

Thanks!

Dale
Jan 07, 2008, 12:40 PM
lol in all truth, back then when those functions were written I didn't know a lot of python.

I asked him for something to track the events we were implementing, he wrote it, and I looked at it and said, "Yeah whatever, as long as it works". :lol:

It's a different story now though. ;)

Zebra 9
Jan 09, 2008, 09:00 AM
I just wish the script data was multiplayer compat (or I knew a way to make MP). When I first got civ I didn't know what python was (other then a snake), all I knew was JavaScript and HTML.

Darque
Jan 09, 2008, 09:17 AM
I take it that an SDK change would be required to make it multiplayer compatable?

Gaius Octavius
Jan 09, 2008, 10:52 AM
Well, dang. I had hoped to make my scenarios using scripts multiplayer compatible. That's not good. :(

Psychic_Llamas
Jan 09, 2008, 08:14 PM
Thanks Zebra :p

i knew it would be blatantly obvious :mischief:

Zebra 9
Jan 11, 2008, 04:28 PM
I take it that an SDK change would be required to make it multiplayer compatable?I would think so.

Your welcome Psychic_Llamas.

salaminizer
Jan 18, 2008, 05:30 AM
bah, it's time I put my python knowledge in practice again, and not by making a goddamn parsing algorithm or an image processing program) but that has nothing to do with my question :lol:

it can be a very stupid question indeed but I'm not @ home right now so I'll still ask: the cannotTrain is used in the Civilopedia? like.. if I use your leaderspecific snippet the effects will show when viewing the unit in the pedia? "you cannot train this unit" or whatever that message is?

your snippets will serve as inspiration though...

Zebra 9
Jan 18, 2008, 04:53 PM
I don't know whether it will show up in the pedia or not.

Ambreville
May 13, 2008, 02:58 PM
New snippet for those of us who just can't figure out Python?

What about a routine that can be used in a Event Description's PythonCallback to cause one specific nation to declare war on another specific one, where CIV-A is the aggressor, and Civ-B the aggressed.

Then users like me would only need to type in the actual civs' names.

Zebra 9
May 15, 2008, 08:49 AM
That isn't hard, I have several events that do this in the Navy Seal's Earth 1000AD and the Medieval Age. I'll post the code tonight, tomorrow, or Saturday.

Ambreville
May 15, 2008, 09:41 AM
That's terrific! Thanks!

Ambreville
May 22, 2008, 07:17 AM
Here's another idea: assuming there is a new building class called Radar Station in a city, would it be possible to attach a script that would give air units based in that city a bonus to intercept?

Arian
May 22, 2008, 07:37 AM
Another idea/request:

Adding a building to a city after completion of a project.

For example:
Let's say you complete SDI in a city then add a SDI-building to that city which reduces damage from nukes.
Of course you need to add a SDI-building via XML with art etc. :)

I tried using an event in XML but no success :(

Zebra 9
May 23, 2008, 05:52 PM
Here's another idea: assuming there is a new building class called Radar Station in a city, would it be possible to attach a script that would give air units based in that city a bonus to intercept?Only if you could make a promotion that did what you want then we give that promotion when they enter the city, and take it away when they leave.

Adding a building to a city after completion of a project.
Yes this is very possible, I will get a snippet in the next week.

Ambreville
May 23, 2008, 06:56 PM
Only if you could make a promotion that did what you want then we give that promotion when they enter the city, and take it away when they leave.

Sure. I already have the permanent interception promotion. I can make another one or two with a different name "Ground Radar" (and "Improved Ground Radar") that would reflect the fact they come from the station itself. I probably will limit the number of radar stations that can be built, for the sake of game balance.

Zebra 9
May 29, 2008, 03:25 PM
Ok, I'll see if I find time in the near future. RL is givin me a headache. :yuck:

Arian
May 29, 2008, 04:11 PM
Ok, I'll see if I find time in the near future. RL is givin me a headache.

Hey Zebra,

Take your time. Thing can wait here :lol:

Greetz

Zebra 9
Jun 05, 2008, 03:12 PM
I think this is what Ambreville needs for his PythonCallback:

Pick a name that reflects the event that it belongs to and that only includes letters, numbers, and under scores (_), the name should be similar to "doMyEvent".

Then in your event (the one in Civ4EventInfos.xml, not the trigger) change the PythonCallback tag to have the name you decided on, it should look like this.<PythonCallback>doMyEvent</PythonCallback>
Next you need to open CvRandomEventInterface.py. At the end of the file add this code.def doMyEvent(argsList):
iEvent = argsList[0]
kTriggeredData = argsList[1]

## --------- ## MAKE CHANGES HERE ## --------- ##
##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
szEnemyPlayer = "CIVILIZATION_CHINA" # The type tag of the enemy civilization, it will declare war on it's team
resetDiplomacy = True # Resets pTeam's diplomacy with szEnemyPlayer's Team when True, or it leaves the diplomacy the same when False
warPlan = WarPlanTypes.NO_WARPLAN # Used for the AI, it tells the AI what type of war to wage
# Possible entries are:
# WarPlanTypes.NO_WARPLAN The AI decides
# WarPlanTypes.WARPLAN_ATTACKED_RECENT,
# WarPlanTypes.WARPLAN_ATTACKED,
# WarPlanTypes.WARPLAN_PREPARING_LIMITED,
# WarPlanTypes.WARPLAN_PREPARING_TOTAL,
# WarPlanTypes.WARPLAN_LIMITED,
# WarPlanTypes.WARPLAN_TOTAL,
# WarPlanTypes.WARPLAN_DOGPILE,

warn = True # Give a message if the civilization is not found, put False if you want no message

## --------- ## DO NOT CHANGE ANYTHING PAST HERE ## --------- ##
##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^


## This looks fo the civilization
iEnemyTeam = -1
for iPlayer in range(gc.getMAX_PLAYERS()):
player = gc.getPlayer(iPlayer)
iType = pPlayergetCivilizationType()
pType = gc.getCivilizationInfo(iType)
sType = pType.getType()
if sType == szEnemyPlayer:
iEnemyTeam = player.getTeam()
break

## If the civilization was not found give the warning
if iEnemyTeam == -1:
if warn:
CyInterface().addImmediateMessage("ERROR: %s was not found, will not declare war!" % szEnemyPlayer, "")

## Otherwise declare war
else:
pTeam.declareWar(iEnemyTeam, resetDiplomacy, warPlan)

return 1Just replace the text doMyEvent with the name you decided on and set the values on szEnemyPlayer, resetDiplomacy, warPlan, and warn. This should do what you need. Unfortunatly I was unable to test this but it should work, and I have have subjected it to more scrutiny than any other snippet I have ever written. Enjoy, and let me know if you need help. ;)
==================================
I will try to get the promotion system for Ambreville, and Arian's building placement system up tomorrow. :thumbsup:

Ambreville
Jun 05, 2008, 03:45 PM
You rock, man! :rockon:

phungus420
Jun 05, 2008, 05:46 PM
Would it be possible, as a few lines of python code, to add in an XML tag to the promotionsinfos.xml that allowed certain promotions to see a new invisible type? If so, how would I go about doing this?

I've gotten to the point where I'm going to start reading the python tutorials, I can't go any further with modifications I want to make to mods with XML. This seems like a simple thing to start with (though I could be completely wrong). Edit: nevermind, looks like that would be an SDK thing. Looking at the Python files, it doesn't look like much is in python really.

Ambreville
Jun 06, 2008, 01:54 PM
If you ever get over RL some... here's another idea.

This one's for those who like historical mod/scenarios that call for expeditionary forces from a Civ that does not control any cities on the game map -- like for example the colonization of far-flung colonies, or WWI & WWII US troops on a map limited to just Europe (etc).

The "total kill" option needs to be used to make sure the "overseas civ" isn't instantly defeated since it doesn't have a capital on Turn #1. Python can then be used to spawn unit reinforcements on a regular or random basis.

What's still missing here is a function that gives the overseas civ a set number of beakers, gold, and spy points per turn, even if it has no cities. If it conquers some, that number would then get added to whatever is generated from the conquered cities.

The coding could be setup to be active on Turn #1, or included in the event's callback routine that brings that civ into play.

Possible? Interested?

Zebra 9
Jun 06, 2008, 06:55 PM
Here is the code that Arian requested. It will add a building to a city when it completes a project.
def onProjectBuilt(self, argsList):
'Project Completed'
pCity, iProjectType = argsList
game = gc.getGame()
if ((not gc.getGame().isNetworkMultiPlayer()) and (pCity.getOwner() == gc.getGame().getActivePlayer())):
popupInfo = CyPopupInfo()
popupInfo.setButtonPopupType(ButtonPopupTypes.BUTT ONPOPUP_PYTHON_SCREEN)
popupInfo.setData1(iProjectType)
popupInfo.setData2(pCity.getID())
popupInfo.setData3(2)
popupInfo.setText(u"showWonderMovie")
popupInfo.addPopup(pCity.getOwner())

## ------------- ## CHANGE HERE ## ------------- ##
sProject = "PROJECT_SDI" # The type tag of the project that gives the building
sBuilding = "BUILDING_BOMB_SHELTER" # The type tag of the building to be given


## ------------- ## DO NOT CHANGE ## ------------- ##
if iProjectType == gc.getInfoTypeForString(sProject):
pCity.setNumRealBuilding(gc.getInfoTypeForString(s Building), 1)Place this code into an unchanged CvEventManager.py replacing onProjectBuilt. Or if you are using either Dr. Elmer Giggle's event manager or zModular Python the code will look like this.def onProjectBuilt(self, argsList):
'Project Completed'
pCity, iProjectType = argsList


## ------------- ## CHANGE HERE ## ------------- ##
sProject = "PROJECT_SDI" # The type tag of the project that gives the building
sBuilding = "BUILDING_BOMB_SHELTER" # The type tag of the building to be given


## ------------- ## DO NOT CHANGE ## ------------- ##
if iProjectType == gc.getInfoTypeForString(sProject):
pCity.setNumRealBuilding(gc.getInfoTypeForString(s Building), 1)Just place in your Event Manager file and away you go. If you would like multiple projects to give buildings just duplicate the code that comes after "## ------------- ## CHANGE HERE ## ------------- ##". Enjoy and just give a post if you need help. :thumbsup:

I'll be working on the promo's for Ambreville over the weekend. And about your newest Q, yes it's possible. Is it worth it? Depends on how complex it turns out to be. I would have to write code to calculate how much should go for science and treasury (don't need culture since they don't have cities). I'll see what I can do, but I can tell this much, it isn't going to be a snippet (try MOD COMP or maybe small MOD). :goodjob::cool::king:;):):D:crazyeye::scan:

Arian
Jun 06, 2008, 11:56 PM
Thank you, Zebra

I'll try it later :goodjob:

Arian
Jun 07, 2008, 12:56 AM
What am I doing wrong?

This is the original code in my CvEventManager.py:

def onProjectBuilt(self, argsList):
'Project Completed'
pCity, iProjectType = argsList
game = gc.getGame()
if ((not gc.getGame().isNetworkMultiPlayer()) and (pCity.getOwner() == gc.getGame().getActivePlayer())):
popupInfo = CyPopupInfo()
popupInfo.setButtonPopupType(ButtonPopupTypes.BUTT ONPOPUP_PYTHON_SCREEN)
popupInfo.setData1(iProjectType)
popupInfo.setData2(pCity.getID())
popupInfo.setData3(2)
popupInfo.setText(u"showWonderMovie")
popupInfo.addPopup(pCity.getOwner())

then I change it by pasting the code. It looks like this:

def onProjectBuilt(self, argsList):
'Project Completed'
pCity, iProjectType = argsList
game = gc.getGame()
if ((not gc.getGame().isNetworkMultiPlayer()) and (pCity.getOwner() == gc.getGame().getActivePlayer())):
popupInfo = CyPopupInfo()
popupInfo.setButtonPopupType(ButtonPopupTypes.BUTT ONPOPUP_PYTHON_SCREEN)
popupInfo.setData1(iProjectType)
popupInfo.setData2(pCity.getID())
popupInfo.setData3(2)
popupInfo.setText(u"showWonderMovie")
popupInfo.addPopup(pCity.getOwner())

## ------------- ## CHANGE HERE ## ------------- ##
sProject = "PROJECT_ISS" # The type tag of the project that gives the building
sBuilding = "BUILDING_ISS" # The type tag of the building to be given

## ------------- ## DO NOT CHANGE ## ------------- ##
if iProjectType == gc.getInfoTypeForString(sProject):
pCity.setNumRealBuilding(gc.getInfoTypeForString(s Building), 1)

In this case PROJECT_ISS is International Space Station project and BUILDING_ISS the building model of the station (found on the forum btw) but when I start a new game, the game interface is gone???
Without the code everything works fine.

I have absolutely no clue what's happening here...:confused:
Any idea what causing this??

Wolfshanze
Jun 07, 2008, 11:49 AM
Zebra 9... I'm trying to get National Wonders to play a movie when built... I already changed the XML entries, but got nothing to show-up.... Arian then told me to change the Python Event Manager and gave me some tips... I followed them as he stated...

DISREGARD ABOVE

Okay... I got it figured out (thanks to Arian's files he posted)... the problem was as simple as a couple of tabs... the start to some of my lines weren't tabbed properly. I matched them to Arians and it made all the difference in the world... believe it or not... some mere tabbing was all that was needed.

Arian
Jun 07, 2008, 12:07 PM
Zebra,

Wolfshanze has mentioned the possiblity to display a movie after circumnavigating (?) the world.
I think that's a nice idea. Can this be done in Python?

Zebra 9
Jun 09, 2008, 08:12 AM
If it's screens, it must be done by python. I have never added a screen, but I can duplicate the dawn of man screen and make it look different. I'll seee what I can figure out with the code I gave you.

EDIT: Arian could you post the entire file you changed? I think it might be indentation but I can't be sure until I see the file.

Gaius Octavius
Jun 09, 2008, 08:27 AM
Sure. I already have the permanent interception promotion. I can make another one or two with a different name "Ground Radar" (and "Improved Ground Radar") that would reflect the fact they come from the station itself. I probably will limit the number of radar stations that can be built, for the sake of game balance.

It's a little bit more complicated than that, I'm afraid, because you can bomb Radar Stations. So it can't be based just on when they leave or return to a city.

I think what we really need is a C++ system wherein the station actively gives a Y% intercept bonus to all air units within X tiles. This would be like Civ 3, and much more useful than the promotion system, since you could conceivably make tile improvements with Radar Stations and not have them in cities alone. That's probably outside Zebra 9's main area of Python expertise, though.

Zebra 9
Jun 09, 2008, 08:31 AM
I do believe it is. I'll still work on the other system though.

Ambreville
Jun 09, 2008, 08:40 AM
It's a little bit more complicated than that, I'm afraid, because you can bomb Radar Stations. So it can't be based just on when they leave or return to a city.

I think what we really need is a C++ system wherein the station actively gives a Y% intercept bonus to all air units within X tiles. This would be like Civ 3, and much more useful than the promotion system, since you could conceivably make tile improvements with Radar Stations and not have them in cities alone. That's probably outside Zebra 9's main area of Python expertise, though.

Well, if you want to develop a tile-based system, more power to you. On the other hand, until something like that becomes available again, I'll be using whatever Zebra can come up with. ;)

Arian
Jun 09, 2008, 09:46 AM
Zebra:

EDIT: Arian could you post the entire file you changed? I think it might be indentation but I can't be sure until I see the file.

You were right about the indentation. I checked the code with IDLE Python editor and the error showed right up. However I didn't check if it really works because the project ISS is quite at the end of the game but I'm confident it works!! :D
I didn't know Python is so sensitive for correct indentation. Wolfshanze had the same problem with identation...

Attached is the CvEventManager.py. When I check it with IDLE, it gives indentation errors but ingame everything looks fine.

Anyway thanks for your time and effort! :goodjob:

Gaius Octavius
Jun 09, 2008, 10:08 AM
Well, if you want to develop a tile-based system, more power to you. On the other hand, until something like that becomes available again, I'll be using whatever Zebra can come up with. ;)

If I could do it all on my own from scratch, I wouldn't be poking around here for it. ;) Though I would like to give it a try. I am still learning my way around the SDK and it might be possible sooner or later. I had hoped that Dale would do something with it, as he's the combat genius around here... I'm more of an economy-oriented guy. :mischief:

Zebra 9
Jun 09, 2008, 02:16 PM
Wouldn't you you just update a variable that held it's interception val every time it moved? So when it moved to another plot you would run a loop checking the adjacent plots (maybe up to 9 plots way or something like that) for cities and if it finds a city it increases it's value, and you would do the same thing with the old plot but instead removing.

Jeckel
Jun 09, 2008, 04:27 PM
I didn't know Python is so sensitive for correct indentation. Wolfshanze had the same problem with identation...

Python is based on indentation. If you don't use the right indentation the code will have no idea where it is spose to run. A good first step might be to read a few of the tutorials on basic python. There are some good ones at the main python site.

Ambreville
Jun 09, 2008, 05:27 PM
Yeah... found out the hard way!

Ambreville
Jun 16, 2008, 12:36 PM
(...) And about your newest Q, yes it's possible. Is it worth it? Depends on how complex it turns out to be. I would have to write code to calculate how much should go for science and treasury (don't need culture since they don't have cities). I'll see what I can do, but I can tell this much, it isn't going to be a snippet (try MOD COMP or maybe small MOD). :goodjob::cool::king:;):):D:crazyeye::scan:

That's unfortunate. I was looking at flat/constant numbers has far as how much gold and beakers* the Civ would be able to generate (basically set by the scenario). I don't know if that makes it any easier.

(*) Spy points would also be needed.

Zebra 9
Jun 16, 2008, 03:25 PM
Well, that is the simplest system I can think, so I'll see what I can do.

P.S. I have had your code but I haven't had the time to post it and right now I don't have, I'll try to get it up to you tomorrow.

Arian
Jun 21, 2008, 12:31 PM
Zebra, your code works like charm!

The station is floating over the city after completion of the project.

Again thank you very much! :thumbsup:

General Tso
Jun 21, 2008, 03:00 PM
I just wish the script data was multiplayer compat (or I knew a way to make MP). When I first got civ I didn't know what python was (other then a snake), all I knew was JavaScript and HTML.

Here's a little Python/Civ4 trivia:
Python is actually named after "Monty Python's Flying Circus"

Ambreville
Jun 28, 2008, 06:57 AM
Any luck with the radar station snippet or the supply of Beaker/Gold/Spy points for Civs without cities?

Ambreville
Jul 05, 2008, 06:35 AM
Other idea -- a system allowing a Civ to sell units stationed in its capital city?

Arian
Jul 05, 2008, 06:43 AM
Other idea -- a system allowing a Civ to sell units stationed in its capital city?

That would only be realistic for ships, armors, siege weapons and air units ('material' units). I think it's a bit odd to sell 'troop'-units. That way you sell people. Know what I mean?

Jeckel
Jul 05, 2008, 06:49 AM
Wheather you call it selling a unit or "renting a military group", the game mechanic is the same.

Someone updated TheLopez's Mercenaries Mod to BtS. With a little tweaking you could limit unit selling to just the capital.

Arian
Jul 05, 2008, 07:07 AM
Someone updated TheLopez's Mercenaries Mod to BtS. With a little tweaking you could limit unit selling to just the capital.


Too bad the link is broken. Can you reupload it?

Jeckel
Jul 05, 2008, 11:57 AM
Too bad the link is broken. Can you reupload it?

Your right, my bad, I don't know what I was thinking. I might have an upgraded version on one of my storage computers, buried deep in the zip files. Give me a couple days to do my rounds on the hard drive searching and I'll see what I can come up with. :)

Zebra 9
Jul 07, 2008, 09:06 AM
I'm still working on this stuff, but I have to use a proxy to access CFC on my main computer, and it's a pain (I'm using a local WiFi rather than the dial up).

Ambreville
Jul 07, 2008, 11:38 AM
I'm still working on this stuff, but I have to use a proxy to access CFC on my main computer, and it's a pain (I'm using a local WiFi rather than the dial up).

That's sounds like a pain. Good luck!

Ambreville
Jul 07, 2008, 11:39 AM
That would only be realistic for ships, armors, siege weapons and air units ('material' units). I think it's a bit odd to sell 'troop'-units. That way you sell people. Know what I mean?

Basically, yes -- material units (which would instantly lose any previous combat experience as a result of the sale).

neutral_leader
Jul 25, 2008, 06:44 AM
I have an inquiry:

Would it be possible in the python to a) rig a system to change city graphics based on what civics are selected and/or b) make civics mutually exclusive?

EmperorFool
Jul 25, 2008, 03:47 PM
Would it be possible in the python to . . . make civics mutually exclusive?

After a few minutes of searching, I found these two civics-related functions in CvGameUtils.py:


def canDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False

def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False


Note the bolded lines. They are saying that a single civic is passed into the function. This would allow you to stop someone from switching to civic X if they were already running civic Y, but it won't allow you to block them from switching to both X and Y at the same time.

Since the Civics screen is in Python, you should be able to block them from making the mutually exclusive selection there. It would not stop an AI from switching to them, however. I think for that you'd need to do SDK work, but maybe Zebra9 knows a way.

Zebra 9
Jul 26, 2008, 09:05 AM
What do you mean by mutually exclusive"?

EmperorFool
Jul 26, 2008, 09:24 AM
What do you mean by mutually exclusive"?

From Google (http://www.google.com/search?q=define%3A+mutually+exclusive&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a):

mutually exclusive: contradictory: unable to be both true at the same time

The two civics cannot be used together. For example, in each category (Legal, Government, Religion, etc) all of the choices are mutually exclusive because you have to choose one of the five. You cannot use Organized Religion and Pacifism.

I believe neutral_leader wants to make it so that, e.g. you cannot run Pacifism and Slavery together, even though they are in different categories.

Zebra 9
Jul 26, 2008, 11:32 AM
Ok, I had been planning on incorporating this into my zCivics MOD COMP. I'll try adding it in the next week.

neutral_leader
Jul 26, 2008, 06:51 PM
That would be a godsend.

Ambreville
Jul 27, 2008, 08:33 AM
I'm still working on this stuff, but I have to use a proxy to access CFC on my main computer, and it's a pain (I'm using a local WiFi rather than the dial up).

Are you still having issues with this?

Zebra 9
Jul 28, 2008, 01:07 AM
Yes, I still have to use the proxy. The only problem it causes is that I can can't upload to CFC, but I recently bought 10 gig of server space and I can upload there; ;)

tsentom1
Aug 04, 2008, 02:13 PM
EDIT: Nevermind, I figured it out. Thanks anyway for the great python snippets

I've been having trouble getting the civic specific unit's code to work

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
bIgnoreUpgrades = argsList[5]

## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Train This Unit
if eUnit == gc.getInfoTypeForString('UNIT_CARAVAN' ):
if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoT ypeForString('CIVIC_BARTER' )):
return True

return False

Is causing my interface to vanish so I know it must be a whitespace, formatting problem. I'm using BTS 3.17, does this code still work for this? Or if someone sees my error, any help would be appreciated. thanks:)

Zebra 9
Aug 04, 2008, 03:05 PM
Well try going trough and line by line remove the indentation and then re-add it. That's what I do when I get an indentation error. :thumbsup:

EmperorFool
Aug 04, 2008, 03:43 PM
It would help a lot if you posted the error you're getting. Enable the logging system and look in Logs/PythonErr.log.

However, just looking at it I can see that you are mixing tabs and spaces -- always a source of trouble with Python. The line


if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoT ypeForString('CIVIC_BARTER' )):


has a tab mixed in with the spaces in the indentation. The others may have problems too, but that was the first and only one I examined (sixth sense :)). Pick one and stick with it.

I recommend going with tabs since most of the Civ4 code uses them.

Gurra09
Aug 15, 2008, 05:02 AM
Are your python snippet for Civic Specific Unit compatible for BTS? Because the code you said was in unmodded game was different in my original BTS Python files and when I used the snippet the civilopedia didn't worked and when I played a game I couldn't see menus or anything except for the main map.

This is my Python Code:

def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
bIgnoreUpgrades = argsList[5]
civic = "CIVIC_SLAVERY" ## The Civic
unit = "UNIT_SLAVE" ## The Unit

## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Train This Unit
if eUnit == gc.getInfoTypeForString(unit):
if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoT ypeForString(civic)):
return True
return False



Gurra09

Zebra 9
Aug 15, 2008, 06:58 AM
Well, it should work with BtS. I think I have spotted an error though. Your indentation is incorrect. This should work:
def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
bIgnoreUpgrades = argsList[5]
civic = "CIVIC_SLAVERY" ## The Civic
unit = "UNIT_SLAVE" ## The Unit

## If The Civ Doesn't Have The Correct Civic Tell the SDK Not To Allow The Player To Train This Unit
if eUnit == gc.getInfoTypeForString(unit):
if not gc.getPlayer(pCity.getOwner()).isCivic(gc.getInfoT ypeForString(civic)):
return True
return FalseYou used spaces on some of the lines (I might have used spaces in the snippet, I'll have to check).

Zebra 9
Aug 15, 2008, 06:59 AM
Yes, I used spaces in the snippet, not sure why I did. I'll fix it soon. Sorry.

Gurra09
Aug 15, 2008, 03:06 PM
Now the civilopedia and screens works but I can construct my unit even if I don't have the civic I have wroted in the Python (Slavery).

I can build it with Caste System, Tribalism and every civic. Why?


Gurra09

Arian
Aug 15, 2008, 08:37 PM
Try this:

In PythonCallbackDefines.xml change

<Define>
<DefineName>USE_CANNOT_TRAIN_CALLBACK</DefineName>
<iDefineIntVal>0</iDefineIntVal>
</Define>

to

<Define>
<DefineName>USE_CANNOT_TRAIN_CALLBACK</DefineName>
<iDefineIntVal>1</iDefineIntVal>
</Define>

Not sure of it works but you could give it a try.

Zebra 9
Aug 16, 2008, 07:59 AM
Yup do what Arian said.