Increasing AI opponents past 22?

AtrainV

Chieftain
Joined
Aug 11, 2012
Messages
22
Disclaimer: I know extremely little about modding/scripting/programming.

I really love Gedemon's YNAEMP. Honestly it's the only thing I play in Civ 5 anymore. I love how it allows me to play alternate versions of earth's history. I especially love the fact that he created a "Giant" earth map that allows for more space in the regions that often get overcrowded on traditional TSL maps.

However, I dislike the fact that I have to pick and choose certain civs to include while excluding others. The only reason for this currently is because of the 22 AI opponent cap. Previously when I had inquired about this, I was told the until the main .dll is released to the public, there is no way to alter this.

Now that the main .dll has been opened up, has any progress been made on this front? In Gedemon's thread for the YNAEMP mod it seemed that he hadn't been able to figure it out yet, but I was wondering if anybody else had tinkered with it and seen any positive results. So, what's the current state of this situation?

tl;dr Now that the main .dll is open to the public, can we figure out how to increase the number of opponent AIs past 22?
 
... but it is not all that is needed.

If you increase MAX_MAJOR_CIVS above 22 and then try and play on a Pangea map, the CvStartPositioner::SubdivideRegion() method will assert (fail) as it doesn't know how to divide the land mass into more than 22 regions (although the assert message reads 18!) - a "good" example of the problems hard-coded into the DLL code :eek:
 
If you increase MAX_MAJOR_CIVS above 22 and then try and play on a Pangea map, the CvStartPositioner::SubdivideRegion() method will assert (fail) as it doesn't know how to divide the land mass into more than 22 regions (although the assert message reads 18!) - a "good" example of the problems hard-coded into the DLL code :eek:

So what is the next frontier? I.E. What as to be done now to overcome this?
 
What has to be done now to overcome this?
Someone (not me) has to sit down with the code and identify every method that assumes there are a max of 22 major civs - and as that example shows they are not all obvious - and then work out how to correctly code the assumptions.
 
Someone (not me) has to sit down with the code and identify every method that assumes there are a max of 22 major civs - and as that example shows they are not all obvious - and then work out how to correctly code the assumptions.


Either this or point them to MAX_MAJOR_CIVS.

I'm no coder, but I'll have a look and see what I can deduce.

EDIT: I've figured it out. Read the comments between lines 23 and 33. The offending code is between lines 34 and 92.

Imagine our world as a piece of paper. You want to cut it into even pieces if you can. First, you need to know how many initial pieces to cut. Then, you need to know how many pieces to cut each initial piece into. Leftover cuts are fine, but should be minimized. Judging by this, a map with a scenario that has all the starting positions already defined SHOULD work with just MAX_MAJOR_CIVS raised.

You must input each case manually. Do we have a math nerd that could come up with a formula for this? Ideally, we should be handing up to 64 major civ regions. Just for good measure.

