Multiple Production Mod

Making sure I have the correct placement there, as I'm likely to use it (already sent you a PM to see if you'd made any AI additions for this. :lol:). Put your addition in bold.
saw your PM, preferred to reply here as others might be interested too. This seems to be one of the more popular modcomps.
 
Denev, just wanted to say I used this as my inspiration for a Multiple Research game option, which does essentially the same thing as this, but with research.

O wow I would love that !!
Can it be possible to add the code here ? I'd definitively add it in my MOD !
 
O wow I would love that !!
Can it be possible to add the code here ? I'd definitively add it in my MOD !

Yeah, I can post. It's fairly simple compared to MPM. Here's the code:

in CvTeam:
Spoiler :

Code:
void CvTeam::setResearchProgress(TechTypes eIndex, int iNewValue, PlayerTypes ePlayer)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < GC.getNumTechInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
    FAssertMsg(ePlayer >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(ePlayer < MAX_PLAYERS, "ePlayer is expected to be within maximum bounds (invalid Index)");

    if (getResearchProgress(eIndex) != iNewValue)
    {
        m_paiResearchProgress[eIndex] = iNewValue;
        FAssert(getResearchProgress(eIndex) >= 0);

        if (getID() == GC.getGameINLINE().getActiveTeam())
        {
            gDLL->getInterfaceIFace()->setDirty(GameData_DIRTY_BIT, true);
            gDLL->getInterfaceIFace()->setDirty(Score_DIRTY_BIT, true);
        }

        if (getResearchProgress(eIndex) >= getResearchCost(eIndex))
        {
            int iOverflow = (100 * (getResearchProgress(eIndex) - getResearchCost(eIndex))) / std::max(1, GET_PLAYER(ePlayer).calculateResearchModifier(eIndex));
/************************************************************************************************/
/* Afforess                      Start         12/29/09                                               */
/*                                                                                              */
/*      Multiple Research                                                                       */
/************************************************************************************************/
            setHasTech(eIndex, true, ePlayer, true, true);
            iOverflow = GET_PLAYER(ePlayer).doMultipleResearch(iOverflow);
            GET_PLAYER(ePlayer).changeOverflowResearch(iOverflow);
/************************************************************************************************/
/* Afforess                         END                                                            */
/************************************************************************************************/
            if (!GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS) && !GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_BROKERING))
            {
                setNoTradeTech(eIndex, true);
            }
        }
    }
}

Then, in CvPlayer, add this new function to the very bottom of the file:
Spoiler :

Code:
int CvPlayer::doMultipleResearch(int iOverflow)
{
	TechTypes eCurrentTech;
	eCurrentTech = getCurrentResearch();
	
	FAssertMsg(eCurrentTech < GC.getNumTechInfos(), "eCurrentTech is expected to be within maximum bounds (invalid Index)");

	if (!GC.getGameINLINE().isOption(GAMEOPTION_MULTIPLE_RESEARCH))
	{
		return iOverflow;
	}
	
	while (eCurrentTech != NO_TECH && ((100 * (GET_TEAM(getTeam()).getResearchCost(eCurrentTech) - GET_TEAM(getTeam()).getResearchProgress(eCurrentTech))) / std::max(1, calculateResearchModifier(eCurrentTech)) <= iOverflow))
	{//The Future Tech can cause strange infinite loops
		if (GC.getTechInfo(eCurrentTech).isRepeat())
			break;
		iOverflow -= (100 * (GET_TEAM(getTeam()).getResearchCost(eCurrentTech) - GET_TEAM(getTeam()).getResearchProgress(eCurrentTech))) / std::max(1, calculateResearchModifier(eCurrentTech));
		GET_TEAM(getTeam()).setHasTech(eCurrentTech, true, getID(), true, true);
		if (!GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS) && !GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_BROKERING))
		{
			GET_TEAM(getTeam()).setNoTradeTech(eCurrentTech, true);
		}
		eCurrentTech = getCurrentResearch();
	}
	
	return std::max(0, iOverflow);
}

in CvPlayer.h add this next to one of the existing functions (like getGrowthThreshold)

