I want to help this mod

Nope... never had any indication that there was any time delay at all with this pinch method. Nothing ever mentioned it and it would be so insignificant on profiling runs that it doesn't become obvious. I'm not saying you're wrong, just that one calculation of anything isn't going to make for any kind of delay whatsoever - it's when you get thousands or millions or more calculations in a round that we tend to see delays. I don't think this is called often. That said, no reason not to make it cheaper in processing. So it's helpful to know there's a difference. As for the rest of this statement, given that it should be impossible to get less than 50, and the std::max command is slow, might as well just return iModifier.
Did an edit while you wrote your post, and I know it isn't a big thing in the code in question here, it was more meant as a general advice that makes most sense if used inside a loop that does its thing thousands of times in a row.
 
Did an edit while you wrote your post, and I know it isn't a big thing in the code in question here, it was more meant as a general advice that makes most sense if used inside a loop that does its thing thousands of times in a row.
Yeah, exactly... very good to know though.

Also interesting about the compiler. Makes sense, I mean most of the code in C++ is just an easier way for us to read it and when compiled it is converted to the simplest possible processing flow that speaks directly to the processor that represents what you've programmed. This is why C++ is so much faster than python - python must be converted to processing language during the running of the code, so it's like you're compiling on demand during the program run. That's what I came to understand anyhow.
 
Yeah, exactly... very good to know though.

Also interesting about the compiler. Makes sense, I mean most of the code in C++ is just an easier way for us to read it and when compiled it is converted to the simplest possible processing flow that speaks directly to the processor that represents what you've programmed. This is why C++ is so much faster than python - python must be converted to processing language during the running of the code, so it's like you're compiling on demand during the program run. That's what I came to understand anyhow.
Python is actually interpreted by c (or was it c++) code, so there is no compiling actually happening at runtime, but there is a c code that reads python lines and interprets them and then call different generic c code functions to do what is written in the python code. That is pretty much why python is in some ways considered a pseudo programming language, as the language itself is often just another way to tell a different language what the job is.

It's in reality a bit more complicated than that, but that is the simple understanding of it.
 
Last edited:
MAX_PLAYERS should be changed to MAX_PC_PLAYERS, as the era of the NPC teams are completly inconsequential
I bet that change would be good in 100 different places. Anywhere there is "if (!NPC)" inside a player loop should be a good place to check.
You could also move the unused NPCs to the end, after the bard/neand/animal player #s and lower MAX_CIV_PLAYERS to exclude the unused ones.

I did a bit more digging into the civilization units/building.
Each civilization type (not player - so it takes memory if civ is used or not) has 1 array of unit classes and 1 of building classes and there is a building/unit type set for each class . If there is nothing in the CivilizationInfo XML for a class, then the default found in UnitClassInfo is used.

I'll start on somthing to remember eras.
 
You could also move the unused NPCs to the end, after the bard/neand/animal player #s and lower MAX_CIV_PLAYERS to exclude the unused ones.
Be careful with this sort of thinking. There are some hardcoded tripwires on this kind of thing somewhere and I'm pretty sure some are in the EXE. I had much trouble with this when adding more NPCs. Pretty sure you cause a problem when you don't use Barbs as the last player possible. And I know there's a lot of places in the code that call for it like this but I don't think all of it is within the boundaries of what we see.
 
Here's a piece of CvTeam::updateTechShare that I find odd.
Code:
    iBestShare = MAX_INT;

    for (iI = 0; iI < MAX_TEAMS; iI++)
    {
        if (isTechShare(iI))
        {
            iBestShare = std::min(iBestShare, (iI + 1));
        }
    }

    if (iBestShare != MAX_INT)
and another similar bit
Code:
// K-Mod
int CvTeam::getTypicalUnitValue(UnitAITypes eUnitAI) const
{
    int iMax = 0;
    for (int iI = 0; iI < MAX_PLAYERS; ++iI)
    {
        if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
        {
            iMax = std::max(iMax, GET_PLAYER((PlayerTypes)iI).getTypicalUnitValue(eUnitAI));
        }
    }
    return iMax;
}
 
Here's a piece of CvTeam::updateTechShare that I find odd.
Code:
    iBestShare = MAX_INT;

    for (iI = 0; iI < MAX_TEAMS; iI++)
    {
        if (isTechShare(iI))
        {
            iBestShare = std::min(iBestShare, (iI + 1));
        }
    }

    if (iBestShare != MAX_INT)
and another similar bit
Code:
// K-Mod
int CvTeam::getTypicalUnitValue(UnitAITypes eUnitAI) const
{
    int iMax = 0;
    for (int iI = 0; iI < MAX_PLAYERS; ++iI)
    {
        if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
        {
            iMax = std::max(iMax, GET_PLAYER((PlayerTypes)iI).getTypicalUnitValue(eUnitAI));
        }
    }
    return iMax;
}
Not sure where they are from nor what they are for. Much of the K-Mod stuff was imported by Alberts2 and I have found some of it wasn't quite as compatible with C2C as intended in some few cases. No faulting anyone here. It was usually a good idea. I'm not sure what these are for. Perhaps it would help to explain why you find them odd.
 
The strange thing with the first one is that this:
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
iBestShare = MAX_INT;

for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (isTechShare(iI))
{
iBestShare = std::min(iBestShare, (iI + 1));​
}​
}
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
is the same as this:
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
iBestShare = MAX_INT;

for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (isTechShare(iI))
{
iBestShare = iI + 1;
break;​
}​
}
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
I don't understand the purpose of the code, but something is probably amiss with it when it can be simplified like that.

I don't see anything strange with the second one.
 
Last edited:
the forum sucks for reading code.
maybe im reading this stuff wrong but for the first

