• Civilization 7 has been announced. For more info please check the forum here .

Questions about The BUG Mod

Today I installed BUG mod on my BtS game, launched it and noticed that all interface buttons, minimap and commands disappeared. Only map with units, nothing else. I uninstalled the mod, tried to run BtS, but the problem was still there (( What did I do wrong? How do I bring back my interface and BUG mod with it? Warlords and vanilla Civ4 are unaffected.
Thanx
 
Start by posting here the information asked for on the Troubleshooting page. Also, does your user account have non-Latin characters in it (for example accents)?
 
One thing that's been bugging me for a while. I remember a long time ago there was something mentioned about a pyramid schematic to represent the unhappiness in a city. I was under the impression if hovering over the time-wait icon some graphical representation was supposed to be drawn. It's not that big a deal since I can see how long I have to wait anyhow for the unhappy to wear off, but I am just curious if I was missing something.
 
I think you're talking about the suggestion that when you hover over the whip button it would show you something like this:

:(:(:( for 7 turns
:(:( for 10 turns
:( for 10 turns​

This would be for when the current timer was at 17 with 2 :(. Is that what you're talking about?
 
I think you're talking about the suggestion that when you hover over the whip button it would show you something like this:

:(:(:( for 7 turns
:(:( for 10 turns
:( for 10 turns​

This would be for when the current timer was at 17 with 2 :(. Is that what you're talking about?

I was just thinking this the other day. 17 with 2 :( doesn't really tell the whole story since the 2 :( isn't going to be around for the full 17 turns. This would be a great addition!
 
IIRC, there's a checkbox on the Unit Naming panel to enable "advanced methods". What are these and where are they documented? I couldn't find anything in the help file.
 
BUG comes with an INI file (Adv Unit Naming.ini). The advanced methods just mean that each unit type and era combination has its own naming convention. You must enter them into the INI file directly, but the codes work the same as the normal method. That file is in the UserSettings folder.
 
If I install BUG as a Standalone mod, does that mean it's just like a normal other mod? But I also want to know if I can load previous saved games hat I played with BUG when it is installed in my C. Assets folder (like it is now) if I have BUG as a standalone mod. The reason I ask is that when I play the Giant Earth Map, I get no interface and I suspect that something betwen GEM and BUG is conflicting.
 
Multiplayer install of BUG is a normal mod like other mods (FfH, Next War) that you must load to play. When it is installed in the CustomAssets folder, it is always active. It can interfere there with other mods unless you set the other mods' INI files to ignore the CA folder.
 
Ahh, yes you can still play those games if you uninstall the CA version of BUG, but you won't be playing them with BUG anymore. They'll work fine, but you won't have the features of BUG.

What you can do is create a new folder to serve as "My Games/Beyond the Sword". Move your current CustomAssets folder there, and BTS will make a new empty one without BUG for your normal installation. Let's say that new folder is "C:\Games\BTS".

Now copy the BTS shortcut you use to launch BTS, edit the copy's properties, and change the target to this:

<bts.exe> /altroot=C:\Games\BTS​

where <bts.exe> is what was there before.

Copy the file "My Games/Beyond the Sword/BUG Mod/Info/CvAltRoot.py" to the moved CA folder's Python folder. Open it in Notepad and change the folder path at the very bottom to the folder you created above.

This will now launch BTS using that CA folder you moved. Your normal shortcut uses the empty shortcut. You can now install BUG as a mod to play new games and use that shortcut to load (from the main menu) your old games.

Last but not least, to share your BUG settings among both installations, move the "BUG Mod" folder from "Beyond the Sword" to "My Games". You should now be in business.
 
A bit more specific questions:
[CvPlayer.cpp] I'm guessing
5987: if (!bValid && pPlot->isWater())
5988: {
is the better version?
BULL has
if (pPlot->isWater())
{
bValid = false;

instead. Which will lead to the same return value eventually, though if bValid is already true, the python callback is skipped in jodog5000's version (or so I guess, I'm not going to pretend I understand this)
Both parts claim to be from the Unofficial Patch

Spoiler :
Code:
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       10/04/09                    EmperorFool & jdog5000    */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
	// EF: canFoundCitiesOnWater callback handling was incorrect and ignored isWater() if it returned true
	if (!bValid && pPlot->isWater())
	{
		if(GC.getUSE_CAN_FOUND_CITIES_ON_WATER_CALLBACK())
		{
			CyArgsList argsList2;
			argsList2.add(iX);
			argsList2.add(iY);
			lResult=0;
			gDLL->getPythonIFace()->callFunction(PYGameModule, "canFoundCitiesOnWater", argsList2.makeFunctionArgs(), &lResult);

			if (lResult == 1)
			{
				bValid = true;
			}
		}
	}
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/


[CvUnit.cpp]One more issue: A single-line unofficial patch claims to make collateral damage work again for units with barrage promotions but without base collateral abilities.
EmperorFool seems to have added an additional statement into that function, and I'm not sure if that is needed or what it does exactly.
Spoiler :
Code:
void CvUnit::collateralCombat(const CvPlot* pPlot, CvUnit* pSkipUnit)
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	CvWString szBuffer;
	int iTheirStrength;
	int iStrengthFactor;
	int iCollateralDamage;
	int iUnitDamage;
	int iDamageCount;
	int iPossibleTargets;
	int iCount;
	int iValue;
	int iBestValue;
	std::map<CvUnit*, int> mapUnitDamage;
	std::map<CvUnit*, int>::iterator it;

	int iCollateralStrength = (getDomainType() == DOMAIN_AIR ? airBaseCombatStr() : baseCombatStr()) * collateralDamage() / 100;
// BUG - Unofficial Patch - start
	// Barrage promotions made working again on Tanks and other units with no base collateral ability
	if (iCollateralStrength == 0 && getExtraCollateralDamage() == 0)
// BUG - Unofficial Patch - end
	{
		return;
	}

	iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits());

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit != pSkipUnit)
		{
			if (isEnemy(pLoopUnit->getTeam(), pPlot))
			{
				if (!(pLoopUnit->isInvisible(getTeam(), false)))
				{
					if (pLoopUnit->canDefend())
					{
						iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "Collateral Damage"));

						iValue *= pLoopUnit->currHitPoints();

						mapUnitDamage[pLoopUnit] = iValue;
					}
				}
			}
		}
	}

	CvCity* pCity = NULL;
	if (getDomainType() == DOMAIN_AIR)
	{
		pCity = pPlot->getPlotCity();
	}

	iDamageCount = 0;
	iCount = 0;

	while (iCount < iPossibleTargets)
	{
		iBestValue = 0;
		pBestUnit = NULL;

		for (it = mapUnitDamage.begin(); it != mapUnitDamage.end(); it++)
		{
			if (it->second > iBestValue)
			{
				iBestValue = it->second;
				pBestUnit = it->first;
			}
		}

		if (pBestUnit != NULL)
		{
			mapUnitDamage.erase(pBestUnit);

			if (NO_UNITCOMBAT == getUnitCombatType() || !pBestUnit->getUnitInfo().getUnitCombatCollateralImmune(getUnitCombatType()))
			{
				iTheirStrength = pBestUnit->baseCombatStr();

[B]				if (iCollateralStrength == 0)
				{
					iCollateralStrength = baseCombatStr();
				}
[/B]
				iStrengthFactor = ((iCollateralStrength + iTheirStrength + 1) / 2);

				iCollateralDamage = (GC.getDefineINT("COLLATERAL_COMBAT_DAMAGE") * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor);

				iCollateralDamage *= 100 + getExtraCollateralDamage();

				iCollateralDamage *= std::max(0, 100 - pBestUnit->getCollateralDamageProtection());
				iCollateralDamage /= 100;

				if (pCity != NULL)
				{
					iCollateralDamage *= 100 + pCity->getAirModifier();
					iCollateralDamage /= 100;
				}

				iCollateralDamage /= 100;

				iCollateralDamage = std::max(0, iCollateralDamage);

				int iMaxDamage = std::min(collateralDamageLimit(), (collateralDamageLimit() * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor));
				iUnitDamage = std::max(pBestUnit->getDamage(), std::min(pBestUnit->getDamage() + iCollateralDamage, iMaxDamage));

				if (pBestUnit->getDamage() != iUnitDamage)
				{
// BUG - Combat Events - start
					int iDamageDone = iUnitDamage - pBestUnit->getDamage();
					pBestUnit->setDamage(iUnitDamage, getOwnerINLINE());
					CvEventReporter::getInstance().combatLogCollateral(this, pBestUnit, iDamageDone);
// BUG - Combat Events - end
					iDamageCount++;
				}
			}

			iCount++;
		}
		else
		{
			break;
		}
	}

	if (iDamageCount > 0)
	{
		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SUFFER_COL_DMG", iDamageCount);
		gDLL->getInterfaceIFace()->addMessage(pSkipUnit->getOwnerINLINE(), (pSkipUnit->getDomainType() != DOMAIN_AIR), GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COLLATERAL", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pSkipUnit->getX_INLINE(), pSkipUnit->getY_INLINE(), true, true);

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_INFLICT_COL_DMG", getNameKey(), iDamageCount);
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COLLATERAL", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pSkipUnit->getX_INLINE(), pSkipUnit->getY_INLINE());
	}
}
 
It's much easier to read code if you use [code]...[/code] tags to preserve indentation.

For the first, the logic is this: you cannot found on a water plot unless the Python callback allows it. Thus, if you have the "!bValid" check in there, it will allow a previous check to ignore the isWater() test.

Looking at the code, the first two checks should be safe (isFound() for a water tile makes the Python callback unnecessary and isCoastalLand() should definitely return false for water tiles), but the last one is unknown to me. Do water tiles at the mouth of a river return true for isFreshWater()? If so, that would allow you to settle cities on those tiles by adding the check you propose.

For the second, that bolded line has no comment from me, so it should be what's in the original BTS code. If not, please let me know and I'll fix it.
 
I am not proposing anythng, I'm trying to merge BULL into BetterAI. so the code that is not from you is from jdog5000.
I doubt isFreshWater() is true for any water tiles but since I don't know it could be possible - for rivermouth coast and inland lakes.
I think your code is the safer way to do it.

For the second, that bolded line has no comment from me, so it should be what's in the original BTS code. If not, please let me know and I'll fix it.
I checked, that is a change from you. At least it's not from the BTS 3.19 file, maybe you preserved it from an earlier version?
And yes, I saw that there are no comments. That's why I'm asking what it's actually doing.
 
From what I recall, this was a fix from Solver. It makes it so that if you allow the Barrage line of promotions to units that don't already do collateral damage, they have an effect. Without it, they have zero effect on those units.

I will add a comment about it to BULL. It only has any effect if you mod the XML to allow Barrage promotions for units without native collateral damage (e.g. Armored units).
 
As far as I can tell, those lines without comments are not from the unofficial patch either, and even if solver once wrote those lines, this is not how collateralcombat should work.
collateralDamageLimit() is 60 for tanks so that at least keeps the maximum damage at bay but still, with that code a tank with barrage 1 will be stronger than a mobile artillery with the same promotion. A unit with barrage promotion is basically treated as a full-fledged siege unit the moment it gets that promotion. Intended or not, that makes the barrage 1 promotion way too powerful.
Note that collateral damage is done even with collateralStrength of 0. This is not normal combat.
If you still need to give more collateralStrength then at least do something like
if (iCollateralStrength == 0)
{
iCollateralStrength = baseCombatStr() * (getExtraCollateralDamage()) / (100 + getExtraCollateralDamage());
}

to tone it down a bit.
 
Yes, a lot better. Actually that's the only sane way to do it. My code was just stupid, I guess it got too late yesterday :crazyeye:

iStrengthFactor = ((iCollateralStrength + iTheirStrength + 1) / 2);
iCollateralDamage = (GC.getDefineINT("COLLATERAL_COMBAT_DAMAGE") * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor);
iCollateralDamage *= 100 + getExtraCollateralDamage();

That is how collateral damage is calculated. GC.getDefineINT("COLLATERAL_COMBAT_DAMAGE" is just a constant from GlobalDefinesInt and is 10. When iCollateralStrength is the same as iTheirStrength, then (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor) is simply 1. If When iCollateralStrength is 0, then that part is 1/2. So, when a normal siege units does collateral damage to a defender with the same base strenth, he does 100%/120%/150%/200% damage depending on his barrage promotions. A tank with zero iCollateralStrength simply does 0/60%/75%/100% of what it would do if it was a standard siege unit that met a defender with the same strength.
Which is still a huge bonus for barrage 1 and that's why it is disabled.
 
I think you're talking about the suggestion that when you hover over the whip button it would show you something like this:

:(:(:( for 7 turns
:(:( for 10 turns
:( for 10 turns​

This would be for when the current timer was at 17 with 2 :(. Is that what you're talking about?

Yes, I thought I read ages ago this was already implemented but maybe I misread. I thought it was switched off somewhere by default to keep things streamlined. For example, I often get 600-turns unhappiness which would cause quite a large pyramids-schematic to say the least.
 
Top Bottom