Beispiel #1
0
/**
 * moved the fix for #917 here - check a house's ability to handle base plan before it actually tries to generate a base plan, not at game start
 * (we have no idea what houses at game start are supposed to be able to do base planning, so mission maps f**k up)
 */
bool HouseExt::ExtData::CheckBasePlanSanity() {
	auto House = this->AttachedToObject;
	// this shouldn't happen, but you never know
	if(House->ControlledByHuman() || House->IsNeutral()) {
		return true;
	}

	const char *errorMsg = "AI House of country [%s] cannot build any object in %s. The AI ain't smart enough for that.\n";
	bool AllIsWell(true);

	// if you don't have a base unit buildable, how did you get to base planning?
	// only through crates or map actions, so have to validate base unit in other situations
	auto pArray = &RulesClass::Instance->BaseUnit;
	bool canBuild = false;
	for(int i = 0; i < pArray->Count; ++i) {
		auto Item = pArray->GetItem(i);
		if(House->CanExpectToBuild(Item)) {
			canBuild = true;
			break;
		}
	}
	if(!canBuild) {
		AllIsWell = false;
		Debug::DevLog(Debug::Error, errorMsg, House->Type->ID, "BaseUnit");
	}

	auto CheckList = [House, errorMsg, &AllIsWell]
			(DynamicVectorClass<BuildingTypeClass *> *const List, char * const ListName) -> void {
		if(!House->FirstBuildableFromArray(List)) {
			AllIsWell = false;
			Debug::DevLog(Debug::Error, errorMsg, House->Type->ID, ListName);
		}
	};

	// commented out lists that do not cause a crash, according to testers
//	CheckList(&RulesClass::Instance->Shipyard, "Shipyard");
	CheckList(&RulesClass::Instance->BuildPower, "BuildPower");
	CheckList(&RulesClass::Instance->BuildRefinery, "BuildRefinery");
	CheckList(&RulesClass::Instance->BuildWeapons, "BuildWeapons");

//			CheckList(&RulesClass::Instance->BuildConst, "BuildConst");
//			CheckList(&RulesClass::Instance->BuildBarracks, "BuildBarracks");
//			CheckList(&RulesClass::Instance->BuildTech, "BuildTech");
//			CheckList(&RulesClass::Instance->BuildRadar, "BuildRadar");
//			CheckList(&RulesClass::Instance->ConcreteWalls, "ConcreteWalls");
//			CheckList(&RulesClass::Instance->BuildDummy, "BuildDummy");
//			CheckList(&RulesClass::Instance->BuildNavalYard, "BuildNavalYard");

	auto pCountryData = HouseTypeExt::ExtMap.Find(House->Type);
	auto Powerplants = pCountryData->GetPowerplants();
	DynamicVectorClass<BuildingTypeClass*> Dummy(Powerplants.size(), const_cast<BuildingTypeClass**>(Powerplants.begin()));
	CheckList(&Dummy, "Powerplants");

//			auto pSide = SideClass::Array->GetItem(curHouse->Type->SideIndex);
//			auto pSideData = SideExt::ExtMap.Find(pSide);
//			CheckList(&pSideData->BaseDefenses, "Base Defenses");

	return AllIsWell;
}
Beispiel #2
0
void HouseExt::ExtData::UpdateTogglePower() {
	const auto pThis = this->OwnerObject();

	auto pRulesExt = RulesExt::Global();

	if(!pRulesExt->TogglePowerAllowed
		|| pRulesExt->TogglePowerDelay <= 0
		|| pRulesExt->TogglePowerIQ < 0
		|| pRulesExt->TogglePowerIQ > pThis->IQLevel2
		|| pThis->Buildings.Count == 0
		|| pThis->IsBeingDrained 
		|| pThis->ControlledByHuman()
		|| pThis->PowerBlackoutTimer.InProgress())
	{
		return;
	}

	if(Unsorted::CurrentFrame % pRulesExt->TogglePowerDelay == 0) {
		struct ExpendabilityStruct {
		private:
			std::tuple<const int&, BuildingClass&> Tie() const {
				// compare with tie breaker to prevent desyncs
				return std::tie(this->Value, *this->Building);
			}

		public:
			bool operator < (const ExpendabilityStruct& rhs) const {
				return this->Tie() < rhs.Tie();
			}

			bool operator > (const ExpendabilityStruct& rhs) const {
				return this->Tie() > rhs.Tie();
			}

			BuildingClass* Building;
			int Value;
		};

		// properties: the higher this value is, the more likely
		// this building is turned off (expendability)
		auto GetExpendability = [](BuildingClass* pBld) -> int {
			auto pType = pBld->Type;

			// disable super weapons, because a defenseless base is
			// worse than one without super weapons
			if(pType->HasSuperWeapon()) {
				return pType->PowerDrain * 20 / 10;
			}

			// non-base defenses should be disabled before going
			// to the base defenses. but power intensive defenses
			// might still evaluate worse
			if(!pType->IsBaseDefense) {
				return pType->PowerDrain * 15 / 10;
			}

			// default case, use power
			return pType->PowerDrain;
		};

		// create a list of all buildings that can be powered down
		// and give each building an expendability value
		std::vector<ExpendabilityStruct> Buildings;
		Buildings.reserve(pThis->Buildings.Count);

		const auto HasLowPower = pThis->HasLowPower();

		for(auto pBld : pThis->Buildings) {
			auto pType = pBld->Type;
			if(pType->CanTogglePower() && pType->PowerDrain > 0) {
				// if low power, we get buildings with StuffEnabled, if enough
				// power, we look for builidings that are disabled
				if(pBld->StuffEnabled == HasLowPower) {
					Buildings.emplace_back(ExpendabilityStruct{pBld, GetExpendability(pBld)});
				}
			}
		}

		int Surplus = pThis->PowerOutput - pThis->PowerDrain;

		if(HasLowPower) {
			// most expendable building first
			std::sort(Buildings.begin(), Buildings.end(), std::greater<>());

			// turn off the expendable buildings until power is restored
			for(const auto& item : Buildings) {
				auto Drain = item.Building->Type->PowerDrain;

				item.Building->GoOffline();
				Surplus += Drain;

				if(Surplus >= 0) {
					break;
				}
			}
		} else {
			// least expendable building first
			std::sort(Buildings.begin(), Buildings.end(), std::less<>());

			// turn on as many of them as possible
			for(const auto& item : Buildings) {
				auto Drain = item.Building->Type->PowerDrain;
				if(Surplus - Drain >= 0) {
					item.Building->GoOnline();
					Surplus -= Drain;
				}
			}
		}
	}
}
Beispiel #3
0
/**
 * moved the fix for #917 here - check a house's ability to handle base plan
 * before it actually tries to generate a base plan, not at game start (we have
 * no idea what houses at game start are supposed to be able to do base
 * planning, so mission maps f**k up)
 */
