Civilization Fanatics' Forums Capitulation Mechanics

 Apr 12, 2009, 10:06 AM #1 Gooblah Heh...     Join Date: Jun 2007 Posts: 4,282 Team Diplomacy (incl. Capitulation/Vassals) Browsing through the files, I found the code for capitulation. My main concern is the way average power is calculated - literally, Total Power divided by the Number of Civs. Sounds good, but the presence of weak colonies or vassals makes an AI impossible to capitulate even if they have one city left and one unit, so long as that unit is an MA and a backwards colony is using Longbowmen. Okay, maybe a bit of exaggeration, but the point holds. Anywho, I'm considering two methods to change this. 1) Drop the last three (variable, based on MapSize) Civs in terms of power. 2) Ignore colonies and vassals in the calculations. Any tips on how to go about the first? It seems less drastic than the second, and more player-friendly. __________________ It'll all work out. Last edited by Gooblah; Apr 28, 2009 at 06:26 PM. Reason: changed title
 Apr 24, 2009, 03:18 PM #2 Gooblah Heh...     Join Date: Jun 2007 Posts: 4,282 I found an incredibly simple solution, but I'm having trouble figuring how to identify Worldsize. I included CyMap.h in CvTeamAI.cpp, but I'm sure how to utilize the getWorldSize() function. any ideas? Edit, never mind, i think i got it. Could someone review this code for me? Code: ``` int mapsize = CyMap::getWorldSize; int iAveragePower; if (mapsize == WORLDSIZE_DUEL || mapsize == WORLDSIZE_TINY) iAveragePower = iTotalPower / std::max(1, GC.getGameINLINE().countCivTeamsAlive()); else if (mapsize == WORLDSIZE_SMALL || mapsize == WORLDSIZE_STANDARD) iAveragePower = iTotalPower / (std::max(1, GC.getGameINLINE().countCivTeamsAlive())-2); else if (mapsize == WORLDSIZE_LARGE || mapsize == WORLDSIZE_HUGE) iAveragePower = iTotalPower / (std::max(1, GC.getGameINLINE().countCivTeamsAlive())-3);``` Note, in-file line 1 is on the same column as line 2. __________________ It'll all work out. Last edited by Gooblah; Apr 24, 2009 at 03:33 PM.
 Apr 24, 2009, 04:59 PM #3 phungus420 Deity     Join Date: Mar 2003 Posts: 6,296 You should bring this over to the better AI forums, especially if you have working code. __________________ Do not PM me with questions about modding. I will not answer. If you want help with something, start a thread on it, or post in a related existing thread.
Apr 24, 2009, 05:20 PM   #4
Gooblah
Heh...

Join Date: Jun 2007
Posts: 4,282
Quote:
 Originally Posted by phungus420 You should bring this over to the better AI forums, especially if you have working code.
Thanks! Sadly, I can't compile due my usage of a) Vista, b) VS 2009, and c) inability to find the libs folder for the program (and thus, can't insert the necessary libraries to make everything work).
__________________
It'll all work out.

Apr 26, 2009, 10:43 AM   #5
Gooblah
Heh...

Join Date: Jun 2007
Posts: 4,282
Okayy....got compiling to work.

However, there is an error. Apparently, I can't call CyMap::getWorldSize like that, meaning that I'm making a foolish error. It's probably simple, so....hmm.

this is the current code:

Code:
`int mapsize = CyMap::getWorldSize;`
and it gets this error:
Quote:
 CvTeamAI.cpp|1594|error C3867: 'CyMap::getWorldSize': function call missing argument list; use '&CyMap::getWorldSize' to create a pointer to member||

Now, I tried adding the '&' symbol for the pointer, but i got another compiling error; apparently, getWorldSize() is a void, while my variable is an int. At the same time, I can't change my variable's type...rrgh. Any ideas? I ran through the CvMap and CyMap .cpp/.h to find otu if I was calling the function incorrectly...

Edit: WOOOOOOOOOOOOOOOOOOOOO! it compiled! fixed it after a few hours (really dumb mistake, messed with pointers/classes). Code I added/altered:

