Mod-Modders Guide to Fall Further

I'm attempting to define a global variable in python atm.

Is it enough to define the variable at the top of the file, and explicitly declaring the variable a global in any file that modifies the value?


Edit: Also, how do you call the variable in another python file? Need to call it in MainScreen.

Edit the Second: Alright, I got the globals working, and as wrote a small function that sets the relevant global equal to itself, and returns it, which I then call in the Screens file... Works perfectly. All that's left is to balance it. ;)

This is for a new Grigori Spawning mechanic, btw... No randomness at all, instead it increases a certain amount each turn based on buildings and civics. Two globals are used: iGrigoriSpawn, which is used as the counter, and iGrigoriMod, which modifies the counter and is increased everytime a new Adventurer spawns... Same way GPs require more points each time. ;)
 
You define globals at the top of the file they are global for, then within that file you must call the variable into a function with the keyword global, or reference it as this.variable. To call from other screens you just call for it (screen.variable) like normal.

This python variable of your work nicely with savegames?
 
You define globals at the top of the file they are global for, then within that file you must call the variable into a function with the keyword global, or reference it as this.variable. To call from other screens you just call for it (screen.variable) like normal.

This python variable of your work nicely with savegames?

So you're saying I could call it via cf.iGrigoriSpawn?

As for savegames... Not sure yet. :lol:

Edit: Savegames... Yeah, not so much. :lol: So long as you don't exit entirely, it works just fine... Once you exit the game, the python variables are wiped. I'm assuming it's possible to add two ints to pPlayer, moddable with python? This way I could store them each turn... And could get the variable in any python file I wish.

What is the minimum DLL required to make new tags apply to the Player, rather than a leader or civ?
 
I didn't notice that it was just calling another function. the names are so similar.
But I guess what I'd really like to know, what difference does this function make to the output of the one it calls. What does that minor adjustment accomplish ?

From all appearances, what this does is brings in argslist (i am unsure of where this comes from), checks for the second variable in this list (variable 1 would be argslist(0), variable 2 would be argsList[1], because lists start at 0 not 1). Then sets this variable to newArgs, and uses that variable when calling the function canTriggerBrothersInNeed. I am uncertain why it uses argsList(1) (in the form of kTriggeredData) within the parenthesis as it does, the only thing that I can think of is that it is trying to make an array with just 1 object in it - this would be something that you would need to check canTriggerBrothersInNeed for.

Basically it appears that all this does is grabs something in preparation for calling another function. As I was not the writer of this, I am uncertain why they decided to call it in this manner, as I cannot think of any other function that would need canTriggerBrothersInNeed, though I may be wrong here. The only real reasons why someone would use the functions in this manner is if canTriggerBrothersInNeed can be called several different ways, and this is just one of them, or just bad coding practice as they were copying other events already there. I would look through (do a control+f search) of the file and see if there are other functions that call canTriggerBrothersInNeed - this would tell you if this was the reason, though it is possible that something in the DLL might call this, though I doubt it. From all appearances though, you need to look at canTriggerBrothersInNeed to get the necessary documentation that you're looking for.

-Colin
 
Actually you would lose those python variables just by modifications to the python files as well (cause then they reload).

To have them exist on a Player you just need to add a new variable to CvPlayer, have it initialize, and make a get/set function for it, which you then expose to python through CyPlayer (and obviously read/write them in CvPlayer). Since you want to modify with python only, that is all you need. No mucking with CvInfos or CvGameTextMgr like normally done for a new tag.
 
Actually you would lose those python variables just by modifications to the python files as well (cause then they reload).

To have them exist on a Player you just need to add a new variable to CvPlayer, have it initialize, and make a get/set function for it, which you then expose to python through CyPlayer (and obviously read/write them in CvPlayer). Since you want to modify with python only, that is all you need. No mucking with CvInfos or CvGameTextMgr like normally done for a new tag.

Well, when I said pPlayer, I meant CvPlayer in the DLL. :p

