Hooks
static bool BeforeCvCity_popOrder(CvCity* self, int iNum, bool bFinish, bool bChoose);static void AfterCvCity_popOrder(CvCity* self, int iNum, bool bFinish, bool bChoose);static void ReplaceCvCity_popOrder(void (*original)(CvCity*, int, bool, bool), CvCity* self, int iNum, bool bFinish, bool bChoose);CivRegisterBefore<CivHooks::CvCity_popOrder>(host, &BeforeCvCity_popOrder);CivRegisterAfter<CivHooks::CvCity_popOrder>(host, &AfterCvCity_popOrder);CivRegisterReplace<CivHooks::CvCity_popOrder>(host, &ReplaceCvCity_popOrder);
Code
12950void CvCity::popOrder(int iNum, bool bFinish, bool bChoose)12951{12952 VALIDATE_OBJECT1295312954 CvPlayerAI& kOwner = GET_PLAYER(getOwner()); //Used often later on1295512956 OrderData* pOrderNode;12957 SpecialistTypes eSpecialist;12958 ProjectTypes eCreateProject;12959 BuildingTypes eConstructBuilding;12960 UnitTypes eTrainUnit;12961 UnitAITypes eTrainAIUnit;12962 bool bWasFoodProduction;12963 bool bStart;12964 bool bMessage;12965 int iCount;12966 int iProductionNeeded;1296712968 bWasFoodProduction = isFoodProduction();1296912970 if(iNum == -1)12971 {12972 iNum = (getOrderQueueLength() - 1);12973 }1297412975 iCount = 0;1297612977 pOrderNode = headOrderQueueNode();1297812979 while(pOrderNode != NULL)12980 {12981 if(iCount == iNum)12982 {12983 break;12984 }1298512986 iCount++;1298712988 pOrderNode = nextOrderQueueNode(pOrderNode);12989 }1299012991 if(pOrderNode == NULL)12992 {12993 return;12994 }1299512996 if(bFinish)12997 {12998 m_iThingsProduced++;12999 }1300013001 if(bFinish && pOrderNode->bSave)13002 {13003 pushOrder(pOrderNode->eOrderType, pOrderNode->iData1, pOrderNode->iData2, true, false, true);13004 }1300513006 eTrainUnit = NO_UNIT;13007 eConstructBuilding = NO_BUILDING;13008 eCreateProject = NO_PROJECT;13009 eSpecialist = NO_SPECIALIST;1301013011 switch(pOrderNode->eOrderType)13012 {13013 case ORDER_TRAIN:13014 eTrainUnit = ((UnitTypes)(pOrderNode->iData1));13015 eTrainAIUnit = ((UnitAITypes)(pOrderNode->iData2));13016 CvAssertMsg(eTrainUnit != NO_UNIT, "eTrainUnit is expected to be assigned a valid unit type");13017 CvAssertMsg(eTrainAIUnit != NO_UNITAI, "eTrainAIUnit is expected to be assigned a valid unit AI type");1301813019 kOwner.changeUnitClassMaking(((UnitClassTypes)(GC.getUnitInfo(eTrainUnit)->GetUnitClassType())), -1);1302013021 if(bFinish)13022 {13023 int iResult = CreateUnit(eTrainUnit, eTrainAIUnit);13024 if(iResult != FFreeList::INVALID_INDEX)13025 {13026#if defined(MOD_EVENTS_CITY)13027 if (MOD_EVENTS_CITY) {13028 GAMEEVENTINVOKE_HOOK(GAMEEVENT_CityTrained, getOwner(), GetID(), iResult, false, false);13029 } else {13030#endif13031 ICvEngineScriptSystem1* pkScriptSystem = gDLL->GetScriptSystem();13032 if (pkScriptSystem) 13033 {13034 CvLuaArgsHandle args;13035 args->Push(getOwner());13036 args->Push(GetID());13037 args->Push(GET_PLAYER(getOwner()).getUnit(iResult)->GetID()); // This is probably just iResult13038 args->Push(false); // bGold13039 args->Push(false); // bFaith/bCulture1304013041 bool bResult;13042 LuaSupport::CallHook(pkScriptSystem, "CityTrained", args.get(), bResult);13043 }13044#if defined(MOD_EVENTS_CITY)13045 }13046#endif1304713048 iProductionNeeded = getProductionNeeded(eTrainUnit) * 100;1304913050 // max overflow is the value of the item produced (to eliminate prebuild exploits)13051 int iOverflow = getUnitProductionTimes100(eTrainUnit) - iProductionNeeded;13052 int iMaxOverflow = std::max(iProductionNeeded, getCurrentProductionDifferenceTimes100(false, false));13053 int iLostProduction = std::max(0, iOverflow - iMaxOverflow);13054 iOverflow = std::min(iMaxOverflow, iOverflow);13055 if(iOverflow > 0)13056 {13057 changeOverflowProductionTimes100(iOverflow);13058 }13059 setUnitProduction(eTrainUnit, 0);1306013061 int iProductionGold = ((iLostProduction * GC.getMAXED_UNIT_GOLD_PERCENT()) / 100);13062 if(iProductionGold > 0)13063 {13064 kOwner.GetTreasury()->ChangeGoldTimes100(iProductionGold);13065 }13066 }13067 else13068 {13069 // create notification13070 setUnitProduction(eTrainUnit, getProductionNeeded(eTrainUnit) - 1);1307113072 CvNotifications* pNotifications = kOwner.GetNotifications();13073 if(pNotifications)13074 {13075 Localization::String strText = Localization::Lookup("TXT_KEY_NOTIFICATION_REMOVED_UNIT");13076 strText << getNameKey();13077 strText << GC.getUnitInfo(eTrainUnit)->GetDescription();13078 Localization::String strSummary = Localization::Lookup("TXT_KEY_NOTIFICATION_SUMMARY_REMOVED_UNIT");13079 pNotifications->Add(NOTIFICATION_GENERIC, strText.toUTF8(), strSummary.toUTF8(), getX(), getY(), -1);13080 }13081 }13082 }13083 break;1308413085 case ORDER_CONSTRUCT:13086 {13087 eConstructBuilding = ((BuildingTypes)(pOrderNode->iData1));1308813089 CvBuildingEntry* pkBuildingInfo = GC.getBuildingInfo(eConstructBuilding);1309013091 if(pkBuildingInfo)13092 {13093 kOwner.changeBuildingClassMaking(((BuildingClassTypes)(pkBuildingInfo->GetBuildingClassType())), -1);1309413095 if(bFinish)13096 {13097 bool bResult = CreateBuilding(eConstructBuilding);13098 DEBUG_VARIABLE(bResult);13099 CvAssertMsg(bResult, "CreateBuilding failed");1310013101#if defined(MOD_EVENTS_CITY)13102 if (MOD_EVENTS_CITY) {13103 GAMEEVENTINVOKE_HOOK(GAMEEVENT_CityConstructed, getOwner(), GetID(), eConstructBuilding, false, false);13104 } else {13105#endif13106 ICvEngineScriptSystem1* pkScriptSystem = gDLL->GetScriptSystem();13107 if (pkScriptSystem) 13108 {13109 CvLuaArgsHandle args;13110 args->Push(getOwner());13111 args->Push(GetID());13112 args->Push(eConstructBuilding);13113 args->Push(false); // bGold13114 args->Push(false); // bFaith/bCulture1311513116 bool bScriptResult;13117 LuaSupport::CallHook(pkScriptSystem, "CityConstructed", args.get(), bScriptResult);13118 }13119#if defined(MOD_EVENTS_CITY)13120 }13121#endif1312213123 iProductionNeeded = getProductionNeeded(eConstructBuilding) * 100;13124 // max overflow is the value of the item produced (to eliminate prebuild exploits)13125 int iOverflow = m_pCityBuildings->GetBuildingProductionTimes100(eConstructBuilding) - iProductionNeeded;13126 int iMaxOverflow = std::max(iProductionNeeded, getCurrentProductionDifferenceTimes100(false, false));13127 int iLostProduction = std::max(0, iOverflow - iMaxOverflow);13128 iOverflow = std::min(iMaxOverflow, iOverflow);13129 if(iOverflow > 0)13130 {13131 changeOverflowProductionTimes100(iOverflow);13132 }13133 m_pCityBuildings->SetBuildingProduction(eConstructBuilding, 0);1313413135 int iProductionGold = ((iLostProduction * GC.getMAXED_BUILDING_GOLD_PERCENT()) / 100);13136 if(iProductionGold > 0)13137 {13138 kOwner.GetTreasury()->ChangeGoldTimes100(iProductionGold);13139 }13140 13141#if defined(MOD_TRADE_WONDER_RESOURCE_ROUTES)13142 if (MOD_TRADE_WONDER_RESOURCE_ROUTES) {13143 // If the AI has just finished building a World Wonder, cancel any marble trade routes into this city13144 if (!GetPlayer()->isHuman()) {13145 const BuildingClassTypes eBuildingClass = (BuildingClassTypes)pkBuildingInfo->GetBuildingClassType();13146 CvBuildingClassInfo* pBuildingClass = GC.getBuildingClassInfo(eBuildingClass);13147 if (pBuildingClass && ::isWorldWonderClass(*pBuildingClass)) {13148 CvGameTrade* pGameTrade = GC.getGame().GetGameTrade();13149 for (uint ui = 0; ui < pGameTrade->m_aTradeConnections.size(); ui++) {13150 if (pGameTrade->IsTradeRouteIndexEmpty(ui)) {13151 continue;13152 }1315313154 TradeConnection kConnection = pGameTrade->m_aTradeConnections[ui];1315513156 if (kConnection.m_eConnectionType == TRADE_CONNECTION_WONDER_RESOURCE) {13157 CvCity* pDestCity = CvGameTrade::GetDestCity(kConnection);1315813159 if (pDestCity->getX() == getX() && pDestCity->getY() == getY()) {13160 kConnection.m_iCircuitsCompleted = kConnection.m_iCircuitsToComplete;13161 }13162 }13163 }13164 }13165 }13166 }13167#endif1316813169 if(GC.getLogging() && GC.getAILogging())13170 {13171 CvBuildingEntry* pkConstructBuildingInfo = GC.getBuildingInfo(eConstructBuilding);13172 if(pkConstructBuildingInfo)13173 {13174 if(kOwner.GetWonderProductionAI()->IsWonder(*pkConstructBuildingInfo))13175 {13176 CvString playerName;13177 FILogFile* pLog;13178 CvString strBaseString;13179 CvString strOutBuf;13180 playerName = kOwner.getCivilizationShortDescription();13181 pLog = LOGFILEMGR.GetLog(kOwner.GetCitySpecializationAI()->GetLogFileName(playerName), FILogFile::kDontTimeStamp);13182 strBaseString.Format("%03d, ", GC.getGame().getElapsedGameTurns());13183 strBaseString += playerName + ", ";13184 strOutBuf.Format("%s, WONDER - Finished %s", getName().GetCString(), pkConstructBuildingInfo->GetDescription());13185 strBaseString += strOutBuf;13186 pLog->Msg(strBaseString);13187 }13188 }1318913190 }13191 }13192 }13193 break;13194 }1319513196 case ORDER_CREATE:13197 eCreateProject = ((ProjectTypes)(pOrderNode->iData1));1319813199 GET_TEAM(getTeam()).changeProjectMaking(eCreateProject, -1);13200 kOwner.changeProjectMaking(eCreateProject, -1);1320113202 if(bFinish)13203 {13204 bool bResult = CreateProject(eCreateProject);13205 DEBUG_VARIABLE(bResult);13206 CvAssertMsg(bResult, "Failed to create project");1320713208#if defined(MOD_EVENTS_CITY)13209 if (MOD_EVENTS_CITY) {13210 GAMEEVENTINVOKE_HOOK(GAMEEVENT_CityCreated, getOwner(), GetID(), eCreateProject, false, false);13211 } else {13212#endif13213 ICvEngineScriptSystem1* pkScriptSystem = gDLL->GetScriptSystem();13214 if (pkScriptSystem) 13215 {13216 CvLuaArgsHandle args;13217 args->Push(getOwner());13218 args->Push(GetID());13219 args->Push(eCreateProject);13220 args->Push(false); // bGold13221 args->Push(false); // bFaith/bCulture1322213223 bool bScriptResult;13224 LuaSupport::CallHook(pkScriptSystem, "CityCreated", args.get(), bScriptResult);13225 }13226#if defined(MOD_EVENTS_CITY)13227 }13228#endif1322913230 iProductionNeeded = getProductionNeeded(eCreateProject) * 100;13231 // max overflow is the value of the item produced (to eliminate prebuild exploits)13232 int iOverflow = getProjectProductionTimes100(eCreateProject) - iProductionNeeded;13233 int iMaxOverflow = std::max(iProductionNeeded, getCurrentProductionDifferenceTimes100(false, false));13234 int iLostProduction = std::max(0, iOverflow - iMaxOverflow);13235 iOverflow = std::min(iMaxOverflow, iOverflow);13236 if(iOverflow > 0)13237 {13238 changeOverflowProductionTimes100(iOverflow);13239 }13240 setProjectProduction(eCreateProject, 0);1324113242 int iProductionGold = ((iLostProduction * GC.getMAXED_PROJECT_GOLD_PERCENT()) / 100);13243 if(iProductionGold > 0)13244 {13245 kOwner.GetTreasury()->ChangeGoldTimes100(iProductionGold);13246 }13247 }13248 break;1324913250 case ORDER_PREPARE:1325113252 if(bFinish)13253 {13254 eSpecialist = ((SpecialistTypes)(pOrderNode->iData1));1325513256#if defined(MOD_EVENTS_CITY)13257 if (MOD_EVENTS_CITY) {13258 GAMEEVENTINVOKE_HOOK(GAMEEVENT_CityPrepared, getOwner(), GetID(), eSpecialist, false, false);13259 }13260#endif1326113262 iProductionNeeded = getProductionNeeded(eSpecialist) * 100;1326313264 // max overflow is the value of the item produced (to eliminate prebuild exploits)13265 int iOverflow = getSpecialistProductionTimes100(eSpecialist) - iProductionNeeded;13266 int iMaxOverflow = std::max(iProductionNeeded, getCurrentProductionDifferenceTimes100(false, false));13267 iOverflow = std::min(iMaxOverflow, iOverflow);13268 if(iOverflow > 0)13269 {13270 changeOverflowProductionTimes100(iOverflow);13271 }1327213273 setSpecialistProduction(eSpecialist, 0);13274 }1327513276 break;1327713278 case ORDER_MAINTAIN:13279 break;1328013281 default:13282 CvAssertMsg(false, "pOrderNode->eOrderType is not a valid option");13283 break;13284 }1328513286 if(m_unitBeingBuiltForOperation.IsValid())13287 {13288 kOwner.CityUncommitToBuildUnitForOperationSlot(m_unitBeingBuiltForOperation);13289 m_unitBeingBuiltForOperation.Invalidate();13290 }1329113292 if(pOrderNode == headOrderQueueNode())13293 {13294 bStart = true;13295 stopHeadOrder();13296 }13297 else13298 {13299 bStart = false;13300 }1330113302 m_orderQueue.deleteNode(pOrderNode);13303 pOrderNode = NULL;13304 if(bFinish)13305 {13306 CleanUpQueue(); // cleans out items from the queue that may be invalidated by the recent construction13307 }1330813309 if(bStart)13310 {13311 startHeadOrder();13312 }1331313314 if((getTeam() == GC.getGame().getActiveTeam()) || GC.getGame().isDebugMode())13315 {13316 if(isCitySelected())13317 {13318 DLLUI->setDirty(SelectionButtons_DIRTY_BIT, true);13319 DLLUI->setDirty(CityScreen_DIRTY_BIT, true);13320 }13321 }1332213323 bMessage = false;1332413325 if(bChoose)13326 {13327 if(getOrderQueueLength() == 0)13328 {13329 if(!isHuman() || isProductionAutomated())13330 {13331 AI_chooseProduction(false /*bInterruptWonders*/);13332 }13333 else13334 {13335 chooseProduction(eTrainUnit, eConstructBuilding, eCreateProject, bFinish);1333613337 bMessage = true;13338 }13339 }13340 }1334113342 if(bFinish && !bMessage)13343 {13344 if(getOwner() == GC.getGame().getActivePlayer())13345 {13346 Localization::String localizedText;13347 if(eTrainUnit != NO_UNIT)13348 {13349 CvUnitEntry* pkUnitInfo = GC.getUnitInfo(eTrainUnit);13350 if(pkUnitInfo)13351 {13352 localizedText = Localization::Lookup(((isLimitedUnitClass((UnitClassTypes)(pkUnitInfo->GetUnitClassType()))) ? "TXT_KEY_MISC_TRAINED_UNIT_IN_LIMITED" : "TXT_KEY_MISC_TRAINED_UNIT_IN"));13353 localizedText << pkUnitInfo->GetTextKey() << getNameKey();13354 }13355 }13356 else if(eConstructBuilding != NO_BUILDING)13357 {13358 CvBuildingEntry* pkBuildingInfo = GC.getBuildingInfo(eConstructBuilding);13359 if(pkBuildingInfo)13360 {13361 localizedText = Localization::Lookup(((isLimitedWonderClass(pkBuildingInfo->GetBuildingClassInfo())) ? "TXT_KEY_MISC_CONSTRUCTED_BUILD_IN_LIMITED" : "TXT_KEY_MISC_CONSTRUCTED_BUILD_IN"));13362 localizedText << pkBuildingInfo->GetTextKey() << getNameKey();13363 }13364 }13365 else if(eCreateProject != NO_PROJECT)13366 {13367 localizedText = Localization::Lookup(((isLimitedProject(eCreateProject)) ? "TXT_KEY_MISC_CREATED_PROJECT_IN_LIMITED" : "TXT_KEY_MISC_CREATED_PROJECT_IN"));13368 localizedText << GC.getProjectInfo(eCreateProject)->GetTextKey() << getNameKey();13369 }13370 if(isProduction())13371 {13372 localizedText = Localization::Lookup(((isProductionLimited()) ? "TXT_KEY_MISC_WORK_HAS_BEGUN_LIMITED" : "TXT_KEY_MISC_WORK_HAS_BEGUN"));13373 localizedText << getProductionNameKey();13374 }13375 DLLUI->AddCityMessage(0, GetIDInfo(), getOwner(), false, GC.getEVENT_MESSAGE_TIME(), localizedText.toUTF8()/*, szSound, MESSAGE_TYPE_MINOR_EVENT, szIcon, (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX(), getY(), true, true*/);13376 }13377 }1337813379 if((getTeam() == GC.getGame().getActiveTeam()) || GC.getGame().isDebugMode())13380 {13381 if(isCitySelected())13382 {13383 DLLUI->setDirty(SelectionButtons_DIRTY_BIT, true);13384 DLLUI->setDirty(CityScreen_DIRTY_BIT, true);13385 DLLUI->setDirty(PlotListButtons_DIRTY_BIT, true);13386 }13387 DLLUI->setDirty(CityInfo_DIRTY_BIT, true);13388 }13389}