/// Is this a valid Promotion for the UnitCombatType? bool IsPromotionValidForUnitCombatType(PromotionTypes ePromotion, UnitTypes eUnit) { CvUnitEntry* unitInfo = GC.getUnitInfo(eUnit); CvPromotionEntry* promotionInfo = GC.getPromotionInfo(ePromotion); if(unitInfo == NULL || promotionInfo == NULL) return false; // No combat class (civilians) if(unitInfo->GetUnitCombatType() == NO_UNITCOMBAT) { return false; } // Combat class not valid for this Promotion #if defined(MOD_GLOBAL_PROMOTION_CLASSES) if(!(promotionInfo->GetUnitCombatClass(unitInfo->GetUnitPromotionType()))) #else if(!(promotionInfo->GetUnitCombatClass(unitInfo->GetUnitCombatType()))) #endif { return false; } return true; }
/// Is this a valid Promotion for this civilian? bool IsPromotionValidForCivilianUnitType(PromotionTypes ePromotion, UnitTypes eUnit) { CvPromotionEntry* promotionInfo = GC.getPromotionInfo(ePromotion); if(promotionInfo == NULL) return false; if(!(promotionInfo->GetCivilianUnitType((int)eUnit))) { return false; } return true; }
/// Total cargo space from all free promotions int CvUnitEntry::GetCargoSpace() const { int rtnValue = 0; for(int iLoop = 0; iLoop < GC.getNumPromotionInfos(); iLoop++) { const PromotionTypes ePromotion = static_cast<PromotionTypes>(iLoop); CvPromotionEntry* pkPromotionInfo = GC.getPromotionInfo(ePromotion); if(pkPromotionInfo) { if(GetFreePromotions(iLoop)) { const int iVal = pkPromotionInfo->GetCargoChange(); rtnValue += iVal; } } } return rtnValue; }
/// Is this a valid Promotion for the UnitCombatType? bool IsPromotionValidForUnitCombatType(PromotionTypes ePromotion, UnitTypes eUnit) { CvUnitEntry* unitInfo = GC.getUnitInfo(eUnit); CvPromotionEntry* promotionInfo = GC.getPromotionInfo(ePromotion); if(unitInfo == NULL || promotionInfo == NULL) return false; // No combat class (civilians) if(unitInfo->GetUnitCombatType() == NO_UNITCOMBAT) { return false; } // Combat class not valid for this Promotion if(!(promotionInfo->GetUnitCombatClass(unitInfo->GetUnitCombatType()))) { return false; } return true; }
/// Update military Power void CvUnitEntry::DoUpdatePower() { int iPower; // *************** // Main Factors - Strength & Moves // *************** // We want a Unit that has twice the strength to be roughly worth 3x as much with regards to Power iPower = int(pow((double) GetCombat(), 1.5)); // Ranged Strength int iRangedStrength = int(pow((double) GetRangedCombat(), 1.45)); // Naval ranged attacks are less useful if(GetDomainType() == DOMAIN_SEA) { iRangedStrength /= 2; } if(iRangedStrength > 0) { iPower = iRangedStrength; } // We want Movement rate to be important, but not a dominating factor; a Unit with double the moves of a similarly-strengthed Unit should be ~1.5x as Powerful iPower = int((float) iPower * pow((double) GetMoves(), 0.3)); // *************** // Other modifiers // *************** // Suicide Units are obviously less useful if(IsSuicide()) { iPower /= 2; } // Nukes are cool if(GetNukeDamageLevel() > 0) { iPower += 4000; } // *************** // Promotion modifiers // *************** int iTemp; int iLoop; for(int iPromotionLoop = 0; iPromotionLoop < GC.getNumPromotionInfos(); iPromotionLoop++) { CvPromotionEntry* kPromotion = GC.getPromotionInfo((PromotionTypes)iPromotionLoop); if(kPromotion == NULL) continue; if(GetFreePromotions(iPromotionLoop)) { // City Attack - add half of the bonus if(kPromotion->GetCityAttackPercent() > 0) { iTemp = (iPower * kPromotion->GetCityAttackPercent() / 2); iTemp /= 100; iPower += iTemp; } // Attack - add half of the bonus if(kPromotion->GetAttackMod() > 0) { iTemp = (iPower * kPromotion->GetAttackMod() / 2); iTemp /= 100; iPower += iTemp; } // Defense - add half of the bonus if(kPromotion->GetDefenseMod() > 0) { iTemp = (iPower * kPromotion->GetDefenseMod() / 2); iTemp /= 100; iPower += iTemp; } // Paradrop - add 25% if(kPromotion->GetDropRange() > 0) { iTemp = iPower; iTemp /= 4; iPower += iTemp; } // Blitz - add 20% if(kPromotion->IsBlitz()) { iTemp = iPower; iTemp /= 5; iPower += iTemp; } // Set Up For Ranged Attack - reduce by 20% if(kPromotion->IsMustSetUpToRangedAttack()) { iTemp = iPower; iTemp /= 5; iPower -= iTemp; } // Only Defensive - reduce by 25%, but only if the Unit has no ranged capability if(kPromotion->IsOnlyDefensive() && GetRangedCombat() == 0) { iTemp = iPower; iTemp /= 4; iPower -= iTemp; } for(iLoop = 0; iLoop < GC.getNumTerrainInfos(); iLoop++) { // Terrain Attack - add one quarter of the bonus if(kPromotion->GetTerrainAttackPercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetTerrainAttackPercent(iLoop) / 4); iTemp /= 100; iPower += iTemp; } // Terrain Defense - add one quarter of the bonus if(kPromotion->GetTerrainDefensePercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetTerrainDefensePercent(iLoop) / 4); iTemp /= 100; iPower += iTemp; } } for(iLoop = 0; iLoop < GC.getNumFeatureInfos(); iLoop++) { // Feature Attack - add one quarter of the bonus if(kPromotion->GetFeatureAttackPercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetFeatureAttackPercent(iLoop) / 4); iTemp /= 100; iPower += iTemp; } // Feature Defense - add one quarter of the bonus if(kPromotion->GetFeatureDefensePercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetFeatureDefensePercent(iLoop) / 4); iTemp /= 100; iPower += iTemp; } } for(iLoop = 0; iLoop < GC.getNumUnitCombatClassInfos(); iLoop++) { // Unit Combat Class (e.g. Pikemen) - add one quarter of the bonus if(kPromotion->GetUnitCombatModifierPercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetUnitCombatModifierPercent(iLoop) / 4); iTemp /= 100; iPower += iTemp; } } for(iLoop = 0; iLoop < GC.getNumUnitClassInfos(); iLoop++) { // Unit Class (e.g. bonus ONLY against Galleys) - add one eighth of the bonus // We're assuming here that the bonus against the other Unit is at least going to be somewhat useful - trust the XML! :o if(kPromotion->GetUnitClassModifierPercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetUnitClassModifierPercent(iLoop) / 8); iTemp /= 100; iPower += iTemp; } // Unit Class Attack - one tenth of the bonus if(kPromotion->GetUnitClassAttackModifier(iLoop) > 0) { iTemp = (iPower * kPromotion->GetUnitClassAttackModifier(iLoop) / 10); iTemp /= 100; iPower += iTemp; } // Unit Class Defense - one tenth of the bonus if(kPromotion->GetUnitClassDefenseModifier(iLoop) > 0) { iTemp = (iPower * kPromotion->GetUnitClassDefenseModifier(iLoop) / 10); iTemp /= 100; iPower += iTemp; } } for(iLoop = 0; iLoop < NUM_DOMAIN_TYPES; iLoop++) { // Domain - add one quarter of the bonus if(kPromotion->GetDomainModifierPercent(iLoop) > 0) { iTemp = (iPower * kPromotion->GetDomainModifierPercent(iLoop) / 4); iTemp /= 100; iPower += iTemp; } } } } // Debug output //char temp[256]; //sprintf(temp, "%s: %i\n", GetDescription(), iPower); //OutputDebugString(temp); m_iCachedPower = iPower; }
bool isPromotionValid(PromotionTypes ePromotion, UnitTypes eUnit, bool bLeader, bool bTestingPrereq) { CvUnitEntry* unitInfo = GC.getUnitInfo(eUnit); CvPromotionEntry* promotionInfo = GC.getPromotionInfo(ePromotion); if(unitInfo == NULL || promotionInfo == NULL) return false; // Can this Promotion not be chosen through normal leveling? if(!bTestingPrereq && promotionInfo->IsCannotBeChosen()) { return false; } // If a Unit gets a Promotion for free then hand it out, no questions asked if(unitInfo->GetFreePromotions(ePromotion)) { return true; } // If this isn't a combat Unit, no Promotion if(unitInfo->GetUnitCombatType() == NO_UNITCOMBAT) { return false; } // Is this a valid Promotion for the UnitCombatType? if(!::IsPromotionValidForUnitCombatType(ePromotion, eUnit)) { return false; } if(!bLeader && promotionInfo->IsLeader()) { return false; } // If the Unit only has one move then Blitz is not useful if(unitInfo->GetMoves() == 1) { if(promotionInfo->IsBlitz()) { return false; } } // Promotion Prereqs if(NO_PROMOTION != promotionInfo->GetPrereqPromotion()) { if(!isPromotionValid((PromotionTypes)promotionInfo->GetPrereqPromotion(), eUnit, bLeader, true)) { return false; } } PromotionTypes ePrereq1 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion1(); PromotionTypes ePrereq2 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion2(); PromotionTypes ePrereq3 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion3(); PromotionTypes ePrereq4 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion4(); PromotionTypes ePrereq5 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion5(); PromotionTypes ePrereq6 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion6(); PromotionTypes ePrereq7 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion7(); PromotionTypes ePrereq8 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion8(); PromotionTypes ePrereq9 = (PromotionTypes)promotionInfo->GetPrereqOrPromotion9(); if(ePrereq1 != NO_PROMOTION || ePrereq2 != NO_PROMOTION || ePrereq3 != NO_PROMOTION || ePrereq4 != NO_PROMOTION || ePrereq5 != NO_PROMOTION || ePrereq6 != NO_PROMOTION || ePrereq7 != NO_PROMOTION || ePrereq8 != NO_PROMOTION || ePrereq9 != NO_PROMOTION) { bool bValid = false; if(!bValid) { if(NO_PROMOTION != ePrereq1 && isPromotionValid(ePrereq1, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq2 && isPromotionValid(ePrereq2, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq3 && isPromotionValid(ePrereq3, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq4 && isPromotionValid(ePrereq4, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq5 && isPromotionValid(ePrereq5, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq6 && isPromotionValid(ePrereq6, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq7 && isPromotionValid(ePrereq7, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq8 && isPromotionValid(ePrereq8, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { if(NO_PROMOTION != ePrereq9 && isPromotionValid(ePrereq9, eUnit, bLeader, true)) { bValid = true; } } if(!bValid) { return false; } } return true; }
//------------------------------------------------------------------------------------------------------ // // FUNCTION: SetGlobalActionInfo(CvActionInfo** ppActionInfo, int* iNumVals) // // PURPOSE : Takes the szTagName parameter and if it exists in the xml it loads the ppActionInfo // with the value under it and sets the value of the iNumVals parameter to the total number // of occurances of the szTagName tag in the xml. // //------------------------------------------------------------------------------------------------------ bool CvDllDatabaseUtility::SetGlobalActionInfo() { cvStopWatch kPerfTest("SetGlobalActionInfo", "xml-perf.log"); LogMsg("SetGlobalActionInfo\n"); typedef std::vector<CvActionInfo*> ActionInfoVector; ActionInfoVector& actionInfos = GC.getActionInfo(); //First, clear out action info data for(ActionInfoVector::iterator it = actionInfos.begin(); it != actionInfos.end(); ++it) { CvActionInfo* pActionInfo = (*it); delete pActionInfo; } actionInfos.clear(); const int iNumMissionTypes = CvTypes::getNUM_MISSION_TYPES(); //Verify action counts if(!(NUM_INTERFACEMODE_TYPES > 0)) { LogMsg("NUM_INTERFACE_TYPES is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(GC.getNumBuildInfos() > 0)) { LogMsg("GC.getNumBuildInfos() is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(GC.getNumPromotionInfos() > 0)) { LogMsg("GC.getNumPromotionInfos() is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(GC.getNumSpecialistInfos() > 0)) { LogMsg("GC.getNumSpecialistInfos() is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(NUM_CONTROL_TYPES > 0)) { LogMsg("NUM_CONTROL_TYPES is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(GC.getNumAutomateInfos() > 0)) { LogMsg("GC.getNumAutomateInfos() is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(NUM_COMMAND_TYPES > 0)) { LogMsg("NUM_COMMAND_TYPES is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } if(!(iNumMissionTypes > 0)) { LogMsg("NUM_MISSION_TYPES is not greater than zero in CvDllDatabaseUtility::SetGlobalActionInfo."); } int iEstimatedNumActionInfos = NUM_INTERFACEMODE_TYPES + GC.getNumBuildInfos() + GC.getNumPromotionInfos() + GC.getNumSpecialistInfos() + NUM_CONTROL_TYPES + NUM_COMMAND_TYPES + GC.getNumAutomateInfos() + iNumMissionTypes; int* piBuffer = FNEW(int[iEstimatedNumActionInfos * 4], c_eCiv5GameplayDLL, 0); memset(piBuffer,0, sizeof(int) * iEstimatedNumActionInfos * 4); int* piIndexList = piBuffer + iEstimatedNumActionInfos * 0; //FNEW(int[iNumActionInfos], c_eCiv5GameplayDLL, 0); int* piPriorityList = piBuffer + iEstimatedNumActionInfos * 1; //FNEW(int[iNumActionInfos], c_eCiv5GameplayDLL, 0); int* piActionInfoTypeList = piBuffer + iEstimatedNumActionInfos * 2; //FNEW(int[iNumActionInfos], c_eCiv5GameplayDLL, 0); int* piOrderedIndex = piBuffer + iEstimatedNumActionInfos * 3; //FNEW(int[iNumActionInfos], c_eCiv5GameplayDLL, 0); //Gather all available infos, checking for NULL entries as they may have been removed. int iTotalActionInfoCount = 0; int i = 0; for(i=0; i<NUM_COMMAND_TYPES; i++) { CvCommandInfo* commandInfo = GC.getCommandInfo((CommandTypes)i); if(commandInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = commandInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_COMMAND; iTotalActionInfoCount++; } } for(i=0; i<NUM_INTERFACEMODE_TYPES; i++) { CvInterfaceModeInfo* interfaceInfo = GC.getInterfaceModeInfo((InterfaceModeTypes)i); if(interfaceInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = interfaceInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_INTERFACEMODE; iTotalActionInfoCount++; } } for(i=0; i<GC.getNumBuildInfos(); i++) { CvBuildInfo* buildInfo = GC.getBuildInfo((BuildTypes)i); if(buildInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = buildInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_BUILD; iTotalActionInfoCount++; } } for(i=0; i<GC.getNumPromotionInfos(); i++) { CvPromotionEntry* promotionEntry = GC.getPromotionInfo((PromotionTypes)i); if(promotionEntry) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = promotionEntry->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_PROMOTION; iTotalActionInfoCount++; } } for(i=0; i<GC.getNumSpecialistInfos(); i++) { CvSpecialistInfo* specialistInfo = GC.getSpecialistInfo((SpecialistTypes)i); if(specialistInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = specialistInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_SPECIALIST; iTotalActionInfoCount++; } } for(i=0; i<NUM_CONTROL_TYPES; i++) { CvControlInfo* controlInfo = GC.getControlInfo((ControlTypes)i); if(controlInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = controlInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_CONTROL; iTotalActionInfoCount++; } } for(i=0; i<GC.getNumAutomateInfos(); i++) { CvAutomateInfo* automateInfo = GC.getAutomateInfo(i); if(automateInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = automateInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_AUTOMATE; iTotalActionInfoCount++; } } for(i=0; i<iNumMissionTypes; i++) { CvMissionInfo* missionInfo = GC.getMissionInfo((MissionTypes)i); if(missionInfo) { piIndexList[iTotalActionInfoCount] = i; piPriorityList[iTotalActionInfoCount] = missionInfo->getOrderPriority(); piActionInfoTypeList[iTotalActionInfoCount] = ACTIONSUBTYPE_MISSION; iTotalActionInfoCount++; } } //Preallocate actionInfos.reserve(iTotalActionInfoCount); //Sort and add action infos. orderHotkeyInfo(&piOrderedIndex, piPriorityList, iTotalActionInfoCount); for(i = 0; i < iTotalActionInfoCount; i++) { CvActionInfo* pActionInfo = FNEW(CvActionInfo, c_eCiv5GameplayDLL, 0); CvAssert(piIndexList[piOrderedIndex[i]] != -1); pActionInfo->setOriginalIndex(piIndexList[piOrderedIndex[i]]); pActionInfo->setSubType((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]]); if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_COMMAND) { GC.getCommandInfo((CommandTypes)piIndexList[piOrderedIndex[i]])->setActionInfoIndex(i); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_INTERFACEMODE) { GC.getInterfaceModeInfo((InterfaceModeTypes)piIndexList[piOrderedIndex[i]])->setActionInfoIndex(i); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_BUILD) { GC.getBuildInfo((BuildTypes)piIndexList[piOrderedIndex[i]])->setMissionType(GC.getInfoTypeForString("MISSION_BUILD")); GC.getBuildInfo((BuildTypes)piIndexList[piOrderedIndex[i]])->setActionInfoIndex(i); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_PROMOTION) { CvPromotionEntry* pkEntry = GC.getPromotionInfo((PromotionTypes)piIndexList[piOrderedIndex[i]]); pkEntry->SetCommandType(GC.getInfoTypeForString("COMMAND_PROMOTION")); pkEntry->setActionInfoIndex(i); CvString strHotKey = pkEntry->CreateHotKeyFromDescription(pkEntry->getHotKey(), pkEntry->isShiftDown(), pkEntry->isAltDown(), pkEntry->isCtrlDown()); pkEntry->setHotKeyDescription(pkEntry->GetDescription(), GC.getCommandInfo((CommandTypes)(pkEntry->GetCommandType()))->GetDescription(), strHotKey); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_SPECIALIST) { CvSpecialistInfo* pkSpecialist = GC.getSpecialistInfo((SpecialistTypes)piIndexList[piOrderedIndex[i]]); pkSpecialist->setMissionType(GC.getInfoTypeForString("MISSION_JOIN")); pkSpecialist->setActionInfoIndex(i); CvString strHotKey = pkSpecialist->CreateHotKeyFromDescription(pkSpecialist->getHotKey(), pkSpecialist->isShiftDown(), pkSpecialist->isAltDown(), pkSpecialist->isCtrlDown()); pkSpecialist->setHotKeyDescription(pkSpecialist->GetDescription(), GC.getMissionInfo((MissionTypes)(pkSpecialist->getMissionType()))->GetDescription(), strHotKey); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_CONTROL) { GC.getControlInfo((ControlTypes)piIndexList[piOrderedIndex[i]])->setActionInfoIndex(i); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_AUTOMATE) { GC.getAutomateInfo(piIndexList[piOrderedIndex[i]])->setActionInfoIndex(i); } else if((ActionSubTypes)piActionInfoTypeList[piOrderedIndex[i]] == ACTIONSUBTYPE_MISSION) { GC.getMissionInfo((MissionTypes)piIndexList[piOrderedIndex[i]])->setActionInfoIndex(i); } GC.getActionInfo().push_back(pActionInfo); } SAFE_DELETE_ARRAY(piBuffer); // SAFE_DELETE_ARRAY(piOrderedIndex); // SAFE_DELETE_ARRAY(piIndexList); // SAFE_DELETE_ARRAY(piPriorityList); // SAFE_DELETE_ARRAY(piActionInfoTypeList); return true; }