Code:
```int iTotalPower = GC.getGameINLINE().countTotalCivPower();
int iAveragePower, worldsize;
CvMap i;
worldsize = i.getWorldSize();
if (worldsize == WORLDSIZE_DUEL || worldsize == WORLDSIZE_TINY)
iAveragePower = iTotalPower / std::max(1, GC.getGameINLINE().countCivTeamsAlive());
else if (worldsize == WORLDSIZE_SMALL || worldsize == WORLDSIZE_STANDARD)
iAveragePower = iTotalPower / (std::max(1, GC.getGameINLINE().countCivTeamsAlive())-2);
else if (worldsize == WORLDSIZE_LARGE || worldsize == WORLDSIZE_HUGE)
iAveragePower = iTotalPower / (std::max(1, GC.getGameINLINE().countCivTeamsAlive())-3);
int iMasterPower = GET_TEAM(eTeam).getPower(false);
int iVassalPower = (getPower(true) * (iPowerMultiplier + iPersonalityModifier / std::max(1, iMembers))) / 100;```
Edit 2: Dammit! Another problem. Compiler couldn't input 'release.obj'. No idea what this is...any clues?
__________________
It'll all work out.

Last edited by Gooblah; Apr 26, 2009 at 05:14 PM.

 Apr 26, 2009, 05:10 PM #6 EmperorFool Deity     Join Date: Mar 2007 Location: Mountain View, California Posts: 9,625 The problem with your code is that you're creating a new map and asking it for its size, which probably defaults to STANDARD. What you want to do instead is ask the game for the map that's being used and get the size from it. Code: `int iMapSize = GC.getMap().getWorldSize();` __________________ Monkeys killing monkeys killing monkeys over pieces of the ground. Silly monkeys, give them thumbs they make a club and beat their brother down. BUG Mod - BTS Unaltered Gameplay [ Forum | Download | FAQ | Known Issues | Troubleshooting | Modding Tutorial ] BAT 3.0.1 QuickFix™ released Oct 24th
Apr 26, 2009, 05:24 PM   #7
Gooblah
Heh...

Join Date: Jun 2007
Posts: 4,282
Quote:
 Originally Posted by EmperorFool The problem with your code is that you're creating a new map and asking it for its size, which probably defaults to STANDARD. What you want to do instead is ask the game for the map that's being used and get the size from it. Code: `int iMapSize = GC.getMap().getWorldSize();`
Oh. Thanks dude!

So, lemme get this straight:

GC references CvGlobals.h, right? so within the getmap() function of class CvGlobals, there's a getWorldSize()?

Edit: Weird, Codeblocks still can't compile....rrgh.
__________________
It'll all work out.

Last edited by Gooblah; Apr 26, 2009 at 05:28 PM.

Apr 26, 2009, 05:35 PM   #8
EmperorFool
Deity

Join Date: Mar 2007
Location: Mountain View, California
Posts: 9,625
Quote:
 Originally Posted by Gooblah GC references CvGlobals.h, right?
Essentially, yes. Technically, GC is a preprocessor macro defined in CvGlobals.h that calls a global function that returns the single CvGlobals object for the system.

Code:
`GC.getMap()`
is turned into

Code:
`CvGlobals::getInstance().getMap()`
by the C++ preprocessor using simple string replacement.

Quote:
 Originally Posted by Gooblah Within the getmap() function of class CvGlobals, there's a getWorldSize()?
Not exactly. CvGlobals::getMap() returns the CvMap that the game is using. CvMap::getWorldSize() returns the size of that map.

I would recommend reading a brief introduction to Object Oriented Programming or OOP. This will explain the difference between the function CvMap::getMap() and calling this function on an instance of CvMap as happens in the code above.
__________________
Monkeys killing monkeys killing monkeys over pieces of the ground.
Silly monkeys, give them thumbs they make a club and beat their brother down.

BUG Mod - BTS Unaltered Gameplay
[ Forum | Download | FAQ | Known Issues | Troubleshooting | Modding Tutorial ]

