Python Wonders and their effects

Can you adjust training times of certain units in Python? Like say the Celts can train either Mounted Units, Melee, Ranged, Gun, with less cost in hammers than other civs? If so that could fill a gap in Unique Civ powers.
I don't think so, at least, but there are literately thousands of methods available. What I do in these situations is to simply search the API - in this case with the word "cost" - and see what crops up. It does sound like a setting they would have made available in the XML anyway (but I guess not).

I'm toying with an idea of adding buildings to the game that take a raw resource and refine it into its productive state. (...) My question: Do you think that's a good gameplay mechanic or unnecessary. I don't want the mod to introduce a lot of junk for junk's sake, but in my head this sounds like it could be a fun dynamic.
I'm not sure about this, actually. It might turn out to be a great addition to the game, but on the other hand you're basically doubling up on resources and hoops that the player needs to jump through.

Maybe someone else wants to give their two cents?
 
You can, in fact, modify the cost of units in Python via the getUnitCostMod callback in CvGameUtils.py (you have to be sure to activate the callback in PythonCallbackDefines.xml, where it is controlled by USE_GET_UNIT_COST_MOD_CALLBACK). This function should return an integer that is a percentage value which is used by the DLL to modify the cost of a unit (so returning 90 makes the unit cost 90% of the normal cost). This is used in Final Frontier to implement some civics that change the cost of some unit types (like Light Ship Doctrine makes destroyers and cruisers have 90% of the normal cost).

