Unofficial Patch for 3.19

I wonder if he realizes that he loses almost all of his XP with the upgrade (the amount for the new level stays the same, though, so upgrading a highly promoted unit basically means that it won't ever get promoted again).

He's talking about a unit with a great general attached. Those don't lose experience on upgrading.

EDIT: I shouldn't be posting in multiple threads at once. I'm too slow everywhere.
 
I have a request...

I'd like to see units be able to be traded for gold in the diplomacy screen. Perhaps the value of the unit could be determined by the cost to upgrade that unit? You would of course have to have the required PreReqTechs for the unit you wish to purchase.

Example: Say I want to buy a Longbowman. It would cost me the amount of gold it would take to upgrade a standard Archer to a Longbowman in order to purchase that Longbowman.


Just a rough idea....
 
I've played this game so much, I'm surprised I haven't seen this before, and I really like making attacking Warlords as well. Are you sure there is a unit level cap? Do you have a save with a unit hitting this cap? What level is the cap at?

Yes, I am sure there is a cap. At around 4xx (iirc) instead of the experience indicator saying how many points you need to get the next promotions it stays the same - i.e instead of saying 11 / 17 it would say 11 / 10 so you can never get another promo. I'm not surprised you ain't reached the cap as most people probably don't DOW on everyone and have mounted units with GG, Blitz, morale, & mobility (Justinian is my stress relief).

Unfortunately I don't have a save at moment, but next time I play as Byzantium I'll try to remember to post one.
 
Version 1.2 has been posted here at CFC!

Version 1.20 changes:
Spoiler :

- CvUnit::canSpread - Moved Python cannot spread callback to end of function where it belongs, will speed up those mods which use this callback a little
- CvPlayerAI::AI_missionaryValue - Fixed copy and past bug causing overvaluation of missionaries for AIs going for cultural victory early in the game.
- CvGameTextMgr (many places) - Fixed issues where unhappiness and unhealthiness from civics or buildings would incorrectly show up as -(unhappy face) instead of +(unhappy face) in several circumstances. (Thanks EmporerFool, Grave, Afforess)
- CvGameTextMgr - Game will now properly display info for buildings which generate unhappiness in an area or globally, or produce state religion unhappiness (should these ever come up in mods)
- CvPlayerAI::AI_doTurnPost and CvPlayerAI::AI_doTurnUnitsPost - Added in accidentally skipped fix for AI_doSplit issues as suggested by alexman
- CvTeamAI::AI_calculateAreaAIType - Fixed incorrect index usage (thanks cephalo)
- CvCity::popOrder - Fixed issue with improper use of iExtra causing national wonders to max out early in some mods (thanks davidlallen)
- CvTeam::addTeam - Fixed bug where, if civs A and B join in a permanent alliance, they get the max of A and B's espionage points against C but C just keeps its point against A and loses its points to B if that's higher
- CvUnit::canMoveInto - Removed strange behavior where setting a unit to be unable to enter a terrain type would be overridden by features (forrest, fallout) (thanks TC01)
- CvCityAI::AI_chooseProduction - Fixed bug reducing AI production of workers, and a similar issue for barb players producing too many
 
Version 1.2 has been posted here at CFC!

Stupid question ... I've just patched to 3.19 and installed Better AI 0.81. Do I need to get this unofficial patch or is everything I need already in the Better AI mod? Cheers!
 
Jdog5000, I've found the cause of a rare-ish CTD, and a possible fix for it. In CvPlayerAI.cpp, in the function "TechTypes CvPlayerAI::AI_bestTech(int iMaxPathLength, bool bIgnoreCost, bool bAsync, TechTypes eIgnoreTech, AdvisorTypes eIgnoreAdvisor) const" There is a section where in rare instances, the formula divides by 0.

The code in question is this section:
Code:
int iNewCapacity = kLoopUnit.getMoves() * kLoopUnit.getCargoSpace();
int iOldCapacity = GC.getUnitInfo(eExistingUnit).getMoves() * GC.getUnitInfo(eExistingUnit).getCargoSpace();
[B]iAssaultValue += (800 * (iNewCapacity - iOldCapacity)) / iOldCapacity;[/B]

In Vanilla BTS, the iOldCapacity is never 0, but in Rise of Mankind (and possibly other mods), there is a promotion that adds an extra cargo space to ships, even to ships without preexisting cargo space. If the AI gave this promotion to a ship without cargo space, the iOldCapacity would be 0, and the function would divide by 0. I fixed this by changing that segment of code into this:
Code:
int iNewCapacity = kLoopUnit.getMoves() * kLoopUnit.getCargoSpace();
int iOldCapacity = GC.getUnitInfo(eExistingUnit).getMoves() * GC.getUnitInfo(eExistingUnit).getCargoSpace();
[B]if (iOldCapacity <= 0)
{
	iAssaultValue += (600 * iNewCapacity);
}[/B]
[B]else[/B]
{
	iAssaultValue += (800 * (iNewCapacity - iOldCapacity)) / iOldCapacity;
}

That fixed the CTD and allow me to go to the next turn. I would appreciate it if this fix made it into the next UP.
 
In looking in the SDK for where exactly the cityAcquiredAndKept event is fired, I found another place where the active player is passed instead of the new owner of the city. That got me thinking: how exactly are modders using the ePlayer parameter passed to the event?

The cityAcquired event takes a player called eOldOwner. That's nice and descriptive. The AndKept event takes a player called iPlayer. Lovely!

CvPlayerAI::AI_conquerCity() was changed at the end to pass in getID() instead of the active player:

Code:
	if (!bRaze)
	{
// BUG - Unofficial Patch - start
		// EF: was passing getActivePlayer()
		CvEventReporter::getInstance().cityAcquiredAndKept([B]getID()[/B], pCity);
// BUG - Unofficial Patch - end
	}

I don't remember if this is in the UP or just BULL, but here's the other place I found it using the active player: when the popup asking if you want to keep or raze the city appears, sometimes there is the option to liberate it. In that case, CvButtonPopup handles firing the event (lame). Here's the fix:

Code:
		else if (pPopupReturn->getButtonClicked() == 2)
		{
			CvCity* pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
			if (NULL != pCity)
			{
// BUG - Unofficial Patch - start
				// EF: was passing getActivePlayer()
				CvEventReporter::getInstance().cityAcquiredAndKept([B](PlayerTypes)info.getData2()[/B], pCity);
// BUG - Unofficial Patch - end
			}

			CvMessageControl::getInstance().sendDoTask(info.getData1(), TASK_GIFT, info.getData2(), -1, false, false, false, false);
		}

I've checked all other calls to CvEventReporter::cityAcquiredAndKept(), and they seem to be passing the appropriate player.
 
When you hover over a player you see whom they are the worst enemy of. This fix hides those haters if you haven't met them.

Code:
void CvGameTextMgr::getOtherRelationsString(CvWStringBuffer& szString, PlayerTypes eThisPlayer, PlayerTypes eOtherPlayer)
{
	...
			if (kTeam.isHasMet(kOtherPlayer.getTeam()))
			{
				if (::atWar((TeamTypes) iTeam, kThisPlayer.getTeam()))
				{
					szString.append(NEWLINE);
					szString.append(gDLL->getText(L"TXT_KEY_AT_WAR_WITH", kTeam.getName().GetCString()));
				}

// BUG - Unofficial Patch - start
				// EF: don't show enemies that active player hasn't met
				if (!kTeam.isHuman() && kTeam.AI_getWorstEnemy() == kThisPlayer.getTeam() [B]&& kTeam.isHasMet(GC.getGameINLINE().getActiveTeam())[/B])
// BUG - Unofficial Patch - end
				{
					szString.append(NEWLINE);
					szString.append(gDLL->getText(L"TXT_KEY_WORST_ENEMY_OF", kTeam.getName().GetCString()));
				}
			}

I just wrote this but haven't tested it yet. I'll post again once I've had a chance to test.
 
I don't remember if this is in the UP or just BULL, but here's the other place I found it using the active player: when the popup asking if you want to keep or raze the city appears, sometimes there is the option to liberate it. In that case, CvButtonPopup handles firing the event (lame). Here's the fix:

Code:
		else if (pPopupReturn->getButtonClicked() == 2)
		{
			CvCity* pCity = GET_PLAYER(GC.getGameINLINE().getActivePlayer()).getCity(info.getData1());
			if (NULL != pCity)
			{
// BUG - Unofficial Patch - start
				// EF: was passing getActivePlayer()
				CvEventReporter::getInstance().cityAcquiredAndKept([B](PlayerTypes)info.getData2()[/B], pCity);
// BUG - Unofficial Patch - end
			}

			CvMessageControl::getInstance().sendDoTask(info.getData1(), TASK_GIFT, info.getData2(), -1, false, false, false, false);
		}

I've checked all other calls to CvEventReporter::cityAcquiredAndKept(), and they seem to be passing the appropriate player.

Hmmm ... I'm not sure about this one. Here's the current chain of events:

1) Human player captures a city
2) Event fires saying human acquired city
3) Human player selects to liberate city to player X
4) Event fires saying human acquired and kept city
5) Player X is given city in trade from human player
6) Event fires saying that Player X acquired city (not acquired and kept since they have no option to raze it)