iBestShare = MAX_INT;
iBestShare = std::min(iBestShare, (iI + 1));
if (iBestShare != MAX_INT)

I was lookin at the middle line. its given a minimum of MAX_INT right? For some reason this is startin to confuse me, but iBestshare will always be force to MAX_INT?
no big deal if im right anyways, just fails the if.
 
The strange thing with the first one is that this:
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
iBestShare = MAX_INT;

for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (isTechShare(iI))
{
iBestShare = std::min(iBestShare, (iI + 1));​
}​
}
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
is the same as this:
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
iBestShare = MAX_INT;

for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (isTechShare(iI))
{
iBestShare = iI + 1;
break;​
}​
}
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
I don't understand the purpose of the code, but something is probably amiss with it when it can be simplified like that.

I don't see anything strange with the second one.
It's not the same. If iI somehow runs away, such as in a case where the for loop is bugged, then iBestShare would end up equal to MAX_INT. Admittedly there's really no honest logical reason for such a hedge - if you have the problem, you'll have an issue anyhow when il exceeds MAX_INT. There really is admittedly no good reason for the pinch here. Even if C++ processes the pinch better than you thought, it's still added processing that's entirely unnecessary.

If we're looking at the second statement for a mathematical quirk, it seems to check out to me. It gets the highest typical unit value from the typical unit values of all players on the team.
 
the forum sucks for reading code.
maybe im reading this stuff wrong but for the first

iBestShare = MAX_INT;
iBestShare = std::min(iBestShare, (iI + 1));
if (iBestShare != MAX_INT)

I was lookin at the middle line. its given a minimum of MAX_INT right? For some reason this is startin to confuse me, but iBestshare will always be force to MAX_INT?
no big deal if im right anyways, just fails the if.
No... min means get the lowest of both numbers. max means get the highest of these two numbers. Took me a bit to wrap my head around it but I'm pretty confident in my understanding of it after a lot of practice with it now.

Thus, if iI+1 == something lower than the Maximum Integer value, then iBestShare will become that amount. If in the next pass iI+1 is lower (which it won't be) than the previous iI+1, then it will take on that value. It's always going to return the first true result it finds so why it doesn't just break at that point, I don't know. Another oversight. Unless isTechShare(iI) is capable of changing the value of iI after it's processed and returning a different amount. That may be the case if it's really clever here. I've never seen that sort of trick in our code employed before but whoever did this was apparently not thinking everything through quite right so I doubt such a clever approach to a value loop would be in play here.
 
ah, I thought it ment if the second number goes above the first the make the second number equal to the first. I guess I was way off on that 1
 
and for that current ear thing ull nee something on init() for the new member and all there is for the EraTypes enums is NO_ERA. I guess there's the function getStartEra() or I could use a 0, first era is 0 right? or getInfoTypeForString() but id rather 1 more enum like START_ERA or INITIAL_ERA.
 
and for that current ear thing ull nee something on init() for the new member and all there is for the EraTypes enums is NO_ERA. I guess there's the function getStartEra() or I could use a 0, first era is 0 right? or getInfoTypeForString() but id rather 1 more enum like START_ERA or INITIAL_ERA.
If you're looking for the current era number: (int)GC.getGame().getCurrentEra()

Try to avoid getInfoTypeForString() wherever possible - it's very very slow and there's usually a better way unless you're basically caching the result of it and then calling it multiple times later.

get StartEra() may not always be 0 if you didn't start the game in the Prehistoric. But you CAN use 0 to mean the gamestarting era, sure.

I'm not sure what all this is referring to when you say, for THAT current era thing... but maybe this commentary helps?
 
I cant find thread but toffer said it might be good idea to save value of current era instead of doin the loop through players. So GC.getGame().getCurrentEra() will return m_eCurrentEra. Ill need to initialize m_eCurrentEra which ill probably do on reset(). was just wondering what to use to give it it's first value. Ill use 0 for now
 
I cant find thread but toffer said it might be good idea to save value of current era instead of doin the loop through players. So GC.getGame().getCurrentEra() will return m_eCurrentEra. Ill need to initialize m_eCurrentEra which ill probably do on reset(). was just wondering what to use to give it it's first value. Ill use 0 for now
Oh right I see.
 
Code:
 int iEra = GET_PLAYER(getOwnerINLINE()).getCurrentEra();

(iEra - GC.getGame().getStartEra() / 2)
If iEra happens to be 0 can this cause a divide by 0?
 
Code:
 int iEra = GET_PLAYER(getOwnerINLINE()).getCurrentEra();

(iEra - GC.getGame().getStartEra() / 2)
If iEra happens to be 0 can this cause a divide by 0?
No. You are always dividing by 2. You can divide a 0, you just can't divide BY 0.
 
[...] I call this a packed array because it uses the least space necessary. Or "sized" array because I can get its size from its pointer. [...]
The internal arrays that different info-classes use, have too many zeroes (or any null values like -1) that occupy memory [...]
If we optimize these internal arrays, we save a lot of memory in everybody's game to develop fuller features. (These info are always loaded, regardless of your game progress.) [...]

I need some time to develop all possible memory savings based on this. Once I finish it, we can measure how much this approach benefits us. It's 434.5MB-> 435.5MB (1 test) after I converted 2 of those arrays, but we'll see.
(Please ignore my last suggestion to reformat the XMLs -- it's too radical and provides no real benefit.)

EDIT: It's better to use vectors instead.
 
Last edited:
is there anyways we could set the Animals/Sea modifier spawn for each era
I think you said something like this a couple months ago. I've had this new global define laying around for a while. It allows someone to set a starting era for the water animal spawns.
I've got another that does the spawning part of Raxo's No Limits mod.

I havn't tested, also still needs the Xml.
 

Attachments

Back
Top Bottom