Code:
[LIST=1]
[*]void CvStartPositioner::SubdivideRegion (CvStartRegion region, int iNumDivisions)
[*]{
[*]	int iNumDivides = 0;
[*]	int iLaterSubdivisions = 0;

[*]	// Break recursion when number of divisions is down to 1
[*]	if (iNumDivisions == 1)
[*]	{
[*]		// Store this as a final region
[*]		m_StartRegionVector.push_back(region);
[*]	}

[*]	// Need to subdivide
[*]	else if (iNumDivisions > 1)
[*]	{
[*]		// See if region is taller or wider
[*]		bool bTaller = true;
[*]		if ((region.m_Boundaries.m_iNorthEdge - region.m_Boundaries.m_iSouthEdge) <
[*]			(region.m_Boundaries.m_iEastEdge - region.m_Boundaries.m_iWestEdge))
[*]		{
[*]			bTaller = false;
[*]		}

[*]		// If number of divisions is greater than 3...
[*]		//
[*]		// Number       First Divide     Each Subdivision
[*]		// ------       ------------     ----------------
[*]		//   4                2                 2
[*]		//  5-6               3                 2
[*]		//  7-8               2                 4
[*]		//   9                3                 3
[*]		// 10-12              3                 4
[*]		// 13-16              2                 8
[*]		// 17-18              3                 6
[*]		// 19-20              2                10
[*]		// 21-22              3                 8
[*]		switch (iNumDivisions)
[*]		{
[*]		case 2:
[*]			iNumDivides = 2;
[*]			iLaterSubdivisions = 1;
[*]			break;
[*]		case 3:
[*]			iNumDivides = 3;
[*]			iLaterSubdivisions = 1;
[*]			break;
[*]		case 4:
[*]			iNumDivides = 2;
[*]			iLaterSubdivisions = 2;
[*]			break;
[*]		case 5:
[*]		case 6:
[*]			iNumDivides = 3;
[*]			iLaterSubdivisions = 2;
[*]			break;
[*]		case 7:
[*]		case 8:
[*]			iNumDivides = 2;
[*]			iLaterSubdivisions = 4;
[*]			break;
[*]		case 9:
[*]			iNumDivides = 3;
[*]			iLaterSubdivisions = 3;
[*]			break;
[*]		case 10:
[*]		case 11:
[*]		case 12:
[*]			iNumDivides = 3;
[*]			iLaterSubdivisions = 4;
[*]			break;
[*]		case 13:
[*]		case 14:
[*]		case 15:
[*]		case 16:
[*]			iNumDivides = 2;
[*]			iLaterSubdivisions = 8;
[*]			break;
[*]		case 17:
[*]		case 18:
[*]			iNumDivides = 3;
[*]			iLaterSubdivisions = 6;
[*]			break;
[*]		case 19:
[*]		case 20:
[*]			iNumDivides = 2;
[*]			iLaterSubdivisions = 10;
[*]			break;
[*]		case 21:
[*]		case 22:
[*]			iNumDivides = 3;
[*]			iLaterSubdivisions = 8;
[*]			break;
[*]		default:
[*]			CvAssertMsg (false, "Trying to create regions for more than 18 major civs.");
[*]		}

[*]		if (iNumDivides == 2)
[*]		{
[*]			CvStartRegion secondRegion;
[*]			ChopIntoTwoRegions(bTaller, &region, &secondRegion, 50);
[*]			SubdivideRegion(region, iLaterSubdivisions);
[*]			SubdivideRegion(secondRegion, iLaterSubdivisions);
[*]		}
[*]		else if (iNumDivides == 3)
[*]		{
[*]			CvStartRegion secondRegion;
[*]			CvStartRegion thirdRegion;
[*]			ChopIntoThreeRegions(bTaller, &region, &secondRegion, &thirdRegion);
[*]			SubdivideRegion(region, iLaterSubdivisions);
[*]			SubdivideRegion(secondRegion, iLaterSubdivisions);
[*]			SubdivideRegion(thirdRegion, iLaterSubdivisions);
[*]		}
[*]	}
[*]}
[/LIST]
 
If you increase MAX_MAJOR_CIVS above 22 and then try and play on a Pangea map, the CvStartPositioner::SubdivideRegion() method will assert (fail) as it doesn't know how to divide the land mass into more than 22 regions (although the assert message reads 18!) - a "good" example of the problems hard-coded into the DLL code :eek:

noob question: my build does not give assert, is there something to configure before compiling ?
 
noob question: my build does not give assert, is there something to configure before compiling ?

Did you try this on a map with the starting positions already set? I'd assume so, considering YnAEM with TSL. In theory, it shouldn't give that specific assert if you have ALL the starting locations set.
 
YnAEMP have no TSL set on the WB map, it define the starting location during loading. And I'm testing on normal game / script map, to be sure mod does not interfere :)
 
YnAEMP have no TSL set on the WB map, it define the starting location during loading. And I'm testing on normal game / script map, to be sure mod does not interfere :)

Is it just crashing, failing to assert? Please yield unto us a more prolix explanation.
 
