seasonal terrain changes

hachejay

beta shopper
Joined
Dec 30, 2009
Messages
43
Location
United Kingdom
hello! I've been playing around with making terrain change every few turns to simulate seasonal changes. This is the main chunk of code that I have so far: (from CvGame.cpp)

Code:
void CvGame::updateSeasonState()
{
	int iSeasonClock;		//timer
	int iX, iY;				//coordinates
	CvPlot* pPlot;			//plot

	TerrainTypes eSpringGrass = ((TerrainTypes)(GC.getDefineINT("TERRAIN_SPRING_GRASS")));		//terrain defines for XML import (CvXMLLoadUtilitySet.cpp)
	TerrainTypes eSummerGrass = ((TerrainTypes)(GC.getDefineINT("TERRAIN_SUMMER_GRASS")));
	TerrainTypes eAutumnGrass = ((TerrainTypes)(GC.getDefineINT("TERRAIN_AUTUMN_GRASS")));
	TerrainTypes eWinterGrass = ((TerrainTypes)(GC.getDefineINT("TERRAIN_WINTER_GRASS")));

	if (iSeasonClock < 12)		//move the timer on 1
		{
			iSeasonClock++;
		}

	if (iSeasonClock == 3)		//set spring terrain on 3rd turn of timer
		{
			for(iX = 0; iX < GC.getMapINLINE().getGridWidthINLINE(); iX++)
			{
				for(iY = 0; iY < GC.getMapINLINE().getGridHeightINLINE(); iY++)
				{
					pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
					{
						if (pPlot->getTerrainType() == eWinterGrass)
						{
							pPlot->setTerrainType(eSpringGrass);
						}
					}
				}
			}
		}

	if (iSeasonClock == 6)		//set summer terrain on 6th turn of timer
		{
			for(iX = 0; iX < GC.getMapINLINE().getGridWidthINLINE(); iX++)
			{
				for(iY = 0; iY < GC.getMapINLINE().getGridHeightINLINE(); iY++)
				{
					pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
					{
						if (pPlot->getTerrainType() == eSpringGrass)
						{
							pPlot->setTerrainType(eSummerGrass);
						}
					}
				}
			}
		}

	if (iSeasonClock == 9)		//set autumn terrain on 9th turn of timer
		{
			for(iX = 0; iX < GC.getMapINLINE().getGridWidthINLINE(); iX++)
			{
				for(iY = 0; iY < GC.getMapINLINE().getGridHeightINLINE(); iY++)
				{
					pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
					{
						if (pPlot->getTerrainType() == eSummerGrass)
						{
							pPlot->setTerrainType(eAutumnGrass);
						}
					}
				}
			}
		}

	if (iSeasonClock == 12)		//set winter terrain on 12th turn of timer
		{
			for(iX = 0; iX < GC.getMapINLINE().getGridWidthINLINE(); iX++)
			{
				for(iY = 0; iY < GC.getMapINLINE().getGridHeightINLINE(); iY++)
				{
					pPlot = GC.getMapINLINE().plotINLINE(iX, iY);
					{
						if (pPlot->getTerrainType() == eAutumnGrass)
						{
							pPlot->setTerrainType(eWinterGrass);
						}
					}
				}
			}

		iSeasonClock = 0;	//reset timer to start

	}

}

The dll compiles with one warning:

Code:
...makefile\cvgamecoredll\cvgame.cpp(6638): warning C4700: local variable 'iSeasonClock' used without having been initialized

The game runs ok but the code appears to do nothing.

Would anyone with slightly better programming knowledge mind having a quick look at this and seeing if I've done anything obviously wrong?

Cheers!

hache
 
I don't know any actual C++ but it seems that you need to assign some default value to iSeasonClock before checking it. Makes sense, not?
 
If I understand what you're trying to do, then you need to maintain the season clock value between different calls to your function. That means that you shouldn't use it as a local variable, but to make it a member variable of CvGame.

To do that you need to place the variable inside the definition of the class in CvGame.h.

If you need more details - feel free to ask.
 
i'm not too good with c++ either (hence the plea for help!) but I thought it would assign it a starting value automatically. I hadn't given it a default value because as this is to be run every turn I was worried it would set it the same value every turn, which would stop my code from doing anything. However, changing it to
Code:
int iSeasonClock=0;
does get rid of the compile problem, so thankyou! ;)


...still doesnt have any effect in though. :(

confusion abounds.
 
To do that you need to place the variable inside the definition of the class in CvGame.h.

that would make sense, thankyou!... not entirely sure where to do that though: currently the only line in CvGame.h is

Code:
	void updateSeasonState();

is what you mean just moving int iSeasonClock; to the file too? if so where, like just under the above?
 
In CvGame.h you'll see 2 lines saying:
Code:
class CvGame
{

This is the start of the class definition.
Everything from there to the closing brackets ('}') is defined inside the class.

You should place both your function (if you haven't done so already) and this variable inside this.

It is a convention to name member variables with a standard prefix - in the civ code (and also what I usually use) it's 'm_'. So you'll declare your variable like this:
Code:
int m_iSeasonClock;

You should initialize this variable in the reset() method, where most variables are initialized (this method is already called in the cases where it's needed).

Look for CvGame::reset in CvGame.cpp, and in it just add:
Code:
m_iSeasonClock = 0;

EDIT: You might want this value to be saved when you save the game. In this case - checkout the CvGame::read() and CvGame::write() methods.
Note that it will break existing saved games. unless you specifically make sure it doesn't.
 
had a little thought about possibly making some changes occur randomly, and had a quick question about uses of srand and rand:

am i right in thinking that using srand(time(null)) would only change per/second?

ie in this case, if i used the code in my first post to check each plot at x/y but then called a random number to decide whether or not a change in each tile should occur, would the seed from srand not update quick enough to change this?

as in would something like this:
Code:
	if (pPlot->getTerrainType() == eTerrainWhatever)
	{
		srand(time(null));

		m_iChangePercent = rand() % 100;

		if m_iChangePercent < 65
		{									
			pPlot->setTerrainType(eSomethingElse)
		}
	}

not work because every plot check in one second would get the same seed and hence would all either change or not?


ps. I only just noticed your edit, Asaf! That's a very good point I had not considered and will have to look into! Thank you!
 
Two things:
Regarding using rand and srand - generally when you use random numbers in C++ you only initialize the seed once per program, and then the list of random numbers is different for the entirety of the session.

Regarding using random numbers in Civ 4 - Civ 4 has a built-in mechanism for generating random numbers, which guarantee two things: that these numbers are shared between different players in multiplayer, and that the same number will be used when you re-load the game (the current seed is saved with the game).
For the saved games issues you have an option to recreate the seed whenever you load a game (in the options menu).

To use the built-in mechanism you should use GC.getGameINLINE().getSorenRandNum() (look for it in the code. You'll find it in many places).
That is in case you care that this value be shared in MP or saved with the game. If it's just graphics, you might not care.
 
oh wow, that's a lot easier! from looking at the code already there does that mean I can use it simply like this:

Code:
if (GC.getGame().getSorenRandNum(100, "Weather check") < 66)
	{									
		pPlot->setTerrainType(eWhatever)
	}

Also, I take it the text inside the speech marks doesn't actually make any difference to anything?

Thanks again for your help!
 
Also, I take it the text inside the speech marks doesn't actually make any difference to anything?

Thanks again for your help!

Only logging and debugging.
You're welcome :)
 
Back
Top Bottom