Unofficial BTS 3.13 patch

Yes, it's there. I'm trying to decide which way it should be fixed, assuming it should. In the strictest technical sense, it's perfectly accurate this way - those buildings still cause unhealthiness, the recycling center just removes it. But it's still probably confusing.

Bh

But is it removing it? It seems to me like it no longer has any effect on unhealthiness.

Thanks again, Bhruic!
 
No, it's not removing it. It's not changing it at all. All it's doing is causing the unhealthiness to be displayed when you mouseover it, where before it wouldn't. It's purely a display issue.

Bh
 
It is removing it. And in the building list for the city screen, it won't show any unhealthiness. Only when you mouseover will it do so. Which technically is correct, as the building still does cause unhealthiness, it's just being removed by a separate building. But again, it's probably confusing, so I'll have to fix it in some fashion.

Bh
 
Stealth destroyers aren't privateers, so your opponent knowing your using them isn't an issue to worry about.
Assuming the game was changed so stealth destroyers would defend when part of a stack there's one potential bug I could see being created. Assume there is a stack of a transport and a stealth destroyer and the game as been altered so it would defend the transport. Now if I had a ship that couldn't see the destroyer and were to hold alt and mouse over the transport would it show battle statistics based on the battle against the transport, or the destroyer that would be the actual defender? Obviously it should be the transports statistics that are displayed, but since the game isn't originally designed to have "sneak defenders" I'm betting it would give away the presence of the stealth destroyer by giving its battle statistics even though the unit would still be invisible. That's just my assumption based on what I know about the game engine, which is nothing.
 
Bhruic,

* I agree with your proposed solution on the Colony tech trading/No Tech Brokering issue.

* Concerning the stealth destroyer issue, I agree that they should move to the forefront and defend when an enemy ship moves into that square.... As the regular destroyer upgrades to stealth destroyer, it more or less leaves the player unable to construct an anti-air naval unit with moderate strength that can do any good in defensive naval battles. (I'd feel differently if destroyers weren't obsoleted by stealth destroyers.)
 
On the issue of the stealth destroyer.

Yes, it's pretty weird that the third strongest warship in the game (after the missile cruiser and battleship) won't defend a fleet of transports against an attacker when the attacker can't see them, very weird. The attacker can't see them, but they can see the attacker so the stealth destroyer should be able to defend against the attacker.

The weirdest part is that if a stealth destroyer attacks a stack of units that can't detect it, then every unit can potentially defend against it. It makes the whole stealth thing a very negative trait when the unit is used in a stack. It means that you don't get offensive advantages and do lose the ability to defend against units that can't detect you.

I think the reason why this bug arose was because a lone stealth destroyer can't be attacked as long as it is undetected. But in a fleet they should operate differently. The stealth effect should be a positive thing, not a negative one.

By the way, the stealth effect from destroyers works technically in exactly the same way as the invisibility effect from submarines. Only units that can see the submarine/stealth destroyer can attack it and the submarine/stealth destroyer won't defend a stack of units if the attacker can't detect them. So whatever is decided for the stealth destroyer should also apply to the two types of submarines. Whenever a submarine is the strongest living unit in a stack defending transports, it should also rise to the occasion and try to defend the transports.

By the way, stealth destroyers still defend against air attacks while they haven't been detected yet. This is inconsistent with their inability to defend against ship attacks while they haven't been detected yet.

Back to the executive issue: Bhruic, do you see options to improve the AI's gold issues with executives without harming it too much in another way?
 
You are both incorrect - it is +4 :hammers: for coal plants (not mine nor drydock :p) as for the other:
drydock usually gives +1 :yuck: with this event it give +1 :yuck: and +1 :health: the tooltip just says it does not give anything (apart from +2 :hammers:) but if you look at the :yuck: and :health: in the city screen you'll see +1 :yuck: AND +1 :health: from buildings, if you now add a recycling center the tooltip still says +2 :hammers: but the +1 :yuck: from the buildings is gone while the +1 :health: is still there, basically the tooltip cannot cope with a situation where the same building gives both :yuck: and :health: but the game can :)