crashing on map loading with max major > 22, crashing during AI (city states) turn if max major = 22 and max payers raised to 79 (and more than 41 CS on setup, haven't tried with less)

note that with max major defined above 22 it still crash on load with a dual map with only 2 civs and 1 CS.

testing on vanilla DLL ATM.
 
Looking at the code posted it seems like a simple iNumDivides * iLaterSubdivisions to get how many starting positions it can support. If that's true then it's very simple to increase it and it would also mean it already supports up to 24 players, just add a case for 23 and 24 players where 21 and 22 are now. That however most likely won't solve the crashes, so it's just a start.

noob question: my build does not give assert, is there something to configure before compiling ?

Check CvAssert.h. By default asserts are off in any build with FINAL_RELEASE defined. It's defined in the projects property page, under preprocessor. But easier than changing that is to change the #if in the header. (changing it from FINAL_RELEASE under preprocessor may have other consequences.)
 
Is it just crashing, failing to assert? Please yield unto us a more prolix explanation.

wait, just tried with YnAEMP again (as the new vanilla setup menu with the keep setting features hadn't liked at all that I tried to set more than 22 civs in my previous test), adding case 23 and 24 in CvStartPositioner, and the DLL that was crashing on dual continent has launched the giant earth with 24 civs :think:
 
what is YnAEMP & TSL?

YnAEMP and TSL = True Starting Location


back on the subject, I'm starting to think that my first tests were on G&K DLL...

& thanks for the info for CVASSERT_ENABLE snarko.

back to test now...
 
wait, just tried with YnAEMP again (as the new vanilla setup menu with the keep setting features hadn't liked at all that I tried to set more than 22 civs in my previous test), adding case 23 and 24 in CvStartPositioner, and the DLL that was crashing on dual continent has launched the giant earth with 24 civs :think:


Did I help?

Also, here's a table showing the additional cases that need to be added. As you can see, we get less and less efficient (having more leftover divisions) as our civ count increases. Civilizations is the CivCount, Divs is Divisions, and Subs is Subdivisions.

Please someone check over this and edit as needed.

First Table
Spoiler :
Civilizations | Divs | Subs
25, 26, 27, 28|2|14
29, 30|3|10
31, 32|2|16
33, 34|3|12
35, 36|2|18
37, 38, 39, 40|2|20
41, 42|3|14
43, 44|2|22
45, 46|3|16
47, 48|2|24
49, 50, 51, 52, 53, 54|3|18
55, 56|2|28
57, 58, 59, 60|3|20
61, 62, 63, 64|2|32

Notice an interesting pattern? Look at every other Subs value.


Civilizations | Divs | Subs
25, 26|2|13
27|3|9
28|2|14
29, 30|3|10
31, 32|2|16
33|3|11
34|2|17
35, 36|2|18
37, 38|2|19
39|3|13
40|2|20
41, 42|3|14
43, 44|2|22
45|3|15
46|3|16
47, 48|2|24
49, 50|2|25
51, 52|2|26
53, 54|3|18
55, 56|2|28
57, 58|2|29
59, 60|3|20
61, 62|2|31
63, 64|2|32
 
I was trying to work out how they've related the total number of civs to the pairs of numbers in a mathematical way but so far no dice. If anyone wants to take a crack at it, I made a quick console app that tests whether a given math operation gives the same results as the given switch statement. You need visual studio 2010 to open the project. It's written in C# but it should be fairly self explanatory.

The Program.Op(int) function takes in the total number of civs and returns a Pair class. (Pair has two fields, First and Second, first is iNumDivisions, second is iLaterSubDivisions.) It compares the results to each of the example answers and tells you if something went wrong what it expected and what it got instead. When you run it the program checks all number of civs between 0 and 45, obviously only comparing the ones that have existing values to map to in the source code. (so i > 1 && i < 23)

EDIT: So far nothing simple has returned all correct pairs past 7.

Dunno how helpful it'll be to anyone, some kind of graphing tool might be more effective.
 

Attachments

Did I help?
Forcing me to try again with YnAEMP was a good idea :D

But without whoward69 I would never I've though at looking at SubdivideRegion, still not getting assert (but maybe it's because my code crash in a place where there is no assert...)
 
I was trying to work out how they've related the total number of civs to the pairs of numbers in a mathematical way but so far no dice. If anyone wants to take a crack at it, I made a quick console app that tests whether a given math operation gives the same results as the given switch statement. You need visual studio 2010 to open the project. It's written in C# but it should be fairly self explanatory.

The Program.Op(int) function takes in the total number of civs and returns a Pair class. (Pair has two fields, First and Second, first is iNumDivisions, second is iLaterSubDivisions.) It compares the results to each of the example answers and tells you if something went wrong what it expected and what it got instead. When you run it the program checks all number of civs between 0 and 45, obviously only comparing the ones that have existing values to map to in the source code. (so i > 1 && i < 23)

EDIT: So far nothing simple has returned all correct pairs past 7.

Dunno how helpful it'll be to anyone, some kind of graphing tool might be more effective.

Try testing something involving their divisibility by either 2 or 3. I'm sure you can come up with something.
 
As you can see, we get less and less efficient (having more leftover divisions) as our civ count increases.
Is it important to follow a pattern ?

ATM I'm testing 34 civs on YnAEMP with G&K, and I have set 3*9, 10, 12 for values above 24... :D
 
Back
Top Bottom