bool HouseExt::ExtData::CheckBasePlanSanity() {
	auto const pThis = this->OwnerObject();
	// this shouldn't happen, but you never know
	if(pThis->ControlledByHuman() || pThis->IsNeutral()) {
		return true;
	}

	auto AllIsWell = true;

	auto const pRules = RulesClass::Instance;
	auto const pType = pThis->Type;

	auto const errorMsg = "AI House of country [%s] cannot build any object in "
		"%s. The AI ain't smart enough for that.\n";

	// if you don't have a base unit buildable, how did you get to base
	// planning? only through crates or map actions, so have to validate base
	// unit in other situations
	auto const idxParent = pType->FindParentCountryIndex();
	auto const canBuild = std::any_of(
		pRules->BaseUnit.begin(), pRules->BaseUnit.end(),
		[pThis, idxParent] (UnitTypeClass const* const pItem)
	{
		return pThis->CanExpectToBuild(pItem, idxParent);
	});

	if(!canBuild) {
		AllIsWell = false;
		Debug::Log(Debug::Severity::Error, errorMsg, pType->ID, "BaseUnit");
	}

	auto CheckList = [pThis, pType, idxParent, errorMsg, &AllIsWell] (
		Iterator<BuildingTypeClass const*> const list,
		const char* const ListName) -> void
	{
		if(!HouseExt::FindBuildable(pThis, idxParent, list)) {
			AllIsWell = false;
			Debug::Log(Debug::Severity::Error, errorMsg, pType->ID, ListName);
		}
	};

	// commented out lists that do not cause a crash, according to testers
	//CheckList(make_iterator(pRules->Shipyard), "Shipyard");
	CheckList(make_iterator(pRules->BuildPower), "BuildPower");
	CheckList(make_iterator(pRules->BuildRefinery), "BuildRefinery");
	CheckList(make_iterator(pRules->BuildWeapons), "BuildWeapons");
	//CheckList(make_iterator(pRules->BuildConst), "BuildConst");
	//CheckList(make_iterator(pRules->BuildBarracks), "BuildBarracks");
	//CheckList(make_iterator(pRules->BuildTech), "BuildTech");
	//CheckList(make_iterator(pRules->BuildRadar), "BuildRadar");
	//CheckList(make_iterator(pRules->ConcreteWalls), "ConcreteWalls");
	//CheckList(make_iterator(pRules->BuildDummy), "BuildDummy");
	//CheckList(make_iterator(pRules->BuildNavalYard), "BuildNavalYard");

	auto const pCountryData = HouseTypeExt::ExtMap.Find(pType);
	auto const Powerplants = pCountryData->GetPowerplants();
	CheckList(Powerplants, "Powerplants");

	//auto const pSide = SideClass::Array->GetItemOrDefault(pType->SideIndex);
	//if(auto const pSideExt = SideExt::ExtMap.Find(pSide)) {
	//	CheckList(make_iterator(pSideExt->BaseDefenses), "Base Defenses");
	//}

	return AllIsWell;
}