
(discontinued)
Prologue
Spoiler :
With the news that civ5 will be requiring us to make a transition from squares to hexagons (aka hexes) as our preferred unit of gameboard, there has been much discussion on how these new shapes will behave. Some have even wondered so much the pesky hexes have invaded their dreams, tormenting their civ4-playing souls. "How", they wonder, "could civ4 be imagined in this new geometry?"
With this in mind, I decided to embark on a journey of epic proportions. I took the first step towards creating a love-child of hexes and squares, in the hope that civ4 could borrow some of the genius of the tactically superior hex formation. This was a messy process and not pleasant for the victim square who went under the knife. Two of its opposite corners were cut clean off, proving the point to all the other squares on the grid that it was possible for them too to become hexes. Packed like sardines, these artificial hexes were only partly relieved to find they now only touched 6 other units and noted that it was at least better than being crammed to the point where they would be touching 8 other units.
Meanwhile the omniscient began to play civ on their mangled bodies.

Now that I've proven I've no writing talent, why don't we get straight to the good bit: The HEX Mod.
In this mod we mess with one of the most fundamental rules of the game - adjacency. Currently all tiles on the board, apart from those at the poles, neighbour 8 other tiles because they are all packed as squares. By changing the adjacency rules slightly, by banning one of the diagonal directions for movement (among other things) we can functionally duplicate a true hex board.
Now, my progress so far has been sketchy. My first attempt allowed a successful compile but this is how it looked in game - clearly I broke it!


After fixing a few obvious and careless mistakes/bugs, I obtained:

Also getting infinite loops, almost certainly because I've mucked up something with a loop through NUM_DIRECTION_TYPES.
Here's how you use a square gameboard to play on hexes:
(each number is the distance from the red 0.
Code:
// 3 | 3 | 3 | 3 | 4 | 5 | 6
// -------------------------
// 3 | [b]2[/b] | [b]2[/b] | [b]2[/b] | 3 | 4 | 5
// -------------------------
// 3 | [b]2[/b] | [color="blue"]1[/color] | [color="blue"]1[/color] | [b]2[/b] | 3 | 4
// -------------------------
// 3 | [b]2[/b] | [color="blue"]1[/color] | [color="red"]0[/color] | [color="blue"]1[/color] | [b]2[/b] | 3
// -------------------------
// 4 | 3 | [b]2[/b] | [color="blue"]1[/color] | [color="blue"]1[/color] | [b]2[/b] | 3
// -------------------------
// 5 | 4 | 3 | [b]2[/b] | [b]2[/b] | [b]2[/b] | 3
// -------------------------
// 6 | 5 | 4 | 3 | 3 | 3 | 3
// 3 | 3 | 3 | 3 | 4 | 5 | 6
// -------------------------
// 3 | [b]2[/b] | [b]2[/b] | [b]2[/b] | 3 | 4 | 5
// -------------------------
// 3 | [b]2[/b] | [color="blue"]1[/color] | [color="blue"]1[/color] | [b]2[/b] | 3 | 4
// -------------------------
// 3 | [b]2[/b] | [color="blue"]1[/color] | [color="red"]0[/color] | [color="blue"]1[/color] | [b]2[/b] | 3
// -------------------------
// 4 | 3 | [b]2[/b] | [color="blue"]1[/color] | [color="blue"]1[/color] | [b]2[/b] | 3
// -------------------------
// 5 | 4 | 3 | [b]2[/b] | [b]2[/b] | [b]2[/b] | 3
// -------------------------
// 6 | 5 | 4 | 3 | 3 | 3 | 3
Here is the picture from earlier mangled to try and show the hex nature:

This distance function does the job, and is enough to get the cultural expansions of cities looking correct. It is in CvGameCoreUtils.cpp
Code:
inline int plotDistance(int iX1, int iY1, int iX2, int iY2) // Exposed to Python
{
int iDX;
int iDY;
iDX = iX2 - iX1;
iDY = iY2 - iY1;
int sizeX = (iDX<0?-iDX:iDX);
int sizeY = (iDY<0?-iDY:iDY);
int iA = std::max(iDX - iDY,iDY - iDX); // distance b/n the two.
int iM = std::min(sizeX,sizeY);
return std::min(iA + iM,sizeX+sizeY);
}

It's already pretty speedy, but since this code is called extremely frequently, perfection is preferred.
This is what the above replaces. Note that both plotDistance and stepDistance I plan to replace for the HEX Mod.
Code:
[COLOR="SeaGreen"]// 4 | 4 | 3 | 3 | 3 | 4 | 4
// -------------------------
// 4 | 3 | 2 | 2 | 2 | 3 | 4
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 0 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 4 | 3 | 2 | 2 | 2 | 3 | 4
// -------------------------
// 4 | 4 | 3 | 3 | 3 | 4 | 4
//
// Returns the distance between plots according to the pattern above...[/COLOR]
inline int plotDistance(int iX1, int iY1, int iX2, int iY2) // Exposed to Python
{
int iDX;
int iDY;
iDX = xDistance(iX1, iX2);
iDY = yDistance(iY1, iY2);
return (std::max(iDX, iDY) + (std::min(iDX, iDY) / 2));
}
[COLOR="SeaGreen"]// 3 | 3 | 3 | 3 | 3 | 3 | 3
// -------------------------
// 3 | 2 | 2 | 2 | 2 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 0 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 2 | 2 | 2 | 2 | 3
// -------------------------
// 3 | 3 | 3 | 3 | 3 | 3 | 3
//
// Returns the distance between plots according to the pattern above...[/COLOR]
inline int stepDistance(int iX1, int iY1, int iX2, int iY2) // Exposed to Python
{
return std::max(xDistance(iX1, iX2), yDistance(iY1, iY2));
}
Notes:
Spoiler :
The things the mod should affect:
-Unit movement (not done yet)
-City border expansion (done)
-plus more
Files, locations to examine:
CvGameCoreUtils.h: plotDistance() and stepDistance()
plotDistance is nearly the Euclidean distance. stepDistance is the sort that units would use - diagonalss count as distance 1.
(Change1)
CvMap.cpp: maxStepDistance(), maxPlotDistance()
Uses stepDistance() and plotDistance() but alos makes calls to things like getGridWidthINLINE. Probably needs fixing.
How this will change will depend on how they get used. It's use in CvPlayer.cpp looks the most worrying. It also appears near the end of CvPlayerAI::AI_foundValue.
Whatever change is made, both functions will presumably look identical. It also looks like there's no need to tie it to the (0,0) coordinate. In fact doing so would be wrong.
How will this work if Y wrap is permitted?
(Change2)
...
+Several other points in the code most likely. Some bits could get messy, like looking at how rivers work, and what corners of tiles are.
Notes:
stepDistance() is used in CvGameCoreUtils.cpp in two places, for both of pathHeuristic and stepHeuristic. To my knowledge, both these things are to do with the A* pathfinding algorithm.
(0,0) coordinate is in the bottom left corner of the map.
Hence we make the banned direction be NW and SE (for easier distance calculations I think).
-Unit movement (not done yet)
-City border expansion (done)
-plus more
Files, locations to examine:
CvGameCoreUtils.h: plotDistance() and stepDistance()
plotDistance is nearly the Euclidean distance. stepDistance is the sort that units would use - diagonalss count as distance 1.
(Change1)
CvMap.cpp: maxStepDistance(), maxPlotDistance()
Uses stepDistance() and plotDistance() but alos makes calls to things like getGridWidthINLINE. Probably needs fixing.
How this will change will depend on how they get used. It's use in CvPlayer.cpp looks the most worrying. It also appears near the end of CvPlayerAI::AI_foundValue.
Whatever change is made, both functions will presumably look identical. It also looks like there's no need to tie it to the (0,0) coordinate. In fact doing so would be wrong.
How will this work if Y wrap is permitted?
(Change2)
...
+Several other points in the code most likely. Some bits could get messy, like looking at how rivers work, and what corners of tiles are.
Notes:
stepDistance() is used in CvGameCoreUtils.cpp in two places, for both of pathHeuristic and stepHeuristic. To my knowledge, both these things are to do with the A* pathfinding algorithm.
(0,0) coordinate is in the bottom left corner of the map.
Hence we make the banned direction be NW and SE (for easier distance calculations I think).
This mod is intended as a bit of fun and should be treated as mostly experimental at this point. I don't have plans to make it very pretty and if it does reach a final stage it will probably have some visual quirks associated with it.
I will likely need some help/advice from some SDK and perhaps Python modders out there. Anyone interested in helping out? It probably won't take a lot of work, luckily.
The first thing I am trying to figure out how to do is to restrict unit movement so that NW and SE directions are banned. If anyone can confirm it's not something locked in the EXE, that would give me peace of mind.