Spoiler :
Code:
int doMultipleResearch(int iOverflow);

then in CvEnums, add this to the bottom of the game options
Spoiler :
Code:
GAMEOPTION_MULTIPLE_RESEARCH,

and in CyEnumsInterface.cpp, put this at the bottom of the game options as well:
Spoiler :
Code:
.value("GAMEOPTION_MULTIPLE_RESEARCH", GAMEOPTION_MULTIPLE_RESEARCH)

Nearly done, now for the XML, add this to the end of your Civ4GameOptionInfos.xml
Spoiler :
Code:
<GameOptionInfo>
            <Type>GAMEOPTION_MULTIPLE_RESEARCH</Type>
            <Description>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH</Description>
            <Help>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH_HELP</Help>
            <bDefault>1</bDefault>
            <bVisible>1</bVisible>
        </GameOptionInfo>

And my GameText entries are:
Spoiler :

Code:
<TEXT>
        <Tag>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH</Tag>
        <English>Multiple Research</English>
        <French>Multiple Research</French>
        <German>Mehrfachforschung</German>
        <Italian>Multiple Research</Italian>
        <Spanish>Multiple Research</Spanish>
    </TEXT>
    <TEXT>
        <Tag>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH_HELP</Tag>
        <English>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</English>
        <French>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</French>
        <German>Wenn ein Spieler genügend Forschungspunkte erreicht hat, um mehr als eine Technologie zu erforschen und mindestens eine weitere vorausgewählt ist, so können mehrere Technologien pro Runde erforscht werden.</German>
        <Italian>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</Italian>
        <Spanish>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</Spanish>
    </TEXT>

Pretty easy, at least compared to the MPM as far as merging goes. Once you recompile, test it out by giving yourself like 100 GS's and settling them in your capital. Then, pick a tech in the future. Watch as you get 10-15 of them in 1 turn. :p
 
Great ! (and thanks for the quick response !)

I'm familiar enough to think it will be done relatively easily ;)
But like many things in life, great & smart things are not always the most complicated ;) :goodjob:
 
Yeah, I can post. It's fairly simple compared to MPM. Here's the code:

in CvTeam:
Spoiler :

Code:
void CvTeam::setResearchProgress(TechTypes eIndex, int iNewValue, PlayerTypes ePlayer)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < GC.getNumTechInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
    FAssertMsg(ePlayer >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(ePlayer < MAX_PLAYERS, "ePlayer is expected to be within maximum bounds (invalid Index)");

    if (getResearchProgress(eIndex) != iNewValue)
    {
        m_paiResearchProgress[eIndex] = iNewValue;
        FAssert(getResearchProgress(eIndex) >= 0);

        if (getID() == GC.getGameINLINE().getActiveTeam())
        {
            gDLL->getInterfaceIFace()->setDirty(GameData_DIRTY_BIT, true);
            gDLL->getInterfaceIFace()->setDirty(Score_DIRTY_BIT, true);
        }

        if (getResearchProgress(eIndex) >= getResearchCost(eIndex))
        {
            int iOverflow = (100 * (getResearchProgress(eIndex) - getResearchCost(eIndex))) / std::max(1, GET_PLAYER(ePlayer).calculateResearchModifier(eIndex));
/************************************************************************************************/
/* Afforess                      Start         12/29/09                                               */
/*                                                                                              */
/*      Multiple Research                                                                       */
/************************************************************************************************/
            setHasTech(eIndex, true, ePlayer, true, true);
            iOverflow = GET_PLAYER(ePlayer).doMultipleResearch(iOverflow);
            GET_PLAYER(ePlayer).changeOverflowResearch(iOverflow);
/************************************************************************************************/
/* Afforess                         END                                                            */
/************************************************************************************************/
            if (!GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS) && !GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_BROKERING))
            {
                setNoTradeTech(eIndex, true);
            }
        }
    }
}

Then, in CvPlayer, add this new function to the very bottom of the file:
Spoiler :