So just CvPlayer.cpp, CvPlayer.h, and CyPlayer? That's what I was hoping. :lol: Is it necessary to add anything to the CvPlayer() or CvPlayer::Init() functions?
 
Well, couldn't you also set a variable to be constant, unchanged, and then have it make a count of the number of adventurers. In this way, you may not have to touch the DLL, as long as you don't modify that constant.

Ex.
Say you wanted that change of an adventurer to spawn to be constant*gameSpeedModifier*numAdventurersModifier. As long as you don't modify the constant, you can get gameSpeedModifier to be some number (it is already called elsewhere in python I'm sure) based on game speed, and create a new variable that counts the number of units the grigori have with the hero promotion, and then have it return a number modified by this.

In this way, through the use of constants that you don't change, you can avoid touching the DLL at all. It may not be the most effective means of checking this however. Just another option that I'm tossing out.

-Colin
 
Yes, you just need to do CvPlayer.h, CvPlayer.cpp, CyPlayer.h, CyPlayer.cpp, CyPlayerInterface.cpp. In CyPlayer you will simply declare 2 functions, a get/set combo, which route to CvPlayer. In CvPlayer, you will declare the get/set functions, and also declare a variable, initialize it in CvPlayer::CvPlayer, save/load it in ::read/::write, and then set/read it in get/set.

So 2 lines in CyPlayerInterface.cpp, 2 in CyPlayer.h, 2 functions (which I tend to write as a single line) in CyPlayer.cpp, 3 lines (in 2 locations, declare functions for 2 lines and declare variable for 1 line) in CyPlayer.h, and then 2 functions, along with 3 other lines, to initialize, load, and save the data for this variable in CvPlayer.cpp.
 
Yeah, got it working. ;)

The code I based it on was get/change, rather than get/set... Works about as well. More of a pain to reset, easier to add to... I add to it more often than I wipe it, so I think the trade off is worth it.

I've got the python 'working' enough to know the DLL is working. Need to modify the way I set it up initially, and fix the display.

Edit: Got all of the python set up correctly now, and after testing can confirm that it is conserved when you exit/reload. ;) Aside from balancing, it's all working perfectly. :goodjob: Rather more work than I initially intended, but worth it.
 
For buildings, check CvCity::processBuildings()...
For civics, check CvPlayer::processCivics()...

IIRC :)
 
I am having an issue with auto-applied promotions that grant experience.

For my "Dynamic Dural" modmod I have created a tiered system of promotions dependent upon various buildings to grant experience. The promotions also use various unitcombats so that, for instance, the Dural Training Hall replacement (the Dojo) grants .5 XP/turn up until 10 XP for Melee unitcombats. The automatically applied promotion that does this is called "Basic Melee Training."

When a College is built and a Dojo is present in the city, then "Intermediate Melee Training" is automatically applied to a unit. This allows .5 XP gain/turn up to 26 XP.

"Basic Melee Training" is marked as being replaced by "Intermediate Melee Training." What is happening in practice now that I have a College and a Dojo built in a city with Melee units is that

a) both promotions are present on Melee units in the city; Basic Melee Training is not being removed and

b) A unit with more than 26 XP is now getting 1 XP/turn -- somehow the XP limit from both of the promotions is being ignored in the calculations.

Here is the XML for the current promotions:

