Attention ALL C++ programmers and python ditto: We need multiple maps in one game!

NikG

SDK Lover
Joined
Nov 30, 2005
Messages
170
Location
Glorious state of Denmark
General Info:
This is NOT a suggestion thread or something! It is purely intented to programmers in C++ and python that will help in making more maps possible in one game.

Why?

Several people want it in their mods in progress and it will certainly greatly increase the value of certain mods.

How?

Multiple maps will not be possible alone in python, we need the SDK, however people with python knowlegde will be appreciate to answer certain questions etc.

The first step:
In the final product moving units back and forth from one map to other should be possible, but there is no idea in starting from the top, so first of we need:
A secondary map in the game, which is initialized, generated with terrain and the possiblity to switch between them, so we can see the terrain on both.


Secondary note

I have my self worked extensively with this, and I have NOT succeded! :sad:
I believe that we need more than just the SDK, and that we need the source of the entire game to make this possible.
However I may be wrong, and maybe a combined effort of all skilled programmers could crack this problem.
 
To make all a little easier:
First an instance of CvMap is created in CvGlobals::init() The constructor calls CvMap::reset. And we have the CvMap::init.
However first of were is the call to the terrain generation? I havent been able to determin this!
 
I think this is a great idea. It would certainly add a new perspective on the game. Imagine a secondary map you end up at after launching the spaceship. Once there you get a new tech tree and can continue to advance to even more futuristic eras. :D

The possiblilities are almost infinite. :crazyeye:
 
You could also imagine multiple layers of the same board, so that there would be an "underground" or "alternate reality" or "ethereal" version of the regular game board. For example, if you want to have another layer of Cyber-warfare, it could be easier (or at least more realistic) to connect cities using "fiber optics" rather than roads in a parallel board than on the main board...
 
You wont get the entire source, however form my understanding the only source that isn't avalable to the public is the graphics engine. I do think this could be possible. memory would be a big issue however as my system struggles to run a single standard map. Two would give it a headache!
 
croxis said:
You wont get the entire source, however form my understanding the only source that isn't avalable to the public is the graphics engine. I do think this could be possible. memory would be a big issue however as my system struggles to run a single standard map. Two would give it a headache!

:mad: I KNOW I wont get the entire source code :vomit:

and I dont want it!
 
Since I know a lot about map scripting, maybe I can be of some help.

From CVMap.cpp
gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "beforeInit");

This calls the map script's beforeInit function. Map scripts are informed in CvMapScriptInterface.py that:
* beforeInit() # Can set up globals here to span variables across functions.

gDLL->getPythonIFace()->pythonGetGridSize(GC.getInitCore().getWorldSize(), &m_iGridWidth, &m_iGridHeight);
This method allows map scripts to override the default width and height declared in XML. For example, great plains uses this because it provides so much land that they use a small width and height. SmartMap uses this to allow you to set any width/height you want directly using dropdown controls.

gDLL->getPythonIFace()->pythonGetLatitudes(&m_iTopLatitude, &m_iBottomLatitude);
This allows map scripts to override the top and bottom latitudes, I'm not sure if anybody really uses this.

gDLL->getPythonIFace()->pythonGetWrapXY(&m_bWrapX, &m_bWrapY);
Lets you set the map wrap. The standard wrap is wrap x and not y.

Essentially all of the above is done before a map script really gets into the nitty gritty of generating tiles, terrain, bonuses, and player placement.

So now we come to where things get interesting. We somehow make a jump over to CVMapGenerator.cpp:

in CvMapGenerator::generateRandomMap()
gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "beforeGeneration");
This is another opportunity for map scripts to do precalculation.

Then we get to:
generatePlotTypes();
generateTerrain();

Now that's where the real work happens. And here is where you're going to get nailed with some real work to fix it for multiple maps. In particular, look at generatePlotTypes() since it comes first:

Code:
void CvMapGenerator::generatePlotTypes()
{
	int* paiPlotTypes = new int[GC.getMapINLINE().numPlotsINLINE()];

	int iNumPlots = GC.getMapINLINE().numPlotsINLINE();

	std::vector<int> plotTypesOut;
	if (gDLL->getPythonIFace()->pythonGeneratePlotTypes(plotTypesOut) && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override
	{
		FAssertMsg(plotTypesOut.size() == iNumPlots, "python generatePlotTypes() should return list with length numPlotsINLINE");
		for (int iI = 0; iI < iNumPlots; iI++)
		{
			paiPlotTypes[iI] = plotTypesOut[iI];
		}
	}
	else
	{
		for (int iI = 0; iI < iNumPlots; iI++)
		{
			paiPlotTypes[iI] = PLOT_LAND;
		}
	}

	setPlotTypes(paiPlotTypes);

	SAFE_DELETE_ARRAY(paiPlotTypes);
}

The call to gDLL->getPythonIFace()->pythonGeneratePlotTypes(plotTypesOut)
is where the map script gets to generate plot types. The other steps of map generation are similar.

So to address the multimap problem in particular, that GC.getMapINLINE(). method is going to be what I think your major hurdle is going to be. No doubt that is used all over the place (I found usages in 26 files). And I suspect you'll need to be modifying that to accomodate your multiple maps.

Anyway, I hope this is helpful.
 
Hey surt, thanks for the information, however where does it call CvMapGenerator::generateRandomMap() ? I am sure that this function is called when you what to regenerate a new map, but I am not 100 % sure, and I cant check were I am right now. Will get back to it when I get home!
 
surt said:
Looks like

CvGame::regenerateMap()

is what you'll want to look at next. That appears to be called from nowhere, so it must be the core engine that calls that method.
Looks like CvDLLButtonPopup.cpp calls it (the map regen button in the menu)
 
The xxxINLINE methods and such are inline in the .h, for instance:
inline int numPlotsINLINE() const
{
return getGridWidthINLINE() * getGridHeightINLINE();
}
So you would think you only have to change one file to touch the whole thing. Except there's a define that says outside the dll, getMapINLINE is not inline and is a call to getMap instead. So beware here, you'll have to change the INLINE and the not inline function both.

CvGame::regenerateMap() is probably only used when you click the regenerate map button in the world builder.

The big point is how can you swap from one map to another? I think that, since the map painting code is not available, you must fool it and swap maps. The easier way would probably be to rewrite the getMap() method and store not just one but several CvMap objects. If you can have a button that calls a method which switches the result of CvGlobals.getMap() to a new map, you'll probably be able to achieve your ends. I'd actually like to test it now but my CD is broken so *@#! :( ...
Now, if you're able to switch maps that way, the map generation etc won't be a problem. You'll just run the scripts several times and store the various maps... But then you'll probably want to either have different scripts for different maps, or at least give the map parameter to the map generator. That's useful if you want a scenario like Test of Time's fantasy setting, where the 4 maps had different terrain and layout, and, I believe, the underwater and earth map were somewhat linked in terms of terrain types. The air and subterranean levels were not linked but the subterranean level had straight tunnel terrains that didn't exist above for instance.
The problem with this, though, is the save game. You probably get called on getMap() in order to save it. It's probably the most important thing to find out as it will decide how you can have more than one map.

You also need to setup some map travel methods. Checking Civ2-ToT can give ideas here, though the scripting language and resources were really awkward in comparison with Civ IV.
 
Worse comes to worse, you could always set it up so that it splits one map into two halves (or quadrants or whatever for however many maps you need) that can function virtually independent of one another... that would also make sure that its not too much for the system, although, of coruse, then it would limit the size of any half/quadrant.
 
LDiCesare said:
The xxxINLINE methods and such are inline in the .h, for instance: So you would think you only have to change one file to touch the whole thing. Except there's a define that says outside the dll, getMapINLINE is not inline and is a call to getMap instead. So beware here, you'll have to change the INLINE and the not inline function both.

CvGame::regenerateMap() is probably only used when you click the regenerate map button in the world builder.

The big point is how can you swap from one map to another? I think that, since the map painting code is not available, you must fool it and swap maps. The easier way would probably be to rewrite the getMap() method and store not just one but several CvMap objects. If you can have a button that calls a method which switches the result of CvGlobals.getMap() to a new map, you'll probably be able to achieve your ends. I'd actually like to test it now but my CD is broken so *@#! :( ...
Now, if you're able to switch maps that way, the map generation etc won't be a problem. You'll just run the scripts several times and store the various maps... But then you'll probably want to either have different scripts for different maps, or at least give the map parameter to the map generator. That's useful if you want a scenario like Test of Time's fantasy setting, where the 4 maps had different terrain and layout, and, I believe, the underwater and earth map were somewhat linked in terms of terrain types. The air and subterranean levels were not linked but the subterranean level had straight tunnel terrains that didn't exist above for instance.
The problem with this, though, is the save game. You probably get called on getMap() in order to save it. It's probably the most important thing to find out as it will decide how you can have more than one map.

You also need to setup some map travel methods. Checking Civ2-ToT can give ideas here, though the scripting language and resources were really awkward in comparison with Civ IV.

Okay first and foremost, I have already tried this! It crashes every time. I could create two instances of CvMap, and I edited the INLINE function both places, etc. etc. etc. And it did not work.

And to surt-> In the CvMap::init, the plot may be initialized, but that is not the same thing as being "ready for work", so what I need to known is:
were does the game generate the map. And indeed we have the regeneratemap, I think, as do others, that this is used by the function in the menu, not the initial generation....
 
NikG said:
Okay first and foremost, I have already tried this! It crashes every time. I could create two instances of CvMap, and I edited the INLINE function both places, etc. etc. etc. And it did not work.

And to surt-> In the CvMap::init, the plot may be initialized, but that is not the same thing as being "ready for work", so what I need to known is:
were does the game generate the map. And indeed we have the regeneratemap, I think, as do others, that this is used by the function in the menu, not the initial generation....

I think if that's the case you're in trouble because that's the only location those map generation methods are called. You'll probably have to just force all the necessary calls yourself, either changing the getmapinline to return the right map, or changing every use to use the right map.
 
I just wanted to add that even though I don't have much to offer as help right now Im watching this thread closely and hoping you guys come up with a way of doing this (Im sure many others are too).

I'll up the ante and offer a date with Woodelf to anyone who accomplishes this task. :D
 
You might try another trick if you're stuck with one CvMap: Divide it in several submaps (like the top is the first map, the bottom is the second). Then pretend it's smaller than what it actually is, and change the iterator on plots so it returns either the top map or the bottom map? That's a kludge and will probably crash as much as several CvMaps, though...
 
Top Bottom