Quick Modding Questions Thread

forgive my ignorance: so functions are declared in the header but defined in the source file?
 
so functions are declared in the header but defined in the source file?

Usually, yes. The declaration is intended so the compiler knows what the function looks like (parameters, return value etc.), so if you want to use it in more than one file it sits in the header (which is included in other source files).
The implementation only matters once, so it can be in the cpp file.

C++ allows you to place the function in the header file, but it is usually less preferable
(but sometimes it's a must).
 
ok I started again from scratch and this time tried not to change anything I didn't have to ie no turning off of any features, just adjusting for number and name of civs and map.

in CvPlayerAI.cpp Im getting these errors "'pPlot' : undeclared identifier" and "left of '->getX_INLINE' must point to class/struct/union" on this:

Code:
	//Rhye - start
	int tempX = pPlot->getX_INLINE();
	int tempY = pPlot->getY_INLINE();

earlier in CvPlayer.cpp pPlot ia defined as "pPlot = GC.getMapINLINE().plotINLINE(iX, iY);"

I looked for getMapINLINE() in files with GC in the name (GameCore, GameCoreUtils) that were included in CvPlayerAI but didn't find anything.

I think I understand what the code is trying to do: retrieve the coordinates of a given plot and store them as variables, but I don't know where its trying to get that information from. what's GC?

thanks for any help.
 
"GC" stands for "Global Context", but don't worry about that, this is not your problem.
To declare pPlot you also need a "CvPlot* pPlot;" line at some point, unless pPlot is in the argument list of the function you are calling, which is what you probably want to do.
If I didn't understand, you can still just paste that whole function that gives you trouble, it should be more obvious then.
 
CvPlot* pPlot is there at the start of the function. here it is:

Code:
int CvPlayerAI::AI_foundValue(int iX, int iY, int iMinRivalRange, bool bStartingLoc) const
{
	CvCity* pNearestCity;
	CvArea* pArea;
	CvPlot* pPlot;
	CvPlot* pLoopPlot;
	FeatureTypes eFeature;
	BonusTypes eBonus;
	ImprovementTypes eBonusImprovement;
	bool bHasGoodBonus;
	int iOwnedTiles;
	int iBadTile;
	int iTakenTiles;
	int iTeammateTakenTiles;
	int iDifferentAreaTile;
	int iTeamAreaCities;
	int iHealth;
	int iValue;
	int iTempValue;
	int iRange;
	int iDX, iDY;
	int iI;
	bool bIsCoastal;
	int iResourceValue = 0;
	int iSpecialFood = 0;
	int iSpecialFoodPlus = 0;
	int iSpecialFoodMinus = 0;
	int iSpecialProduction = 0;
	int iSpecialCommerce = 0;
	
	bool bNeutralTerritory = true;

	int iGreed;
	int iNumAreaCities;

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);

and 300 lines later is my error, at this line,which is one tab in and not part of any set of brackets

Code:
	int tempX = pPlot->getX_INLINE();
 
I would guess that somewhere you are calling this function with an iX and iY value that is off the map (< 0 or >= the width or height value) in at least one direction on a map that does not wrap in that direction. When you do that, the returned value is NULL instead of a valid plot.

By the way, the various somethingINLINE functions involving maps and plots are actually defined in CvMap.h (not .cpp).
 
that makes sense as my map is smaller and doesn't wrap. is there no way of finding out what called the function?
 
"undeclared identifier" is a compile-time error, null pointers can cause troubles but only on run-time (afaik).
If pPlot is declared at the beginning of the function then the scope of that variable is the whole of that function. If 300 lines later, the comiler has no clue anymore what that 'pPlot' thing is then you are already outside of said scope, meaning you might have added a closing bracket where you shouldn't have, or removed a opening bracket.
Or so I think. When in doubt, you can still paste the whole function (not just those parts), or you can upload both the cpp files (original, unless you are working off the standard BTS file, plus the one you are trying to compile) so someone else can take a look.
 
Oops. Fuyu is right (as usual). I wasn't paying enough attention and thought you had successfully compiled it and were now getting a run-time error.

At compile time it has no idea what map you are using, so on and off the map are irrelevant - the map data itself is not yet defined. So my guess is wrong.

As Fuyu says, if it doesn't know what pPlot is at that point then the declaration is "out of scope". To go out of scope in a case like this, where the variable is defined right at the beginning of the function at the outermost level of scope for the function, there must be at least one more "}" than there should be (and it is effectively shifting every line of code that was supposed to be in the function after it to now be outside of the function).

BTW: This is one reason why you should always indent your code properly (like Python forces you to) - if you do, you can spot when and where this sort of thing happens much more easily. When doing so, a "}" that does not cause a corresponding decrease in indentation level means there is an error (unless it is on the same line as the matching "{", which shouldn't happen very often).
 
thank you I found the open bracket. it was only about 10 lines above the error where I had commented out a line that had a "{" at the end. I did find lots of mistakes in my settler maps though.
 
ok I am back to the linker errors now.

here is the first one:

Code:
CvTeam.obj : error LNK2019: unresolved external symbol "public: int __thiscall CvHandicapInfo::getResearchPercentByID(enum PlayerTypes)const " (?getResearchPercentByID@CvHandicapInfo@@QBEHW4PlayerTypes@@@Z) referenced in function "public: int __thiscall CvTeam::getResearchCost(enum TechTypes)const " (?getResearchCost@CvTeam@@QBEHW4TechTypes@@@Z)

so its trying to get civ IDs from somewhere. my civs are listed in CvRhyes.h with integers associated, syntax copied from Rhye. something simple but important is obviously missing.

it occurs to me that I never got any errors in the Cy files even though Rhye made changes there. do you ever get errors there while compiling or do they show up later?

I'm trying to upload a zip of my files and the RFC files I started with but its not working right now , it seems, or just being incredibly slow. I will try again later.

I really appreciate your help. I've spent an enormous amount of time on this thing, even figured out gamefonts so I could have 11 religions, and I feel like I am getting close to having it running. thanks.
 
Well, the same as before - search for "getResearchPercentByID" and see if you see its implementation anywhere (probably in CvInfos.cpp).
This function does not exist in BTS code, so Rhye probably added this one.
 
awesome it compiled. Rhye's and Fall of the Classical World is born. can't thank you guys enough. now to see how it runs haha.
 
So, I'm trying to make a particular piece of Python code execute whenever a new unit is built. I put a function call in CvEventManager.py inside the onUnitBuilt function, but the code still doesn't execute... moreover, when I put a popup in there (in onUnitBuilt) for debugging purposes, it doesn't show up either... which suggests that onUnitBuilt is never executing, or I'm doing something stupid.

CvEventManager.py:
Code:
import Hardship

#....

	def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		player = PyPlayer(city.getOwner())

		CvAdvisorUtils.unitBuiltFeats(city, unit)
		
		if (not self.__LOG_UNITBUILD):
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.UnitInfo(unit.getUnitType()).getDescription(), player.getID(), player.getCivilizationName()))
		Hardship.NewUnit(argsList)