Well that's what I get for assuming ori knows what he's talking about! ;)

Turns out that even with a recycling center, the +1 :health: doesn't get shown for the drydocks (popup or list). I've fixed that now for the popup, but now I'll have to fix it for the list (I was wondering why I wasn't getting the total I was expecting).

Bh
 
^ Having looked at the Hurry code for the AI, I think I know what the problem with that might be... Blake has the AI hurry all builds unless it is told to Wait... The "Wait" is strictly based on the Slaveryrush (ie if there is enough pop to work all good tiles and the building is taking a while, then the AI does not Wait.. unless there is hurry anger or it is essential..etc.) But there is no reason given to 'Wait' on a rush if it would cost too much gold

I would say simply add something like

if Not 'Essential' & HurryGold>0 & (Gold-Hurry Gold<Gold Target/2 or Production = 0)


then Wait=true

{just before the end of the hurry}

The AI will still be using gold for its production under US, just only half or a third of it will be used for every single build the AI does... the rest will be reserved for "Essential" builds or Builds that take a long time (or anything else the AI might want to use gold for like executives or upgrades or diplomacy)

Although upgrading is also a problem.. but there the problem is self limiting.. eventually all their units are upgraded.. but their cities never stop building


existing hurry code

Spoiler :

void CvCityAI::AI_doHurry(bool bForce)
{
PROFILE_FUNC();

CvArea* pWaterArea;
UnitTypes eProductionUnit;
UnitAITypes eProductionUnitAI;
BuildingTypes eProductionBuilding;
int iHurryAngerLength;
int iHurryPopulation;
int iMinTurns;
bool bDanger;
bool bWait;
bool bEssential;
bool bGrowth;
int iI, iJ;

FAssert(!isHuman() || isProductionAutomated());

if (isBarbarian())
{
return;
}

if ((getProduction() == 0) && !bForce)
{
return;
}

pWaterArea = waterArea();

eProductionUnit = getProductionUnit();
eProductionUnitAI = getProductionUnitAI();
eProductionBuilding = getProductionBuilding();

bDanger = AI_isDanger();

for (iI = 0; iI < GC.getNumHurryInfos(); iI++)
{
if (canHurry((HurryTypes)iI))
{
if (bForce)
{
hurry((HurryTypes)iI);
break;
}
iHurryAngerLength = hurryAngerLength((HurryTypes)iI);
iHurryPopulation = hurryPopulation((HurryTypes)iI);

iMinTurns = MAX_INT;
bEssential = false;
bGrowth = false;

// Whip to eliminate unhappiness - thank you Blake!
if (getProduction() > 0)
{
if (AI_getHappyFromHurry((HurryTypes)iI) > 0)
{
hurry((HurryTypes)iI);
break;
}
}

if ((iHurryAngerLength == 0) && (iHurryPopulation == 0))
{
if (GET_PLAYER(getOwnerINLINE()).AI_avoidScience())
{
if (GET_PLAYER(getOwnerINLINE()).getGold() > GET_PLAYER(getOwnerINLINE()).AI_goldTarget())
{
iMinTurns = std::min(iMinTurns, 10);
}
}
if (eProductionBuilding != NO_BUILDING)
{
int iValuePerTurn = AI_buildingValueThreshold(eProductionBuilding, BUILDINGFOCUS_GOLD | BUILDINGFOCUS_MAINTENANCE | BUILDINGFOCUS_PRODUCTION);

iValuePerTurn /= 3;

if (iValuePerTurn > 0)
{
int iHurryGold = hurryGold((HurryTypes)iI);
if ((iHurryGold / iValuePerTurn) < getProductionTurnsLeft(eProductionBuilding, 1))
{
if (iHurryGold < (GET_PLAYER(getOwnerINLINE()).getGold() / 3))
{
hurry((HurryTypes)iI);
return;
}
}
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (isWorldWonderClass((BuildingClassTypes)(GC.getBuildingInfo(eProductionBuilding).getBuildingClassType())))
{
iMinTurns = std::min(iMinTurns, 10);
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getDefenseModifier() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getBombardDefenseModifier() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getYieldModifier(YIELD_PRODUCTION) > 0)
{
if (getBaseYieldRate(YIELD_PRODUCTION) >= 6)
{
iMinTurns = std::min(iMinTurns, 10);
bGrowth = true;
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if ((GC.getBuildingInfo(eProductionBuilding).getCommerceChange(COMMERCE_CULTURE) > 0) ||
(GC.getBuildingInfo(eProductionBuilding).getObsoleteSafeCommerceChange(COMMERCE_CULTURE) > 0))
{
if ((getCommerceRateTimes100(COMMERCE_CULTURE) == 0) || (plot()->calculateCulturePercent(getOwnerINLINE()) < 40))
{
iMinTurns = std::min(iMinTurns, 10);
if (getCommerceRateTimes100(COMMERCE_CULTURE) == 0)
{
bEssential = true;
iMinTurns = std::min(iMinTurns, 5);
if (AI_countNumBonuses(NO_BONUS, false, true, 2, true, true) > 0)
{
bGrowth = true;
}
}
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getHappiness() > 0)
{
if (angryPopulation() > 0)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getHealth() > 0)
{
if (healthRate() < 0)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getSeaPlotYieldChange(YIELD_FOOD) > 0 || GC.getBuildingInfo(eProductionBuilding).getRiverPlotYieldChange(YIELD_FOOD) > 0)
{

iMinTurns = std::min(iMinTurns, 10);

if (AI_buildingSpecialYieldChangeValue(eProductionBuilding, YIELD_FOOD) > (getPopulation() * 2))
{
bEssential = true;
bGrowth = true;
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getFreeExperience() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getMaintenanceModifier() < 0)
{
if (getMaintenance() >= 10)
{
iMinTurns = std::min(iMinTurns, 10);
bEssential = true;
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getDefineINT("DEFAULT_SPECIALIST") != NO_SPECIALIST)
{
if (getSpecialistCount((SpecialistTypes)(GC.getDefineINT("DEFAULT_SPECIALIST"))) > 0)
{
for (iJ = 0; iJ < GC.getNumSpecialistInfos(); iJ++)
{
if (GC.getBuildingInfo(eProductionBuilding).getSpecialistCount(iJ) > 0)
{
iMinTurns = std::min(iMinTurns, 10);
break;
}
}
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getCommerceModifier(COMMERCE_GOLD) > 0)
{
if (GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble())
{
if (getBaseCommerceRate(COMMERCE_GOLD) >= 16)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getCommerceModifier(COMMERCE_RESEARCH) > 0)
{
if (!(GET_PLAYER(getOwnerINLINE()).AI_avoidScience()))
{
if (getBaseCommerceRate(COMMERCE_RESEARCH) >= 16)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}
}

if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getFoodKept() > 0)
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}

if (eProductionUnit != NO_UNIT)
{
if (GC.getUnitInfo(eProductionUnit).getDomainType() == DOMAIN_LAND)
{
if (GC.getUnitInfo(eProductionUnit).getCombat() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}
}

if (eProductionUnitAI == UNITAI_CITY_DEFENSE)
{
if (plot()->plotCheck(PUF_isUnitAIType, UNITAI_SETTLE, -1, getOwnerINLINE()) != NULL)
{
if (!AI_isDefended(-2)) // XXX check for other team's units?
{
iMinTurns = std::min(iMinTurns, 5);
}
}
}

if (eProductionUnitAI == UNITAI_SETTLE)
{
if (area()->getNumAIUnits(getOwnerINLINE(), UNITAI_SETTLE) == 0)
{
if (!(GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble()))
{
if (area()->getBestFoundValue(getOwnerINLINE()) > 0)
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}
}
}

if (eProductionUnitAI == UNITAI_SETTLER_SEA)
{
if (pWaterArea != NULL)
{
if (pWaterArea->getNumAIUnits(getOwnerINLINE(), UNITAI_SETTLER_SEA) == 0)
{
if (area()->getNumAIUnits(getOwnerINLINE(), UNITAI_SETTLE) > 0)
{
iMinTurns = std::min(iMinTurns, 5);
}
}
}
}

if (eProductionUnitAI == UNITAI_WORKER)
{
if (GET_PLAYER(getOwnerINLINE()).AI_neededWorkers(area()) > (area()->getNumAIUnits(getOwnerINLINE(), UNITAI_WORKER) * 2))
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}

if (eProductionUnitAI == UNITAI_WORKER_SEA)
{
if (AI_neededSeaWorkers() > 0)
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}

// adjust for game speed
if (NO_UNIT != getProductionUnit())
{
iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
}
else if (NO_BUILDING != getProductionBuilding())
{
iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
}
else if (NO_PROJECT != getProductionProject())
{
iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getCreatePercent();
}
else
{
iMinTurns *= 100;
}

iMinTurns /= 100;

//this overrides everything.
if (bGrowth)
{
int iHurryGold = hurryGold((HurryTypes)iI);
if ((iHurryGold > 0) && ((iHurryGold * 16) < GET_PLAYER(getOwnerINLINE()).getGold()))
{
hurry((HurryTypes)iI);
break;
}
if (AI_countGoodTiles((healthRate(0) == 0), false, 100) <= (getPopulation() - iHurryPopulation))
{
hurry((HurryTypes)iI);
break;
}
}
if (AI_countGoodTiles((healthRate(0) == 0), false, 100) <= (getPopulation() - iHurryPopulation))
{
if (getProductionTurnsLeft() > iMinTurns)
{
bWait = isHuman();

if ((iHurryPopulation * 3) > (getProductionTurnsLeft() * 2))
{
bWait = true;
}

if (!bWait)
{
if (iHurryAngerLength > 0)
{
//is the whip just too small or the population just too reduced to bother?
if (!bEssential && ((iHurryPopulation < (1 + GC.getDefineINT("HURRY_POP_ANGER"))) || ((getPopulation() - iHurryPopulation) <= std::max(3, (getHighestPopulation() / 2)))))
{
bWait = true;
}
else
{
//sometimes it's worth whipping even with existing anger
if (getHurryAngerTimer() > 1)
{
if (!bEssential)
{
bWait = true;
}
else if (GC.getDefineINT("HURRY_POP_ANGER") == iHurryPopulation && angryPopulation() > 0)
{
//ideally we'll whip something more expensive
bWait = true;
}
}
}

//if the city is just lame then don't whip the poor thing
//(it'll still get whipped when unhappy/unhealthy)
if (!bWait && !bEssential)
{
int iFoodSurplus = 0;
CvPlot * pLoopPlot;

for (iJ = 0; iJ < NUM_CITY_PLOTS; iJ++)
{
if (iJ != CITY_HOME_PLOT)
{
pLoopPlot = getCityIndexPlot(iJ);

if (pLoopPlot != NULL)
{
if (pLoopPlot->getWorkingCity() == this)
{
iFoodSurplus += std::max(0, pLoopPlot->getYield(YIELD_FOOD) - GC.getFOOD_CONSUMPTION_PER_POPULATION());
}
}
}
}

if (iFoodSurplus < 3)
{
bWait = true;
}
}
}
}

if (!bWait)
{
hurry((HurryTypes)iI);
break;
}
}
}
}
}
}




Finally I'd redo the existing executive control so that it was
Not enough gold for a Foreign Branch... divide Corporate value by (# Executives+1)
and
Not enough gold for a Domestic Branch...divide Corporate value by (# Executives +1)

(so in the second case it gets divided twice...and so that its somewhat dependent on # of executives you have... if you don't have enough gold..2 executive means a 1/9 value for a next one.. 3 means a 1/16 value)
 
Well that's what I get for assuming ori knows what he's talking about! ;)

Turns out that even with a recycling center, the +1 :health: doesn't get shown for the drydocks (popup or list). I've fixed that now for the popup, but now I'll have to fix it for the list (I was wondering why I wasn't getting the total I was expecting).

Bh
:blush: I have to admit that while I know what I wanted to say (and I think that is what you fixed now) this post was confusing at best - I should start writing more clearly (or maybe thinking more clearly ;))
 
Update:
  • Fixed bug (introduced) causing endless loop at "waiting for players"
  • Fixed bug (introduced) causing the Great Persons civilopedia entries to be blank
  • Stolen techs can no longer be traded with No Tech Brokering enabled
  • New Colonies mirror their Master's tech status with No Tech Brokering enabled
  • New Colonies mirror their Master's exploration (map) status
  • Healthy/Unhealthy bonuses will display properly under more circumstances (events, etc)

Bh
 
The stealth destroyer seems simple to me... as you say Bhruic, the newbie has an expectation that his "stack" of units will defend, so the game should work that way.

For both the newbie and the expert player, if you wanted your destroyer to stay stealthed and not defend, then don't leave it in a tile with other units. Quite simple.

Wodan
 
The stealth destroyer seems simple to me... as you say Bhruic, the newbie has an expectation that his "stack" of units will defend, so the game should work that way.

I'm just wondering if there's a different group of people out there who expect the SD to not defend if it's in a stack who have been silent so far because that's the way it works. Making the game match expectations is great - as long as everyone has the same expectations. ;)

Bh
 
I'm just wondering if there's a different group of people out there who expect the SD to not defend if it's in a stack who have been silent so far because that's the way it works. Making the game match expectations is great - as long as everyone has the same expectations. ;)

Bh

Well, if there is such a group, I'm not one of them. Thanks :clap: again for your excellent work!!!
 
I downloaded and installed the Nov 2nd (today's) version of the unofficial patch and resumed a game I started with the old version. When I went to upgrade a rifleman to infantry, it correctly shows a cost of 110. If I hold the ALT key to upgrade all riflemen, the cost displays as zero.

Sorry to throw another bug out, Bhruic. Thanks again for the work!
 
Do you have the save?

Bh

No, I didn't think about it until after I passed the turn then I came here to post. I'll play again tonight or tomorrow. If I catch it again, I'll post a save for you.

Sorry
 
* Concerning the stealth destroyer issue, I agree that they should move to the forefront and defend when an enemy ship moves into that square.... As the regular destroyer upgrades to stealth destroyer, it more or less leaves the player unable to construct an anti-air naval unit with moderate strength that can do any good in defensive naval battles. (I'd feel differently if destroyers weren't obsoleted by stealth destroyers.)

oh let's not even go there! i'm about *thisclose* to modding my files so that you can still make destroyers after you can make stealths, with this issue and because stealths can't see subs. whenever the game goes that late i can't seem to stock up enough normal destroyers even tho i try!
That might be a sound argument if you couldn't check what techs the other Civs have. But if you can figure out they have the technology to build them, it doesn't seem logical to deny their existence.

i'm all for SDs defending. just don't keep following this slippery slope and have the AI give me diplomatic penalties if they're being harassed by privateers and sweet little innocent me just happens to be the only civ that knows astronomy and chemistry together okay? thanks bud. ;)
 
Hey Bh- I did not see the fix- Did you include the fix for Great Spy "boot" issue?

I wish I could chime in on the SD discussion, but Iv'e yet to get that far in a game to be able to build them.
 
Top Bottom