BAT 3.0.1 QuickFix™ released Oct 24th

 Apr 28, 2009, 06:14 PM #9 Gooblah Heh...     Join Date: Jun 2007 Posts: 4,282 Yeah, I'm taking a course in C++ this semester, really useful. Anywho, started working on my next 'project', for Kevinman's World History Mod. Quick conversion of CvTeamAI.cpp to make voluntary vassalage an option only if the vassal's power is 55% or less of the prospective master's power. Pretty easy, I guess, but since I'm a bit of a noob, I wanted to get some advice.... So, found the necessary function. Edited it to add a quick if statement comparing iTheirPower and iOurPower: Code: `if ( ((55 * iOurPower)/100) <= iTheirPower)` then added (after all the for loop jazz) an else statement that returned DENIAL_ATTITUDE: Code: ```else { return DENIAL_ATTITUDE; }``` Pretty straightforward. My problem is that I'm not sure if DENIAL_ATTITUDE is correct...I assumed so, since that's what's used in map trading when it refers to a rejection from another AI who's not their worst enemy. I think it looks right, and I'll play around with it... Edit: nvm, realized I hadn't defined iOurPower/iTheirPower. Done. __________________ It'll all work out. Last edited by Gooblah; Apr 28, 2009 at 06:24 PM.
 Apr 28, 2009, 07:05 PM #10 EmperorFool Deity     Join Date: Mar 2007 Location: Mountain View, California Posts: 9,625 Two suggestions for ya: First, on game logic, how about using DENIAL_POWER_US for "We're doing fine on our own." DENIAL_ATTITUDE is for when they don't like you enough; you don't need to be their worst enemy for this one, by the way. Second, on coding style, I would reverse your if test and move the "return" up to it: Code: ```if (55 * iOurPower /100 > iTheirPower) { return DENIAL_POWER_US; }``` I think this is better because the result of not being powerful enough (returning a denial) is right next to the test that causes it. This is sometimes called "early return" in that you bail out of the function as soon as you determine that's what you want to do. Some people don't like having multiple exits from a function, and that can be confusing if there are multiple places in a long function. However, I prefer to have effects near their causes. This way you don't have to read through the entire function to find out what happens in the "else" clause, nor do you see the else clause and have to scroll up to see what the if-test is. A minor advantage is that it removes one level of indentation for everything that follows. While this is fairly trivial, as the function grows and gets more complicated, each level of nesting requires keeping a larger mental context which just makes it more difficult to understand at a glance what the function does. Finally, note that I removed all but the outermost parentheses. This really is trivial, but if you memorize the few rules of operator precedence you will save yourself a lot of () typing and matching in the long run. In this case, * and / have the same precedence, so they are evaluated left-to-right, and the comparison operators have lower precedence, so > is evaluated last. While the presence of () has no bearing on the compiler in this case, it forces me to match them to know what the expression does. Leaving them out allows me to read it more quickly by depending on the rules of operator precedence. __________________ Monkeys killing monkeys killing monkeys over pieces of the ground. Silly monkeys, give them thumbs they make a club and beat their brother down. BUG Mod - BTS Unaltered Gameplay [ Forum | Download | FAQ | Known Issues | Troubleshooting | Modding Tutorial ] BAT 3.0.1 QuickFix™ released Oct 24th
Apr 29, 2009, 02:02 PM   #11
Gooblah
Heh...

Join Date: Jun 2007
Posts: 4,282
Quote:
 Originally Posted by EmperorFool Two suggestions for ya: First, on game logic, how about using DENIAL_POWER_US for "We're doing fine on our own." DENIAL_ATTITUDE is for when they don't like you enough; you don't need to be their worst enemy for this one, by the way. Second, on coding style, I would reverse your if test and move the "return" up to it: Code: ```if (55 * iOurPower /100 > iTheirPower) { return DENIAL_POWER_US; }``` I think this is better because the result of not being powerful enough (returning a denial) is right next to the test that causes it. This is sometimes called "early return" in that you bail out of the function as soon as you determine that's what you want to do. Some people don't like having multiple exits from a function, and that can be confusing if there are multiple places in a long function.
Oh yeahhhh.....the program checks through each code block one at a time right? So if your object meets condition 1, then it'll go for that, even if it could have met condition 2.

Quote:
 However, I prefer to have effects near their causes. This way you don't have to read through the entire function to find out what happens in the "else" clause, nor do you see the else clause and have to scroll up to see what the if-test is.
So, program checks the 'if' statement. if it doesn't meet the condition, it ignores it and heads to the next line of code - in this case a for loop.

Quote:
 Finally, note that I removed all but the outermost parentheses. This really is trivial, but if you memorize the few rules of operator precedence you will save yourself a lot of () typing and matching in the long run. In this case, * and / have the same precedence, so they are evaluated left-to-right, and the comparison operators have lower precedence, so > is evaluated last. While the presence of () has no bearing on the compiler in this case, it forces me to match them to know what the expression does. Leaving them out allows me to read it more quickly by depending on the rules of operator precedence.
This I know, but IMO it's easier. Well, thanks EmperorFool.
__________________
It'll all work out.

 Apr 29, 2009, 02:29 PM #12 EmperorFool Deity     Join Date: Mar 2007 Location: Mountain View, California Posts: 9,625 Given that the code inside the if test exits the function with "return", there's no need to put the rest of the code following it inside an "else" block. __________________ Monkeys killing monkeys killing monkeys over pieces of the ground. Silly monkeys, give them thumbs they make a club and beat their brother down. BUG Mod - BTS Unaltered Gameplay [ Forum | Download | FAQ | Known Issues | Troubleshooting | Modding Tutorial ] BAT 3.0.1 QuickFix™ released Oct 24th

 Bookmarks

 Civilization Fanatics' Forums > Capitulation Mechanics