In Final Frontier Plus this callback is disabled since that ability for civics was actually moved into the DLL, although it functions differently since it specifies a list of unitcombats instead of a list of affected units (the original Light Ship Doctrine only affected destroyers and cruisers, now I expect it does not affect cruisers but does make planetary defense ships, invasion ships, and stealth ships cost less - I'm rambling on about this since this has reminded me that I need to check it to make sure the text for these civics matches what they really do).
 
You can, in fact, modify the cost of units in Python via the getUnitCostMod callback in CvGameUtils.py (you have to be sure to activate the callback in PythonCallbackDefines.xml, where it is controlled by USE_GET_UNIT_COST_MOD_CALLBACK).
Really? :eek2: I'm still new at using CvGameUtils.py and forgot to check there. This should be no problem at all, as long as seasnake activates the callback in PythonCallbackDefines.xml :goodjob:-

seasnake: What Civ and which units/unit classes/combat types will be affected?
 
Good Morning! I'll be out for some of the morning and back this afternoon, wanted to respond:

Holy Roman: 3/4 time necessary to train Mounted Units
Byzantines: 3/4 time to train Gunpowder Units
Celts: 3/4 time to train Melee Units
Portugal: 3/4 time to train Naval Units
 
Holy Roman: 3/4 time necessary to train Mounted Units
Byzantines: 3/4 time to train Gunpowder Units
Celts: 3/4 time to train Melee Units
Portugal: 3/4 time to train Naval Units
Are these to be regarded as "Unique Powers" also?

I'll get to work on this after dinner, then.
 
Try this. Firstly add this code to GGPowers:
Code:
# settings
...
iUnitDiscount = 25
eHolyRomanCombat = getIndex("UnitCombat", "Mounted")
eByzantineCombat = getIndex("UnitCombat", "Gun")
eCelticCombat = getIndex("UnitCombat", "Melee")
ePortugeseCombat = getIndex("UnitCombat", "Naval")
...

### main functions - called from CvEventManager/CvGameUtils

def unitDiscounts(ePlayer, eType):
        eCombat = gc.getUnitInfo(eType).getCombatType()
        if ( (isCivPlayer("Holy Rome", ePlayer) and eCombat == eHolyRomanCombat)
             or (isCivPlayer("Byzantium", ePlayer) and eCombat == eByzantineCombat)
             or (isCivPlayer("Celt", ePlayer) and eCombat == eCelticCombat)
             or (isCivPlayer("Portugal", ePlayer) and eCombat == ePortugeseCombat) ):
                return 100 - iUnitDiscount
        return -1
Secondly, make the code in CvGameUtils reflect this change:
Code:
	def getUnitCostMod(self, argsList):
		iPlayer, iUnit = argsList
		iCostMod = -1 # Any value > 0 will be used
[B]		import GGPowers as power
		return power.unitDiscounts(iPlayer, iUnit)[/B]
Thirdly, update this line in GGUtils:
Code:
tCivilizations = ("Holy Rome", "Byzantium", "Portugal", "Celt", "Arabia", "Gran Colombia", "Germany", "Inca", "Japan", "Maya", "Netherlands", "Ottoman", "Persia", "Russia", "Scandinavia")
Lastly, don't forget to enable the getUnitCostMod() callback in PythonCallbackDefines.xml!

I'm just gonna let you test this one yourself... :p
 
Okay, after I had tried to update the CvEventManager and try out some of the powers I got the blank screen of death! I think I may have made mistake merging them, and sent the EventManager and GameUtils to you for a look.

Where is the file to enable Python Exceptions? I thought I had already done that previously but I can't remember. If anyone knows who to enable python exceptions and could let me know I would appreciate it highly.

Thanks.
 
At a glance your modules look fine, with the exception of some minor errors in CvGameUtils that shouldn't cause the game to crash... But this is what I meant with my sketchy instructions:
Spoiler :
Code:
	def doPillageGold(self, argsList):
		"controls the gold result of pillaging"
		pPlot = argsList[0]
		pUnit = argsList[1]

		iPillageGold = 0
		iPillageGold = CyGame().getSorenRandNum(gc.getImprovementInfo(pPlot.getImprovementType()).getPillageGold(), "Pillage Gold 1")
		iPillageGold += CyGame().getSorenRandNum(gc.getImprovementInfo(pPlot.getImprovementType()).getPillageGold(), "Pillage Gold 2")

		iPillageGold += (pUnit.getPillageChange() * iPillageGold) / 100
		
		import GGPowers as power
		return iPillageGold * power.scandinavia(pUnit)
Code:
	def getUnitCostMod(self, argsList):
		iPlayer, iUnit = argsList
		#iCostMod = -1 # Any value > 0 will be used
		import GGPowers as power
		return power.unitDiscounts(iPlayer, iUnit)
What is causing the crash could probably by any of many things, but looking for Python exceptions is a good start. I fear you have a bug hunt ahead of you...

You enable exceptions and logging and in-game error messages and whatnot in the CivilizationIV.ini file found in your \MyGames\Beyound the Sword\ folder. The actual error logs are found in the Logs subfolder. They are flagged Python.

The code I sent you works on my machine with a standard BtS game. But I haven't play-tested any of it or anything. So issues are to be expected. Any Python related stuff should be possible to sort out in any case.
 
Having a thought then...what if tonight I upload an early version of the mod and send it to you as it now is, and you can work on testing the python for the mod that way? I can then confine my work to the XML here, and in theory all we should have to do at the end is take your working Python folder and the few of the XML files changed and we'll end up with the complete mod? Plus you could see what I've done so far and what's gone into it and give your opinion about what you see.

If that works let me know and I'll e-mail the link.
 
All I have time for is still to check that the code is valid and fires appropriately. I doubt I will have time to test the Python you already have, other than fix any exceptions that pop up while testing the powers. So you still need to test your mod in actual play. (I haven't played a game in some 15 months or so...)

But you can probably upload the mod so that we're working on the same set of files. It should help.
 
Alright, I'll upload the mod and send you the link so you're modifying those Python Files, and I'll stay out of all Python from here on out, so any changes you make won't have to account for anything I do. If you can just test that it loads okay with the PythonPowers that should be enough, more than enough.

I'll do all the XML stuff and any artwork changes to finish the civs. Most of them are getting close now.
 
Hmm... I don't think you can just dump the Python on me like that. Firstly I have no idea what the stuff already in the Event Manager is - and I don't have the time to figure it out either. And secondly there are no bulkheads between Python vs XML vs SDK. The game runs on C++ code and all the XML does is it defines some values and settings. The Python is mirroring the C++ code and is really just a interface for running the C++ code. So its basically all C++, really.

A crash like the one you describe is caused by the game, not the Python or the XML. But something is obviously not computing - it could be a bug in the source code - it could be a invalid setting somewhere - it could even be a corrupted image file. A Python exception shouldn't cause the game to crash either - its works the opposite! When the logic of the Python code breaks - or if there is a error in the code - then the Python simply quits and throws an exception. No crash, even if the game could get broken in the process (because some process was interrupted and data may have been lost).

With that said, lets suppose there is a XML setting somewhere referring to a broken image. (Just a plausible scenario, nothing more.) If that image is prompted to be used by a Python script, sure then the Python code is indeed causing the crash. But there doesn't need to be anything wrong with the script itself!

So basically this is debugging. It can be any combination of things conspiring to make the game crash. Normally I'd suggest reverting all changes and re-introducing them one at the time, until the bug appears. But since you already merged in the code into CvEventManager it would actually make more sense to disable the new features one at the time.

I made it really easy to do this. You disable the entire GGPowers module (and the companion modules) from ever being activated by commenting out the lines that say initiatePowers(). If you do this and the game still crashes, then its not the Python code I supplied causing the crash. Because it isn't being used. (You can comment out the entire intitiatePowers() function definition just to make sure. Its at the end of CvEventManager.py.)

You can similarly disable any of the powers by commenting out all lines referencing those particular features. Like if you wanna disable the Russian power you comment out all lines that say power.russia() - but you need to catch all of them - and there can be several.

So it shouldn't be very difficult to rule out the Powers code as the culprit at all. But I'll give the mod a spin and see if I can't solve this one for you. If I can't, I unfortunately don't have time to debug your entire mod. Its your mod and you're the also the best man for the job.

edit: Unfortunately the download isn't available... :dunno:
 
Hmm... I don't think you can just dump the Python on me like that. Firstly I have no idea what the stuff already in the Event Manager is - and I don't have the time to figure it out either. And secondly there are no bulkheads between Python vs XML vs SDK. The game runs on C++ code and all the XML does is it defines some values and settings. The Python is mirroring the C++ code and is really just a interface for running the C++ code. So its basically all C++, really.

A crash like the one you describe is caused by the game, not the Python or the XML. But something is obviously not computing - it could be a bug in the source code - it could be a invalid setting somewhere - it could even be a corrupted image file. A Python exception shouldn't cause the game to crash either - its works the opposite! When the logic of the Python code breaks - or if there is a error in the code - then the Python simply quits and throws an exception. No crash, even if the game could get broken in the process (because some process was interrupted and data may have been lost).

With that said, lets suppose there is a XML setting somewhere referring to a broken image. (Just a plausible scenario, nothing more.) If that image is prompted to be used by a Python script, sure then the Python code is indeed causing the crash. But there doesn't need to be anything wrong with the script itself!

So basically this is debugging. It can be any combination of things conspiring to make the game crash. Normally I'd suggest reverting all changes and re-introducing them one at the time, until the bug appears. But since you already merged in the code into CvEventManager it would actually make more sense to disable the new features one at the time.

I made it really easy to do this. You disable the entire GGPowers module (and the companion modules) from ever being activated by commenting out the lines that say initiatePowers(). If you do this and the game still crashes, then its not the Python code I supplied causing the crash. Because it isn't being used. (You can comment out the entire intitiatePowers() function definition just to make sure. Its at the end of CvEventManager.py.)

You can similarly disable any of the powers by commenting out all lines referencing those particular features. Like if you wanna disable the Russian power you comment out all lines that say power.russia() - but you need to catch all of them - and there can be several.

So it shouldn't be very difficult to rule out the Powers code as the culprit at all. But I'll give the mod a spin and see if I can't solve this one for you. If I can't, I unfortunately don't have time to debug your entire mod. Its your mod and you're the also the best man for the job.

edit: Unfortunately the download isn't available... :dunno:

Okay, I thought it would be more convenient to just show you what had been done, but if that makes it less convenient than just skip it. I'll just try and deal with it on my end and see if I can make progress through trial and error. I'll keep you informed of how that goes. I don't know why the file is unavailable (it worked last night!) but it doesn't really matter, I'll just try again.

I didn't explain myself well, the mod will open with the new stuff added in, it's just when you go to start a new game it will flash a blank screen that looks like the hall of fame screen without the stats, and then you'll be left with no interface visible. The game opens, the mod loads, you can browse the civpedia, but you have no interface in a new game.

The Mod works when I don't make the edits to the CvEventManager and CvGameUtils, so obviously it is a mistake I've made in trying to merge those lines into the CvEventManager.

Instead of me sending you the mod, could you send me the cveventmanager and the cvgameutils you used to test the GGpowers? Then I could slowly add in the things that have already been done on my end and see where the crash is? What do you think of that plan?
 
I'll try to download again later and see if I can't spot the error. Because that would be most convenient for everyone, agreed? :D

Did you manage to enable Python exceptions?
 
I changed HidePythonExcptions = 0 to = 1.

That do it?
Nope. You had already enabled Python exceptions. All you had to do was look in the log(s).

Trying to download as we speak... I sent you fixed files over email though.
 
By the way - I managed to download, install and launch the mod successfully. No crash on initialization... :dunno:

But the debug log is full of BUG errors, which are basically Python exceptions but managed in a way by the BUG code that they don't interrupt the game: "ERROR: BugOptions - Cannot locate settings folder" (The message is also shows in-game.)

I now realize that your mod is based on another mod, that in turn is based on BUG. And BUG is a really special case with its own Python modding environment. Unfortunately I think that you have broken your mod - and I wouldn't know how to go about helping you fix it. Because when I build a city the BUG code will spout actual exceptions. This in turn means that no Python code activated on that "event" (like the Arabian power) is executed - because the exception will quit the whole thing.

Its probably the same thing whatever you do. Your mod is broken. Sorry. I don't see how you would get this to work. Perhaps start all over and keep an eye out for debug/error messages generated by the Python code in BUG. This way you at least know when you brake it and can take one step back and try again.
 
Back
Top Bottom