Quick Questions / Quick Answers

Interesting. I've only downloaded the "(1) Community Patch" zip in the VP MEGA and have no other mods.

Edit: I found Community-Patch-DLL/issues/3984 in the Github, which explains things. However the math that's performed to get the desired result out of the indicator appears to be done in the compiled .dll. The viewable lua files work with that math (Core Files\CoreLua\PathHelpManager.lua), let me change the number that's displayed in the middle of the movement indicator, but its colour will always be grey because the internal value (how many turns will it take to get there) is being artificially multiplied elsewhere, to a minimum of 5 turns even to move one hex.
 
Last edited:
1. Can unit upgrade cost not be lowered? Changing “UNIT_UPGRADE_COST_PER_PRODUCTION” in Core Defines to anything lower than 1 results in my unit upgrades costing 10 gold.

2. Is there any way I can tweak unit XP gains or the amount of xp needed for a promo? The only thing I’ve found EXPERIENCE_ATTACKING_CITY_RANGED, which is really specific.
 
Code:
//   --------------------------------------------------------------------------------
/// How much does it cost to upgrade this Unit to a shiny new eUnit?
int CvUnit::upgradePrice(UnitTypes eUnit) const
{
   VALIDATE_OBJECT
   int iPrice = 0;
 
   CvUnitEntry* pkUnitInfo = GC.getUnitInfo(eUnit);
   if(pkUnitInfo == NULL)
   {
       return 0;
   }

   if(isBarbarian())
   {
       return 0;
   }

   if (GET_PLAYER(getOwner()).isMinorCiv())
       return 0;

   iPrice = /*10*/ GC.getBASE_UNIT_UPGRADE_COST();

   CvPlayerAI& kPlayer = GET_PLAYER(getOwner());

   int iProductionBase = kPlayer.getProductionNeeded(getUnitType());
   if (iProductionBase == 0)
   {
       iProductionBase = kPlayer.getProductionNeeded(eUnit) / 2;
   }

   iPrice += (std::max(0, (kPlayer.getProductionNeeded(eUnit) - iProductionBase)) * /*2*/ GC.getUNIT_UPGRADE_COST_PER_PRODUCTION());

   // Upgrades for later units are more expensive
   const TechTypes eTech = (TechTypes) pkUnitInfo->GetPrereqAndTech();
   CvTechEntry* pkTechInfo = GC.getTechInfo(eTech);
   if(pkTechInfo)
   {
       const EraTypes eUpgradeEra = (EraTypes) pkTechInfo->GetEra();

       double fMultiplier = 1.0f;
       fMultiplier += (eUpgradeEra* /*0.3*/ GC.getUNIT_UPGRADE_COST_MULTIPLIER_PER_ERA());

       iPrice = int(iPrice * fMultiplier);
   }

   if(!isHuman() && !isBarbarian())
   {
       iPrice *= GC.getGame().getHandicapInfo().getAIUnitUpgradePercent();
       iPrice /= 100;

       iPrice *= std::max(0, ((GC.getGame().getHandicapInfo().getAIPerEraModifier() * GET_TEAM(getTeam()).GetCurrentEra()) + 100));
       iPrice /= 100;
   }

   // Discount
   iPrice -= (iPrice * getUpgradeDiscount()) / 100;

   // Mod (Policies, etc.)
   int iMod = kPlayer.GetUnitUpgradeCostMod();
   iPrice *= (100 + iMod);
   iPrice /= 100;

   // Apply exponent
   iPrice = (int) pow((double) iPrice, (double) /*1.0f*/ GC.getUNIT_UPGRADE_COST_EXPONENT());

   // Make the number not be funky
   int iDivisor = /*5*/ GC.getUNIT_UPGRADE_COST_VISIBLE_DIVISOR();
   iPrice /= iDivisor;
   iPrice *= iDivisor;

   return max(1, iPrice);
}
Code:
//   --------------------------------------------------------------------------------
#if defined(MOD_UNITS_XP_TIMES_100)
void CvUnit::changeExperienceTimes100(int iChangeTimes100, int iMax, bool bFromCombat, bool bInBorders, bool bUpdateGlobal)
#else
void CvUnit::changeExperience(int iChange, int iMax, bool bFromCombat, bool bInBorders, bool bUpdateGlobal)
#endif
{
   VALIDATE_OBJECT
   // Barbs don't get XP or Promotions
#if defined(MOD_UNITS_XP_TIMES_100)
   if (isBarbarian() && iChangeTimes100 > 0)
#else
   if (isBarbarian() && iChange > 0)
#endif
   {
       return;
   }

   if (MOD_BALANCE_CORE_SCALING_XP && !bFromCombat)
   {
       iChangeTimes100 *= GC.getGame().getGameSpeedInfo().getTrainPercent();
       iChangeTimes100 /= 100;
   }

#if defined(MOD_UNITS_XP_TIMES_100)
   // Checking limits.h for the values of MAX_INT and MAX_LONG they are the same, so we need to use "long long" and hence MAX_LLONG
   long long lMaxTimes100 = (iMax == -1) ? INT_MAX : (iMax * 100LL);
   int iMaxTimes100 = (lMaxTimes100 > ((long long)INT_MAX)) ? INT_MAX : (int)lMaxTimes100;
 
   int iUnitExperienceTimes100 = iChangeTimes100;
#else
   int iUnitExperience = iChange;
#endif
   PromotionTypes eNewPromotion = NO_PROMOTION;

   if(bFromCombat)
   {
       CvPlayer& kPlayer = GET_PLAYER(getOwner());

       // Promotion that changes after combat?
       for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
       {
           const PromotionTypes eLoopPromotion = static_cast<PromotionTypes>(iI);
           CvPromotionEntry* pkPromotionInfo = GC.getPromotionInfo(eLoopPromotion);
           if(pkPromotionInfo)
           {
               if (pkPromotionInfo->HasPostCombatPromotions() && m_Promotions.HasPromotion(eLoopPromotion))
               {
                   eNewPromotion = m_Promotions.ChangePromotionAfterCombat(eLoopPromotion);
                   setHasPromotion(eLoopPromotion, false);

                   if (eNewPromotion != NO_PROMOTION)
                   {
                       setHasPromotion(eNewPromotion, true);

#if defined(MOD_EVENTS_UNIT_UPGRADES)
                       if (MOD_EVENTS_UNIT_UPGRADES) {
                           GAMEEVENTINVOKE_HOOK(GAMEEVENT_UnitPromoted, getOwner(), GetID(), eNewPromotion);
                       }
#endif
                       if (kPlayer.GetID() == GC.getGame().getActivePlayer())
                       {
                           CvPromotionEntry* pkNewPromotionInfo = GC.getPromotionInfo(eNewPromotion);
                           Localization::String localizedText = Localization::Lookup(pkNewPromotionInfo->GetDescriptionKey());
                           SHOW_PLOT_POPUP(plot(), getOwner(), localizedText.toUTF8());
                       }
                   }
               }
           }
       }

       // Player Great General/Admiral mod
       int iCombatExperienceMod;
       if (getDomainType() == DOMAIN_SEA)
       {
           iCombatExperienceMod = 100 + kPlayer.getGreatAdmiralRateModifier();
       }
       else
       {
           iCombatExperienceMod = 100 + kPlayer.getGreatGeneralRateModifier();
       }

       // Unit XP mod
#if defined(MOD_UNITS_XP_TIMES_100)
       int iPlayerBonusXpTimes100 = (iChangeTimes100 * kPlayer.getExpModifier()) / 100;
       if (!MOD_UNITS_XP_TIMES_100) {
           // If NOT using XP times 100, remove any fractional part
           iPlayerBonusXpTimes100 -= (iPlayerBonusXpTimes100 % 100);
       }
       iUnitExperienceTimes100 += iPlayerBonusXpTimes100;
       if(MOD_BALANCE_CORE_RESOURCE_MONOPOLIES)
       {
           const std::vector<ResourceTypes>& vStrategicMonopolies = GET_PLAYER(getOwner()).GetStrategicMonopolies();
           for (size_t iResourceLoop = 0; iResourceLoop < vStrategicMonopolies.size(); iResourceLoop++)
           {
               ResourceTypes eResourceLoop = vStrategicMonopolies[iResourceLoop];
               CvResourceInfo* pInfo = GC.getResourceInfo(eResourceLoop);
               if (pInfo && pInfo->getMonopolyXPBonus() > 0)
               {
                   iUnitExperienceTimes100 += (pInfo->getMonopolyXPBonus() * 100);
               }
           }
       }
#else
       iUnitExperience += (iChange * kPlayer.getExpModifier()) / 100;
#if defined(MOD_BALANCE_CORE_RESOURCE_MONOPOLIES)
       if(MOD_BALANCE_CORE_RESOURCE_MONOPOLIES)
       {
           const std::vector<ResourceTypes>& vStrategicMonopolies = GET_PLAYER(getOwner()).GetStrategicMonopolies();
           for (size_t iResourceLoop = 0; iResourceLoop < vStrategicMonopolies.size(); iResourceLoop++)
           {
               ResourceTypes eResourceLoop = vStrategicMonopolies[iResourceLoop];
               CvResourceInfo* pInfo = GC.getResourceInfo(eResourceLoop);
               if (pInfo && pInfo->getMonopolyXPBonus() > 0)
               {
                   iUnitExperience += pInfo->getMonopolyXPBonus();
               }
           }
       }
#endif
#endif
       // Great General & Unit XP mod in borders
       if (bInBorders)
       {
           // In-borders GG mod
           if (getDomainType() == DOMAIN_LAND)
           {
               iCombatExperienceMod += kPlayer.getDomesticGreatGeneralRateModifier();
           }

           int iBorderBonusXpTimes100 = (iChangeTimes100 * kPlayer.getExpInBorderModifier()) / 100;
           if (!MOD_UNITS_XP_TIMES_100) {
               // If NOT using XP times 100, remove any fractional part
               iBorderBonusXpTimes100 -= (iBorderBonusXpTimes100 % 100);
           }
           iUnitExperienceTimes100 += iBorderBonusXpTimes100;
       }

       if(bUpdateGlobal)
       {
           // Add Unit GG mod
           if (getDomainType() == DOMAIN_LAND)
           {
               iCombatExperienceMod += getGreatGeneralModifier();
           }

           if(iMax == -1)
           {
               if(getDomainType() == DOMAIN_SEA)
               {
#if defined(MOD_GLOBAL_LOCAL_GENERALS)
#if defined(MOD_UNITS_XP_TIMES_100)
                   kPlayer.changeNavalCombatExperienceTimes100((iChangeTimes100 * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#else
                   kPlayer.changeNavalCombatExperience((iChange * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#endif
#else
#if defined(MOD_UNITS_XP_TIMES_100)
                   kPlayer.changeNavalCombatExperienceTimes100((iChangeTimes100 * iCombatExperienceMod) / 100);
#else
                   kPlayer.changeNavalCombatExperience((iChange * iCombatExperienceMod) / 100);
#endif
#endif
               }
               else
               {
#if defined(MOD_GLOBAL_LOCAL_GENERALS)
#if defined(MOD_UNITS_XP_TIMES_100)
                   kPlayer.changeCombatExperienceTimes100((iChangeTimes100 * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#else
                   kPlayer.changeCombatExperience((iChange * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#endif
#else
#if defined(MOD_UNITS_XP_TIMES_100)
                   kPlayer.changeCombatExperienceTimes100((iChangeTimes100 * iCombatExperienceMod) / 100);
#else
                   kPlayer.changeCombatExperience((iChange * iCombatExperienceMod) / 100);
#endif
#endif
               }
           }
           else
           {
#if defined(MOD_UNITS_XP_TIMES_100)
               int iModdedChangeTimes100 = min(iMaxTimes100 - m_iExperienceTimes100, iChangeTimes100);
               if (iModdedChangeTimes100 > 0)
#else
               int iModdedChange = min(iMax - m_iExperience, iChange);
               if (iModdedChange > 0)
#endif
               {
                   if(getDomainType() == DOMAIN_SEA)
                   {
#if defined(MOD_GLOBAL_LOCAL_GENERALS)
#if defined(MOD_UNITS_XP_TIMES_100)
                       kPlayer.changeNavalCombatExperienceTimes100((iModdedChangeTimes100 * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#else
                       kPlayer.changeNavalCombatExperience((iModdedChange * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#endif
#else
#if defined(MOD_UNITS_XP_TIMES_100)
                       kPlayer.changeNavalCombatExperienceTimes100((iModdedChangeTimes100 * iCombatExperienceMod) / 100);
#else
                       kPlayer.changeNavalCombatExperience((iModdedChange * iCombatExperienceMod) / 100);
#endif
#endif
                   }
                   else
                   {
#if defined(MOD_GLOBAL_LOCAL_GENERALS)
#if defined(MOD_UNITS_XP_TIMES_100)
                       kPlayer.changeCombatExperienceTimes100((iModdedChangeTimes100 * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#else
                       kPlayer.changeCombatExperience((iModdedChange * iCombatExperienceMod) / 100, (MOD_GLOBAL_LOCAL_GENERALS ? this : NULL));
#endif
#else
#if defined(MOD_UNITS_XP_TIMES_100)
                       kPlayer.changeCombatExperienceTimes100((iModdedChangeTimes100 * iCombatExperienceMod) / 100);
#else
                       kPlayer.changeCombatExperience((iModdedChange * iCombatExperienceMod) / 100);
#endif
#endif
                   }
               }
           }
       }

       if(getExperiencePercent() != 0)
       {
#if defined(MOD_UNITS_XP_TIMES_100)
           int iUnitBonusXpTimes100 = (iUnitExperienceTimes100 + getExperiencePercent()) / 100;
           if (!MOD_UNITS_XP_TIMES_100) {
               // If NOT using XP times 100, remove any fractional part
               iUnitBonusXpTimes100 -= (iUnitBonusXpTimes100 % 100);
           }
           iUnitExperienceTimes100 += iUnitBonusXpTimes100;
#else
           iUnitExperience *= 100 + getExperiencePercent();
           iUnitExperience /= 100;
#endif
       }
   }

#if defined(MOD_UNITS_XP_TIMES_100)
   setExperienceTimes100((getExperienceTimes100() + iUnitExperienceTimes100), iMax);
#else
   setExperience((getExperience() + iUnitExperience), iMax);
#endif
}
Code:
//   --------------------------------------------------------------------------------
int CvUnit::experienceNeeded() const
{
   VALIDATE_OBJECT

   const int iLevel = getLevel();

   // Sum up the levels to get our multiplier (1:1, 2:3, 3:6, 4:10, etc.)
   int iExperienceMultiplier = 0;
   for(int iLevelLoop = 1; iLevelLoop <= iLevel; iLevelLoop++)
   {
       iExperienceMultiplier += iLevelLoop;
   }

   int iExperienceNeeded = /*10*/ GC.getEXPERIENCE_PER_LEVEL() * iExperienceMultiplier;

   const int iModifier = GET_PLAYER(getOwner()).getLevelExperienceModifier();
   if(0 != iModifier)
   {
       float fTemp = (float) iExperienceNeeded;
       fTemp *= (100 + iModifier);
       fTemp /= 100;
       iExperienceNeeded = (int) ceil(fTemp); // Round up
   }

   if (MOD_BALANCE_CORE_SCALING_XP)
   {
       iExperienceNeeded *= GC.getGame().getGameSpeedInfo().getTrainPercent();
       iExperienceNeeded /= 100;
   }

   return iExperienceNeeded;
}

To update global values you can generally add the following to an SQL file:

Code:
UPDATE Defines
SET Value = [new value]
WHERE Name = '[global name]';

Example:
UPDATE Defines
SET Value = '10'
WHERE Name = 'EXPERIENCE_PER_LEVEL';

(make sure to include the ; at the end)

NOTE: It's possible that the /*listed values*/ of globals in the code blocks are not the actual values. If it's a value that exists in the base game it'll be found in the Expansion2 subfolder of the base game's Steam files (XML). It may have been updated in VP in an SQL file.

Notepad++'s Find in Files feature is very helpful.
 
Is light tank an armored unit? (Does "Lightning Warfare" tenet apply on the light tanks?)
Tnx in advance!
 
Is there a pure SQL way to add a new promotion that gives a ranged attack bonus against just melee ships?
 
Is light tank an armored unit? (Does "Lightning Warfare" tenet apply on the light tanks?)
Tnx in advance!

Armored units are melee units like Landship and Tanks. Light Tank is considered Archer unit since it's ranged. Therefore, Light Tanks don't get that promotion unless you're playing Austria and you upgrade your UU into a Light Tank.

Is there a pure SQL way to add a new promotion that gives a ranged attack bonus against just melee ships?

You mean something like this:

Spoiler :

INSERT INTO UnitPromotions_UnitCombatMods
(PromotionType, UnitCombatType, Modifier)
VALUES
('PROMOTION_BLANK', 'UNITCOMBAT_NAVALMELEE', 50);
 
Has there been any chances to the aggressiveness of the AI early game recently, I updated my version and it feels like the ai are much more passive early on, thanks
 
Has there been any chances to the aggressiveness of the AI early game recently, I updated my version and it feels like the ai are much more passive early on, thanks

I've fixed it for next version.
 
How do you disable the AI hate for the civ in the lead in the latter eras?

I can't recall what needs to be edited to change that.
 
How do you disable the AI hate for the civ in the lead in the latter eras?

I can't recall what needs to be edited to change that.

(1) Community Patch > Core Files > Core Changes > DiploAIOptions.sql, set DIPLO_AI_NO_VICTORY_COMPETITION to 1 and save the file.
 
Is it possible to know the changes to aggression values and where to place them? I’d love to be able to use them with ilteroi’s new DLL.

According to Github I've made over 7,000 line changes for next version. Best to wait. :)
 
Border's Iron Curtain policy provides for a free courthouse and immediate annexation. Dows this mean that the city isn't supposed to have any turns of resistance?

I'm asking because I've taken the policy in a game and am still getting resistance. Free courthouses aren't worth that much overall.
 
Border's Iron Curtain policy provides for a free courthouse and immediate annexation. Dows this mean that the city isn't supposed to have any turns of resistance?

I'm asking because I've taken the policy in a game and am still getting resistance. Free courthouses aren't worth that much overall.
Good. Courthouses don't remove resistance, they remove annexation.
 
Top Bottom