diff --git a/Sources/CvDLLWidgetData.cpp b/Sources/CvDLLWidgetData.cpp index 796abb570d..f0efdf2502 100644 --- a/Sources/CvDLLWidgetData.cpp +++ b/Sources/CvDLLWidgetData.cpp @@ -3400,22 +3400,24 @@ void CvDLLWidgetData::parseActionHelp(CvWidgetDataStruct &widgetDataStruct, CvWS // BUG - Delete All Action - start else if (GC.getActionInfo(widgetDataStruct.m_iData1).getCommandType() == COMMAND_DELETE) { - const CvUnit* pHeadSelectedUnit = gDLL->getInterfaceIFace()->getHeadSelectedUnit(); - - if (GC.getGame().isOption(GAMEOPTION_DOWNSIZING_IS_PROFITABLE) - //units have to be inside cultural borders - && pHeadSelectedUnit->plot()->getOwner() == pHeadSelectedUnit->getOwner()) + if (GC.getGame().isOption(GAMEOPTION_DOWNSIZING_IS_PROFITABLE)) { - int iGold = 0; + const CvUnit* pHeadSelectedUnit = gDLL->getInterfaceIFace()->getHeadSelectedUnit(); - foreach_(const CvUnit* pSelectedUnit, gDLL->getInterfaceIFace()->getSelectionList()->units()) - { - iGold += pSelectedUnit->calculateScrapValue(); - } - if (iGold != 0) + //units have to be inside cultural borders + if (pHeadSelectedUnit->plot()->getOwner() == pHeadSelectedUnit->getOwner()) { - szBuffer.append(NEWLINE); - szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOLD_FOR_DISBANDING", iGold)); + int iGold = 0; + + foreach_(const CvUnit* pSelectedUnit, gDLL->getInterfaceIFace()->getSelectionList()->units()) + { + iGold += pSelectedUnit->calculateScrapValue(); + } + if (iGold != 0) + { + szBuffer.append(NEWLINE); + szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOLD_FOR_DISBANDING", iGold)); + } } } } diff --git a/Sources/CvInfoUtil.h b/Sources/CvInfoUtil.h index 3ef39b81f6..6d74b25fd6 100644 --- a/Sources/CvInfoUtil.h +++ b/Sources/CvInfoUtil.h @@ -29,7 +29,6 @@ struct CvInfoUtil { foreach_(const WrappedVar* wrapper, m_wrappedVars) delete wrapper; - m_wrappedVars.clear(); } void initDataMembers() @@ -160,7 +159,7 @@ struct CvInfoUtil /// Enum wrapper ///============== - template + template struct EnumWrapper : WrappedVar { friend struct CvInfoUtil; @@ -180,17 +179,14 @@ struct CvInfoUtil CheckSum(iSum, ref()); } - void readXml(CvXMLLoadUtility* pXML) + virtual void readXml(CvXMLLoadUtility* pXML) { - CvXMLLoadUtility::SetOptionalInfoType(pXML, ref(), m_tag.c_str()); + CvXMLLoadUtility::SetOptionalInfoType(pXML, ref(), m_tag.c_str()); } - void copyNonDefaults(const WrappedVar* source) + virtual void copyNonDefaults(const WrappedVar* source) { - if (delayedResolutionOption == USE_DELAYED_RESOLUTION) - GC.copyNonDefaultDelayedResolution(reinterpret_cast(&ref()), reinterpret_cast(&(static_cast(source)->ref()))); - - else if (ref() == -1) + if (ref() == -1) ref() = static_cast(source)->ref(); } @@ -204,13 +200,43 @@ struct CvInfoUtil Enum_t& ref() const { return *static_cast(m_ptr); } }; + ///====================================== + /// Enum with delayed resolution wrapper + ///====================================== + + template + struct EnumWithDelayedResolutionWrapper : EnumWrapper + { + friend struct CvInfoUtil; + + protected: + EnumWithDelayedResolutionWrapper(Enum_t& var, const wchar_t* tag) + : EnumWrapper(var, tag) + {} + + void uninitVar() + { + GC.removeDelayedResolution(reinterpret_cast(&ref())); + } + + void readXml(CvXMLLoadUtility* pXML) + { + CvXMLLoadUtility::SetOptionalInfoType(pXML, ref(), m_tag.c_str()); + } + + void copyNonDefaults(const WrappedVar* source) + { + GC.copyNonDefaultDelayedResolution(reinterpret_cast(&ref()), reinterpret_cast(&(static_cast(source)->ref()))); + } + }; + template CvInfoUtil& addEnum(Enum_t& var, const wchar_t* tag) { if (GC.isDelayedResolutionRequired(m_eInfoClass, InfoClassTraits::InfoClassEnum)) - m_wrappedVars.push_back(new EnumWrapper(var, tag)); + m_wrappedVars.push_back(new EnumWithDelayedResolutionWrapper(var, tag)); else - m_wrappedVars.push_back(new EnumWrapper(var, tag)); + m_wrappedVars.push_back(new EnumWrapper(var, tag)); return *this; } @@ -361,13 +387,6 @@ struct CvInfoUtil { ref().copyNonDefaultDelayedResolution(static_cast(source)->ref()); } - - void checkSum(uint32_t& iSum) const - { - CheckSumC(iSum, ref()); - } - - IDValueMap_T& ref() const { return *static_cast(m_ptr); } }; template diff --git a/Sources/CvPlayerAI.cpp b/Sources/CvPlayerAI.cpp index bfae1873ec..3744648ec5 100644 --- a/Sources/CvPlayerAI.cpp +++ b/Sources/CvPlayerAI.cpp @@ -635,8 +635,6 @@ void CvPlayerAI::AI_doTurnUnitsPost() foreach_(CvUnit * unit, units_safe() | filtered(CvUnit::fn::isPromotionReady())) { unit->AI_promote(); - // Upgrade replaces the original unit with a new one, so old unit must be killed - unit->doDelayedDeath(); } } @@ -727,22 +725,22 @@ void CvPlayerAI::AI_doTurnUnitsPost() return; } - const bool bAnyWar = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0); + const bool bAnyWar = GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0; const int64_t iStartingGold = getGold(); const int iTargetGold = AI_goldTarget(); - int64_t iUpgradeBudget = (AI_goldToUpgradeAllUnits() / (bAnyWar ? 1 : 2)); + int64_t iUpgradeBudget = AI_goldToUpgradeAllUnits() / (bAnyWar ? 1 : 2); iUpgradeBudget = std::min(iUpgradeBudget, (iStartingGold - iTargetGold < iUpgradeBudget) ? (iStartingGold - iTargetGold) : iStartingGold / 2); iUpgradeBudget = std::max(0, iUpgradeBudget); - if (gPlayerLogLevel > 2) + if (AI_isFinancialTrouble()) { - logBBAI(" %S calculates upgrade budget of %d from %d current gold, %d target", getCivilizationDescription(0), iUpgradeBudget, iStartingGold, iTargetGold); + iUpgradeBudget /= 3; } - if (AI_isFinancialTrouble()) + if (gPlayerLogLevel > 2) { - iUpgradeBudget /= 3; + logBBAI(" %S calculates upgrade budget of %I64d from %I64d current gold, %d target", getCivilizationDescription(0), iUpgradeBudget, iStartingGold, iTargetGold); } // Always willing to upgrade 1 unit if we have the money @@ -896,7 +894,7 @@ void CvPlayerAI::AI_doTurnUnitsPost() if (gPlayerLogLevel > 2 && iStartingGold - getGold() > 0) { logBBAI( - " %S spends %d on unit upgrades out of budget of %d, %d effective gold remaining", + " %S spends %I64d on unit upgrades out of budget of %I64d, %I64d effective gold remaining", getCivilizationDescription(0), iStartingGold - getGold(), iUpgradeBudget, getGold() ); } @@ -10893,19 +10891,13 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* iValue = 0; break; } - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD 06/12/09 jdog5000 */ - /* */ - /* Unit AI */ - /************************************************************************************************/ + iFastMoverMultiplier = AI_isDoStrategy(AI_STRATEGY_FASTMOVERS) ? 3 : 1; iValue += iCombatValue; - iValue += ((iCombatValue * (kUnitInfo.getMoves() - 1) * iFastMoverMultiplier) / 3); // K-Mod put in -1 ! - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD END */ - /************************************************************************************************/ + iValue += ((iCombatValue * (kUnitInfo.getMoves() - 1) * iFastMoverMultiplier) / 3); iValue += ((iCombatValue * kUnitInfo.getWithdrawalProbability()) / 100); + if (kUnitInfo.getCombatLimit() < 100) { iValue -= (iCombatValue * (125 - kUnitInfo.getCombatLimit())) / 100; @@ -11422,12 +11414,7 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* iValue += ((iCombatValue * kUnitInfo.getUnitCombatModifier(iI) * AI_getUnitCombatWeight((UnitCombatTypes)iI)) / 10000); iValue += ((iCombatValue * (kUnitInfo.getDefenderUnitCombat(iI) ? 50 : 0)) / 100); } - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD 03/20/10 jdog5000 */ - /* */ - /* War strategy AI */ - /************************************************************************************************/ - //iValue += (kUnitInfo.getInterceptionProbability() * 3); + if (kUnitInfo.getInterceptionProbability() > 0) { int iTempValue = kUnitInfo.getInterceptionProbability(); @@ -11488,15 +11475,8 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* break; } } - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD 03/08/10 jdog5000 */ - /* */ - /* Victory Strategy AI */ - /************************************************************************************************/ + if (AI_isDoVictoryStrategy(AI_VICTORY_CULTURE2)) - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD END */ - /************************************************************************************************/ { int iTempValue = 0; for (iI = 0; iI < GC.getNumReligionInfos(); iI++) @@ -11515,19 +11495,11 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* if (kUnitInfo.getCorporationSpreads(iI) > 0) { iValue += (5 * kUnitInfo.getCorporationSpreads(iI)) / 2; - /************************************************************************************************/ - /* UNOFFICIAL_PATCH 06/03/09 jdog5000 */ - /* */ - /* Bugfix */ - /************************************************************************************************/ - // Fix potential crash, probably would only happen in mods + if (pArea != NULL) { iValue += 300 / std::max(1, pArea->countHasCorporation((CorporationTypes)iI, getID())); } - /************************************************************************************************/ - /* UNOFFICIAL_PATCH END */ - /************************************************************************************************/ } } } @@ -11566,6 +11538,7 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* break; case UNITAI_ESCORT_SEA: + { iValue += iCombatValue; iValue += iCombatValue * kUnitInfo.getMoves(); iValue += kUnitInfo.getInterceptionProbability() * 3; @@ -11573,21 +11546,13 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* { iValue += 200; } - /************************************************************************************************/ - /* UNOFFICIAL_PATCH 06/03/09 jdog5000 */ - /* */ - /* General AI */ - /************************************************************************************************/ - // Boats which can't be seen don't play defense, don't make good escorts + // Boats which can't be seen don't play defense, don't make good escorts if (kUnitInfo.getInvisibleType() != NO_INVISIBLE) { iValue /= 2; } - /************************************************************************************************/ - /* UNOFFICIAL_PATCH END */ - /************************************************************************************************/ break; - + } case UNITAI_EXPLORE_SEA: { int iExploreValue = 100; @@ -11614,21 +11579,14 @@ int CvPlayerAI::AI_unitValue(UnitTypes eUnit, UnitAITypes eUnitAI, const CvArea* case UNITAI_SETTLER_SEA: case UNITAI_MISSIONARY_SEA: case UNITAI_SPY_SEA: + { iValue += (iCombatValue / 2); iValue += (kUnitInfo.getMoves() * 200); iValue += (kUnitInfo.getCargoSpace() * 300); - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD 05/18/09 jdog5000 */ - /* */ - /* City AI */ - /************************************************************************************************/ - // Never build galley transports when ocean faring ones exist (issue mainly for Carracks) + // Never build galley transports when ocean faring ones exist (issue mainly for Carracks) iValue /= (1 + AI_unitImpassableCount(eUnit)); - /************************************************************************************************/ - /* BETTER_BTS_AI_MOD END */ - /************************************************************************************************/ break; - + } case UNITAI_CARRIER_SEA: iValue += iCombatValue; iValue += (kUnitInfo.getMoves() * 50); diff --git a/Sources/CvUnit.cpp b/Sources/CvUnit.cpp index f474b8e8b6..befbccd541 100644 --- a/Sources/CvUnit.cpp +++ b/Sources/CvUnit.cpp @@ -1484,57 +1484,66 @@ void CvUnit::killUnconditional(bool bDelay, PlayerTypes ePlayer, bool bMessaged) { foreach_(CvUnit* unitX, pPlot->units()) { - if (unitX->getTransportUnit() == this && !unitX->isDelayedDeath()) + if (unitX == this || unitX->getTransportUnit() != this) + { + continue; + } + if (unitX->isDelayedDeath()) + { + // Should mean that we are on the second kill pass of transporting unit (this), + // i.e. this cargo unit (unitX) already failed to survive on the first kill pass where bDelay=True. + FAssertMsg(!bDelay, "bDelay should in theory always be false here... I think"); + unitX->kill(bDelay, NO_PLAYER, true); + continue; + } + + /* Toffer ToDo - revise + if (getCaptureUnitType() != NO_UNIT && getCapturingPlayer() != NO_PLAYER + && unitX->getCaptureUnitType() != NO_UNIT && !GET_PLAYER(getCapturingPlayer()).isNPC() + && GC.getGame().getSorenRandNum(2, "50% prefer safe capture over deadly escape.") == 0) + { + unitX->setCapturingPlayer(getCapturingPlayer()); + unitX->setCapturingUnit(getCapturingUnit()); + unitX->kill(bDelay, ePlayer, bMessaged); + continue; + } + */ + if (GC.getGame().getSorenRandNum(pPlot->isWater() ? 5 : 2, "Unit Survives Drowning") == 0) { - if (pPlot->isValidDomainForLocation(*unitX)) - { - unitX->setCapturingPlayer(NO_PLAYER); - unitX->setCapturingUnit(this); - } bool bSurvived = false; + std::vector validPlots; - if (GC.getDefineINT("WAR_PRIZES") && GC.getGame().getSorenRandNum(10, "Unit Survives Drowning") == 0) + foreach_(const CvPlot* pAdjacentPlot, plot()->adjacent()) { - std::vector validPlots; - - foreach_(const CvPlot* pAdjacentPlot, plot()->adjacent()) - { - if (unitX->canMoveThrough(pAdjacentPlot, false)) - { - validPlots.push_back(pAdjacentPlot); - bSurvived = true; - } - } - if (bSurvived) + if (unitX->canMoveThrough(pAdjacentPlot, false)) { - const CvPlot* rescuePlot = validPlots[GC.getGame().getSorenRandNum(validPlots.size(), "Event pick plot")]; - - FAssertMsg(rescuePlot != NULL, "rescuePlot is expected to be a valid plot!"); - unitX->setXY(rescuePlot->getX(), rescuePlot->getY()); - unitX->setDamage(GC.getGame().getSorenRandNum(unitX->getHP(), "Survival Damage"), NO_PLAYER); - AddDLLMessage( - unitX->getOwner(), false, GC.getEVENT_MESSAGE_TIME(), - gDLL->getText("TXT_KEY_MISC_UNIT_SURVIVED_TRANSPORT_SINKING", unitX->getNameKey(), getNameKey()), - NULL, MESSAGE_TYPE_MINOR_EVENT - ); + validPlots.push_back(pAdjacentPlot); + bSurvived = true; } } - if (!bSurvived) + if (bSurvived) { + const CvPlot* rescuePlot = validPlots[GC.getGame().getSorenRandNum(validPlots.size(), "Event pick plot")]; + + FAssertMsg(rescuePlot != NULL, "rescuePlot is expected to be a valid plot!"); + unitX->setXY(rescuePlot->getX(), rescuePlot->getY()); + unitX->setDamage(GC.getGame().getSorenRandNum(std::min(unitX->getMaxHP() * 2/3, unitX->getHP()), "Survival Damage"), NO_PLAYER); AddDLLMessage( - eOwner, true, GC.getEVENT_MESSAGE_TIME(), - gDLL->getText("TXT_KEY_MISC_UNIT_DROWNED", unitX->getNameKey()), - GC.getEraInfo(GC.getGame().getCurrentEra()).getAudioUnitDefeatScript(), - MESSAGE_TYPE_INFO, NULL, GC.getCOLOR_RED(), getX(), getY() + unitX->getOwner(), false, GC.getEVENT_MESSAGE_TIME(), + gDLL->getText("TXT_KEY_MISC_UNIT_SURVIVED_TRANSPORT_SINKING", unitX->getNameKey(), getNameKey()), + NULL, MESSAGE_TYPE_MINOR_EVENT ); - bMessaged = true; - if (bDelay) - { - unitX->unload(); - } - unitX->kill(bDelay, ePlayer, bMessaged); + continue; } } + AddDLLMessage( + eOwner, true, GC.getEVENT_MESSAGE_TIME(), + gDLL->getText("TXT_KEY_MISC_UNIT_DROWNED", unitX->getNameKey()), + GC.getEraInfo(GC.getGame().getCurrentEra()).getAudioUnitDefeatScript(), + MESSAGE_TYPE_INFO, NULL, GC.getCOLOR_RED(), getX(), getY() + ); + bMessaged = true; + unitX->kill(bDelay, ePlayer, bMessaged); } } @@ -4364,7 +4373,6 @@ void CvUnit::updateCombat(bool bQuick, CvUnit* pSelectedDefender, bool bSamePlot } CvEventReporter::getInstance().combatResult(this, pDefender); - //CvUnitInfo* pDefenderUnitInfo = &(pDefender->getUnitInfo()); PlayerTypes eDefenderUnitPlayer = pDefender->getOwner(); UnitTypes eDefenderUnitType = pDefender->getUnitType(); @@ -12012,12 +12020,7 @@ bool CvUnit::upgradeAvailable(UnitTypes eFromUnit, UnitTypes eToUnit) const bool CvUnit::canUpgrade(UnitTypes eUnit, bool bTestVisible) const { - if (eUnit == NO_UNIT) - { - return false; - } - - if (!isReadyForUpgrade()) + if (eUnit == NO_UNIT || !isReadyForUpgrade()) { return false; } @@ -12054,15 +12057,7 @@ bool CvUnit::canUpgrade(UnitTypes eUnit, bool bTestVisible) const bool CvUnit::isReadyForUpgrade() const { - if (!canMove()) - { - return false; - } - if (plot()->getTeam() != getTeam() && !isUpgradeAnywhere() && !GET_PLAYER(getOwner()).isUpgradeAnywhere()) - { - return false; - } - return true; + return canMove() && (plot()->getTeam() == getTeam() || isUpgradeAnywhere() || GET_PLAYER(getOwner()).isUpgradeAnywhere()); } // has upgrade is used to determine if an upgrade is possible, @@ -19431,23 +19426,17 @@ void CvUnit::setTransportUnit(CvUnit* pTransportUnit) m_transportUnit.reset(); getGroup()->setActivityType(ACTIVITY_AWAKE); -/************************************************************************************************/ -/* Afforess Start 09/01/10 */ -/* */ -/* After a Barb Transport is done, set it to attack AI */ -/************************************************************************************************/ + + // After a Barb Transport is done, set it to attack AI if (pOldTransportUnit != NULL && !pOldTransportUnit->hasCargo()) { - if (pOldTransportUnit->getDomainType() == DOMAIN_SEA && pOldTransportUnit->getOwner() == BARBARIAN_PLAYER) + if (pOldTransportUnit->getDomainType() == DOMAIN_SEA && pOldTransportUnit->isHominid()) { pOldTransportUnit->AI_setUnitAIType(UNITAI_ATTACK_SEA); } } -/************************************************************************************************/ -/* Afforess END */ -/************************************************************************************************/ - // Koshling - have the AI prioritize regrouping with other units when unloaded + // Koshling - have the AI prioritize regrouping with other units when unloaded getGroup()->AI_setMissionAI(MISSIONAI_REGROUP, NULL, NULL); }