Code:
		<PromotionInfo>		<!-- Basic Melee Training -->
			<Type>PROMOTION_MELEE_TRAINING1</Type>
			<Description>TXT_KEY_MELEE_TRAINING1</Description>
			<fFreeXPCap>10</fFreeXPCap>
			<iPower>1</iPower>
			<Button>Art/Interface/Buttons/Promotions/Hero.dds</Button>
			<iFreeXPPerTurn>.5</iFreeXPPerTurn>
			<PrereqBuildingANDs>
				<PrereqBuilding>BUILDING_TRAINING_DURAL</PrereqBuilding>
			</PrereqBuildingANDs>
			<PrereqCivilizations>
				<PrereqCivilization>CIVILIZATION_DURAL</PrereqCivilization>
			</PrereqCivilizations>
			<PrereqTechANDs>
				<PrereqTech>TECH_WARFARE</PrereqTech>
			</PrereqTechANDs>
			<UnitCombats>
				<UnitCombat>
					<UnitCombatType>UNITCOMBAT_MELEE</UnitCombatType>
					<bUnitCombat>1</bUnitCombat>
				</UnitCombat>
			</UnitCombats>
			<bAutoAcquire>1</bAutoAcquire>
			<bMustMaintain>1</bMustMaintain>
			<bNoXP>1</bNoXP>
			<PromotionReplacedBy>PROMOTION_MELEE_TRAINING2</PromotionReplacedBy>
		</PromotionInfo>
		<PromotionInfo>		<!-- Intermediate Melee Training -->
			<Type>PROMOTION_MELEE_TRAINING2</Type>
			<Description>TXT_KEY_MELEE_TRAINING2</Description>
			<fFreeXPCap>26</fFreeXPCap>
			<iPower>1</iPower>
			<Button>Art/Interface/Buttons/Promotions/Hero.dds</Button>
			<iFreeXPPerTurn>.5</iFreeXPPerTurn>
			<PrereqBuildingANDs>
				<PrereqBuilding>BUILDING_TRAINING_DURAL</PrereqBuilding>
				<PrereqBuilding>BUILDING_COLLEGE</PrereqBuilding>
			</PrereqBuildingANDs>
			<PrereqCivilizations>
				<PrereqCivilization>CIVILIZATION_DURAL</PrereqCivilization>
			</PrereqCivilizations>
			<PrereqTechANDs>
				<PrereqTech>TECH_WARFARE</PrereqTech>
			</PrereqTechANDs>
			<UnitCombats>
				<UnitCombat>
					<UnitCombatType>UNITCOMBAT_MELEE</UnitCombatType>
					<bUnitCombat>1</bUnitCombat>
				</UnitCombat>
			</UnitCombats>
			<bAutoAcquire>1</bAutoAcquire>
			<bMustMaintain>1</bMustMaintain>
			<bNoXP>1</bNoXP>
			<PromotionReplacedBy>PROMOTION_MELEE_TRAINING3</PromotionReplacedBy>
		</PromotionInfo>

Do I need to create additional promotion exclusions? E.g. do I need to use <PromotionExcludes> as well? Seems redundant with <PromotionReplacedBy> already present...

Thanks!
 
The rate (0.5 per turn) is always applied to the unit, and all caps on the unit are added together to make the net cap. So if the first promotion grants the 0.5 rate and a 10 cap, you want the second promotion to give only a cap of 16, and no rate. That will result in gaining 0.5 up till 26 as long as the unit maintains both promotions.


I think the error you are having is listing as PromotionReplacedBy, which I think doesn't work. Instead, place PromotionOverwrites/PromotionExcludes on the second promotion and it should remove the first for you. But as stated, you don't HAVE to remove the first.


The Overwrite/Replace/Exclude set were all written for the same purpose: Exclusion of other promotions, but split up to allow maximum flexibility about the order of acquisition (so you could allow a unit to gain Promotion A before Promotion B and keep both that way, but if they get B first, then they can no longer gain A. And other such convoluted things). Since most of the use for the tags has been simply "Cannot have A and B at the same time" it has proven a bit TOO seperated.
 
Depends on what you are wanting to find out. I am reasonably certain that there is a CvPlayer function to check if a player owns any of a particular building, and/or how many they have. But it might only track how many they have BUILT (not subtract when one is lost, or add when one is captured), I haven't looked closely at it. Might also just do a loop over all cities for itself. And if you want to know in which city those buildings are, you want to loop them anyway. You could MAKE such a tracking integer if you wanted and it doesn't exist quite easily. Just add a line in CvCity::processBuilding which updates CvPlayer for a new addition/deletion of that particular class/type
 
CvPlayer::getBuildingClassCount gives you the number a players owns of a buildingclass
 
Back
Top Bottom