Code:
int CvPlayer::doMultipleResearch(int iOverflow)
{
    TechTypes eCurrentTech;
    eCurrentTech = getCurrentResearch();
    
    FAssertMsg(eCurrentTech < GC.getNumTechInfos(), "eCurrentTech is expected to be within maximum bounds (invalid Index)");
    if (!(GC.getGameINLINE().isOption(GAMEOPTION_MULTIPLE_RESEARCH)))
    {
        return iOverflow;
    }
    
    while (eCurrentTech != NO_TECH && (GC.getTechInfo(eCurrentTech).getResearchCost() <= iOverflow))
    {
        iOverflow -= GC.getTechInfo(eCurrentTech).getResearchCost();
        GET_TEAM(getTeam()).setHasTech(eCurrentTech, true, getID(), true, true);
        if (!GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS) && !GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_BROKERING))
        {
            GET_TEAM(getTeam()).setNoTradeTech(eCurrentTech, true);
        }
        eCurrentTech = getCurrentResearch();
        
    }
    
    return std::max(0, iOverflow);
}

in CvPlayer.h add this next to one of the existing functions (like getGrowthThreshold)

Spoiler :
Code:
int doMultipleResearch(int iOverflow);

then in CvEnums, add this to the bottom of the game options
Spoiler :
Code:
GAMEOPTION_MULTIPLE_RESEARCH,

and in CyEnumsInterface.cpp, put this at the bottom of the game options as well:
Spoiler :
Code:
.value("GAMEOPTION_MULTIPLE_RESEARCH", GAMEOPTION_MULTIPLE_RESEARCH)

Nearly done, now for the XML, add this to the end of your Civ4GameOptionInfos.xml
Spoiler :
Code:
<GameOptionInfo>
            <Type>GAMEOPTION_MULTIPLE_RESEARCH</Type>
            <Description>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH</Description>
            <Help>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH_HELP</Help>
            <bDefault>1</bDefault>
            <bVisible>1</bVisible>
        </GameOptionInfo>

And my GameText entries are:
Spoiler :

Code:
<TEXT>
        <Tag>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH</Tag>
        <English>Multiple Research</English>
        <French>Multiple Research</French>
        <German>Mehrfachforschung</German>
        <Italian>Multiple Research</Italian>
        <Spanish>Multiple Research</Spanish>
    </TEXT>
    <TEXT>
        <Tag>TXT_KEY_GAMEOPTION_MULTIPLE_RESEARCH_HELP</Tag>
        <English>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</English>
        <French>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</French>
        <German>Wenn ein Spieler genügend Forschungspunkte erreicht hat, um mehr als eine Technologie zu erforschen und mindestens eine weitere vorausgewählt ist, so können mehrere Technologien pro Runde erforscht werden.</German>
        <Italian>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</Italian>
        <Spanish>When a player has enough beakers to research more than one technology, and more than one technology is queued, they can research multiple technologies per turn.</Spanish>
    </TEXT>

Pretty easy, at least compared to the MPM as far as merging goes. Once you recompile, test it out by giving yourself like 100 GS's and settling them in your capital. Then, pick a tech in the future. Watch as you get 10-15 of them in 1 turn. :p

Mind if I merge this? Weak enough that it could be used as a general mechanic, rather than a trait as I did with Denev's mod (Have a civ that doesn't need food, has no happy cap, and grows by taking slaves.... They won't ever get that mechanic. :lol:)
 
Mind if I merge this? Weak enough that it could be used as a general mechanic, rather than a trait as I did with Denev's mod (Have a civ that doesn't need food, has no happy cap, and grows by taking slaves.... They won't ever get that mechanic. :lol:)

Yeah, anyone can use it. Just throw my name in your credits, please. :)
 
Does the AI understand this modcomp?

Thank you for reviewing my code! :D