That seems right to me.
 
Yeah, I'm looking into this further. There are six places where the cityAcquiredAndKept event is fired. See this post for the list. I'll verify that the events are fired again after the liberation. If so, what you say makes sense.
 
So the CityAcquired and CityAcquiredAndKept events are fired twice each during liberation-via-conquest. I retract my latest fix request.
 
On the latest UP code, in the SVN (The RevDCM SVN, but it might be in others too), you made a slight error. In CvGameTextMgr.cpp

this:

Code:
/*************************************************************************************************/
/** UNOFFICIAL_PATCH                       08/28/09                            jdog5000          */
/**                                                                                              */
/** Bugfix                                                                                       */
/*************************************************************************************************/
/* original bts code
		szHelpText.append(gDLL->getText("TXT_KEY_CIVIC_UNIT_HAPPINESS", GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit(), ((GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit() > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))));

*/
		// Use absolute value with unhappy face
		szHelpText.append(gDLL->getText("TXT_KEY_CIVIC_UNIT_HAPPINESS", abs(GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit()), ((GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit() > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))));
/*************************************************************************************************/
/** UNOFFICIAL_PATCH                        END                                                  */
/*************************************************************************************************/
should look like this:

Code:
	//	Happiness per military unit
	if (GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit() != 0)
	{
		szHelpText.append(NEWLINE);
/*************************************************************************************************/
/** UNOFFICIAL_PATCH                       08/28/09                            jdog5000          */
/**                                                                                              */
/** Bugfix                                                                                       */
/*************************************************************************************************/
/* original bts code
		szHelpText.append(gDLL->getText("TXT_KEY_CIVIC_UNIT_HAPPINESS", GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit(), ((GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit() > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))));

*/
		// Use absolute value with unhappy face

		szHelpText.append(gDLL->getText("TXT_KEY_CIVIC_UNIT_HAPPINESS", abs(GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit()), ((GC.getCivicInfo(eCivic).getHappyPerMilitaryUnit() > 0) ? gDLL->getSymbolID(HAPPY_CHAR) : gDLL->getSymbolID(UNHAPPY_CHAR))));

/*************************************************************************************************/
/** UNOFFICIAL_PATCH                        END                                                  */
/*************************************************************************************************/
	}
Otherwise, every civic on the civic screen shows 0 unhappiness for each military troop. It's a simple error. You accidentally clipped off the condition.
 
@jdog:

I see there's a small change in CvPlayer.cpp which isn't mentioned in the changelog:

UP1.1 (line 1045) reads:

PROFILE_FUNC();

while UP1.2 reads:

//PROFILE_FUNC();

What does this change do?
 
Top Bottom