Hardship.py
Code:
def NewUnit(argsList):
	homecity = argsList[1]
	newguy = argsList[2]
	dPopup = PyPopup()
	dPopup.setHeaderString("Debug")
	dPopup.setBodyString("NewUnit is running")
	dPopup.launch()
	i_des = gc.getInfoTypeForString('PROMOTION_DESERT_SURVIVALIST')
	i_jun = gc.getInfoTypeForString('PROMOTION_JUNGLE_SURVIVALIST')
	i_arc = gc.getInfoTypeForString('PROMOTION_ARCTIC_SURVIVALIST')
	x = homecity.getX()
	y = homecity.getY()
	xrange = range(x-1, x+1)
	yrange = range(y-1, x+1)
	descount = 0
	juncount = 0
	arccount = 0
	for i in xrange:
		for j in yrange:
			nearplot = cyMap.plot(i, j)
			localterrain = nearplot.getTerrainType()
			localfeature = nearplot.getFeatureType()
			if localterrain == 2:
				descount = descount + 1
			if localterrain == 3 or localterrain ==4:
				arccount = arccount +1
			if localfeature == 1:
				juncount = juncount + 1
	if descount > 3:
		newguy.setHasPromotion(i_des , 1)
	if juncount > 3:
		newguy.setHasPromotion(i_jun, 1)
	if arccount > 3:
		newguy.setHasPromotion(i_arc, 1)
 
I'm guessing __LOG_UNITBUILD is 0, and so the code returns before ever getting to your code.
And in NewUnit you refer to elements 1 and 2 of the args list, instead of 0 and 1.
 
The problem is most likely this line (highlighted):
Code:
	def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		player = PyPlayer(city.getOwner())

		CvAdvisorUtils.unitBuiltFeats(city, unit)
		
[B]		if (not self.__LOG_UNITBUILD):[/B]
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.UnitInfo(unit.getUnitType()).getDescription(), player.getID(), player.getCivilizationName()))
		Hardship.NewUnit(argsList)
I'm betting that the attribute CvEventManager.__LOG_UNITBUILD has the value False. In other words; the interpreter never reaches your code, as the method exits before it can reach it.

So you simply bypass the code exiting by adding your function call above this line:
Code:
	def onUnitBuilt(self, argsList):
		'Unit Completed'
		city = argsList[0]
		unit = argsList[1]
		player = PyPlayer(city.getOwner())

		CvAdvisorUtils.unitBuiltFeats(city, unit)

[B]		Hardship.NewUnit(argsList)[/B]
		
		if (not self.__LOG_UNITBUILD):
			return
		CvUtil.pyPrint('%s was finished by Player %d Civilization %s' 
			%(PyInfo.UnitInfo(unit.getUnitType()).getDescription(), player.getID(), player.getCivilizationName()))
Makes sense? Note that the return command will exit the method/function, and that the if line is a escape clause of sorts, preventing the CvUtil.pyPrint() method from adding lines of debug messages unless logging is enabled internally within the CvEventManager module.

Also, you don't have to add pop-ups to the game in order to debug. Simply use the print command (or the CvUtil.pyPrint() method, above) to write your debug messages in \Documents\Games\Beyond the Sword\Logs\PythonDbg.log - just make sure that logging isn't disabled in the .ini file.
 
All right, I feel stupid having to ask this, but I just can't figure this out. How do I alter a mapscript to generate more resources/bonuses on the map? I don't want to do anything fancy, just make more of every resource.
 
I guess it depends on the map script. Somewhere there is obviously some code generating resources, so it should be as simple as changing some value, somewhere.

I'm yet to take a closer look at any map script myself, so I wouldn't where exactly to look. What map script are you looking to edit?
 
1. Where can I modify conditions, at which AI civ will accept peace agreement (I mean amount of gold, cities, techs, etc.)

2. Where can I modify AI workers priorities?
 
Back
Top Bottom