I believe the AI understands.
the popOrder statement which you said assigns true as third argument.
Then the following code will run at the end of popOrder function.
Spoiler :
Code:
	if (bChoose)
	{
		if (getOrderQueueLength() == 0)
		{
			[COLOR="Blue"]if (!isHuman() || isProductionAutomated())
			{
				AI_chooseProduction();
			}[/COLOR]
			else
			{
I have made sure running it with city automate mode. Please tell me your opinion.



Denev, just wanted to say I used this as my inspiration for a Multiple Research game option, which does essentially the same thing as this, but with research.

Fantastic! I have not reached to your idea. I feel honored to have inspired you. Great! :goodjob:



Added you to the credits, and added Denev as well (Usually don't until I actually release, but might as well do it now. ;)).

It's my best pleasure that other modder adopt my modcomp!
 
Any chance the code could be modified to launch a 'ChooseProduction' popup if the player doesn't have anything queued up? I've been trying to get that to work but haven't been able to.

I tried, but popup window seems to be shown only when player is active.
When city production process, player's turn has been finished already. I can't find way to show it before next player's turn. :cry:
 
I tried, but popup window seems to be shown only when player is active.
When city production process, player's turn has been finished already. I can't find way to show it before next player's turn. :cry:

It's not that big of a deal. If the player doesn't select another item to produce, then they get gold, like normal. Fine by me.
 
I tried, but popup window seems to be shown only when player is active.
When city production process, player's turn has been finished already. I can't find way to show it before next player's turn. :cry:

Yeah, I tried 4 or 5 ways that should have worked, but got nothing. I was honestly thinking I'd end up with a WoC endless loop, but instead it did absolutely nothing. :lol:

It's not that big of a deal. If the player doesn't select another item to produce, then they get gold, like normal. Fine by me.

Yeah, it was actually a request from another modder who doesn't like to queue. :lol:

Really, so long as the AI uses it (and it does), it's fine. The player can adapt.
 
To Anyone who used my Multiple Research Code, I caught a bug in the calculations, change the highlighted line:

Code:
int CvPlayer::doMultipleResearch(int iOverflow)
{
    TechTypes eCurrentTech;
    eCurrentTech = getCurrentResearch();
    
    FAssertMsg(eCurrentTech < GC.getNumTechInfos(), "eCurrentTech is expected to be within maximum bounds (invalid Index)");
    if (!(GC.getGameINLINE().isOption(GAMEOPTION_MULTIPLE_RESEARCH)))
    {
        return iOverflow;
    }
    
    while (eCurrentTech != NO_TECH && (GC.getTechInfo(eCurrentTech).getResearchCost() <= iOverflow))
    {
      [COLOR="Red"] iOverflow -= (100 * (GET_TEAM(getTeam()).getResearchProgress(eCurrentTech) - GET_TEAM(getTeam()).getResearchCost(eCurrentTech))) / std::max(1, calculateResearchModifier(eCurrentTech));[/COLOR]
        GET_TEAM(getTeam()).setHasTech(eCurrentTech, true, getID(), true, true);
        if (!GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS) && !GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_BROKERING))
        {
            GET_TEAM(getTeam()).setNoTradeTech(eCurrentTech, true);
        }
        eCurrentTech = getCurrentResearch();
        
    }
    
    return std::max(0, iOverflow);
}

I corrected the code above too, so anyone who uses this code after this post date doesn't need to worry, it is correct.
 
Just to make sure all affected parties are notified, I only made the Multiple Research bug worse with my last fix. Before, I failed to scale tech costs with the gamespeed/era, etc... But, now, it works in reverse, so each new tech would GIVE the player the research it would have cost, instead of taking it, allowing you to research the entire tech tree in one turn. :lol:

The bug is only in CvPlayer, the above code in my original post has been corrected, just replace the doMultipleResearch() function with the new one.
 
Just to make sure all affected parties are notified, I only made the Multiple Research bug worse with my last fix. Before, I failed to scale tech costs with the gamespeed/era, etc... But, now, it works in reverse, so each new tech would GIVE the player the research it would have cost, instead of taking it, allowing you to research the entire tech tree in one turn. :lol:

The bug is only in CvPlayer, the above code in my original post has been corrected, just replace the doMultipleResearch() function with the new one.

What - could you explain that again.

Should I just download the files from the first post and use that or where do I find the last version?

\Skodkim
 
Top Bottom