mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Feature: Mods system improvement, Part III. Bunusing buildings customization.
This commit is contained in:
		| @@ -1210,6 +1210,11 @@ void CCreatureHandler::removeBonusesFromAllCreatures() | ||||
| 	allCreatures.removeBonuses(Selector::all); | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::restoreAllCreaturesNodeType794() | ||||
| { | ||||
| 	allCreatures.setNodeType(CBonusSystemNode::ENodeTypes::ALL_CREATURES); | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::buildBonusTreeForTiers() | ||||
| { | ||||
| 	for(CCreature *c : creatures) | ||||
|   | ||||
| @@ -249,6 +249,7 @@ public: | ||||
| 	void addBonusForTier(int tier, std::shared_ptr<Bonus> b); //tier must be <1-7> | ||||
| 	void addBonusForAllCreatures(std::shared_ptr<Bonus> b); | ||||
| 	void removeBonusesFromAllCreatures(); | ||||
| 	void restoreAllCreaturesNodeType794(); //restore ALL_CREATURES node type for old saves | ||||
|  | ||||
| 	CCreatureHandler(); | ||||
| 	~CCreatureHandler(); | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
| #include "filesystem/Filesystem.h" | ||||
| #include "mapObjects/CObjectClassesHandler.h" | ||||
| #include "mapObjects/CObjectHandler.h" | ||||
| #include "HeroBonus.h" | ||||
|  | ||||
| const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number | ||||
|  | ||||
| @@ -93,7 +94,37 @@ void CBuilding::deserializeFix() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBuilding::update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height) | ||||
| void CBuilding::addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList) | ||||
| { | ||||
| 	bonusList.push_back(b); | ||||
| } | ||||
|  | ||||
| const JsonNode & CBuilding::getCurrentFactionForUpdateRoutine() const | ||||
| { | ||||
| 	const auto & faction = town->faction->identifier; | ||||
| 	const auto & factionsContent = (*VLC->modh->content)["factions"]; | ||||
| 	const auto & coreData = factionsContent.modData.at("core"); | ||||
| 	const auto & coreFactions = coreData.modData; | ||||
| 	const auto & currentFaction = coreFactions[faction]; | ||||
|  | ||||
| 	if(currentFaction.isNull()) | ||||
| 	{ | ||||
| 		const auto index = faction.find(':'); | ||||
| 		const std::string factionDir = index == std::string::npos ? faction : faction.substr(0, index); | ||||
| 		const auto it = factionsContent.modData.find(factionDir); | ||||
|  | ||||
| 		if(it == factionsContent.modData.end()) | ||||
| 		{ | ||||
| 			logMod->warn("Warning: Update old save failed: Faction: '%s' is not found.", factionDir); | ||||
| 			return currentFaction; | ||||
| 		} | ||||
| 		const std::string modFaction = index == std::string::npos ? faction : faction.substr(index + 1); | ||||
| 		return it->second.modData[modFaction]; | ||||
| 	} | ||||
| 	return currentFaction; | ||||
| } | ||||
|  | ||||
| void CBuilding::update792() | ||||
| { | ||||
| 	subId = BuildingSubID::NONE; | ||||
| 	height = ETowerHeight::HEIGHT_NO_TOWER; | ||||
| @@ -106,37 +137,72 @@ void CBuilding::update792(const BuildingID & bid, BuildingSubID::EBuildingSubID | ||||
| 	if(buildingName.empty()) | ||||
| 		return; | ||||
|  | ||||
| 	const auto & faction = town->faction->identifier; | ||||
| 	auto factionsContent = (*VLC->modh->content)["factions"]; | ||||
| 	auto & coreData = factionsContent.modData.at("core"); | ||||
| 	auto & coreFactions = coreData.modData; | ||||
| 	auto & currentFaction = coreFactions[faction]; | ||||
| 	auto & currentFaction = getCurrentFactionForUpdateRoutine(); | ||||
|  | ||||
| 	if (currentFaction.isNull()) | ||||
| 	{ | ||||
| 		const auto index = faction.find(':'); | ||||
| 		const std::string factionDir = index == std::string::npos ? faction : faction.substr(0, index); | ||||
| 		const auto it = factionsContent.modData.find(factionDir); | ||||
|  | ||||
| 		if (it == factionsContent.modData.end()) | ||||
| 		{ | ||||
| 			logMod->warn("Warning: Update old save failed: Faction: '%s' is not found.", factionDir); | ||||
| 			return; | ||||
| 		} | ||||
| 		const std::string modFaction = index == std::string::npos ? faction : faction.substr(index + 1); | ||||
| 		currentFaction = it->second.modData[modFaction]; | ||||
| 	} | ||||
|  | ||||
| 	if (!currentFaction.isNull() && currentFaction.getType() == JsonNode::JsonType::DATA_STRUCT) | ||||
| 	if(!currentFaction.isNull() && currentFaction.getType() == JsonNode::JsonType::DATA_STRUCT) | ||||
| 	{ | ||||
| 		const auto & buildings = currentFaction["town"]["buildings"]; | ||||
| 		const auto & currentBuilding = buildings[buildingName]; | ||||
|  | ||||
| 		subId = CTownHandler::getMappedValue<BuildingSubID::EBuildingSubID>(currentBuilding["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS); | ||||
| 		height = CBuilding::HEIGHT_NO_TOWER; | ||||
| 		height = subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL | ||||
| 			? CTownHandler::getMappedValue<CBuilding::ETowerHeight>(currentBuilding["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES) | ||||
| 			: height = CBuilding::HEIGHT_NO_TOWER; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 		if (subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL) | ||||
| 			height = CTownHandler::getMappedValue<CBuilding::ETowerHeight>(currentBuilding["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES); | ||||
| void CBuilding::update794() | ||||
| { | ||||
| 	if(bid == BuildingID::TAVERN || subId == BuildingSubID::BROTHERHOOD_OF_SWORD) | ||||
| 	{ | ||||
| 		VLC->townh->addBonusesForVanilaBuilding(this); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(!bid.IsSpecialOrGrail()) | ||||
| 		return; | ||||
|  | ||||
| 	VLC->townh->addBonusesForVanilaBuilding(this); | ||||
|  | ||||
| 	if(!buildingBonuses.empty() //addBonusesForVanilaBuilding has done all work | ||||
| 		|| town->faction == nullptr //or faction data is not valid | ||||
| 		|| town->faction->identifier.empty()) | ||||
| 		return; | ||||
|  | ||||
| 	const auto buildingName = CTownHandler::getMappedValue<std::string, BuildingID>(bid, std::string(), MappedKeys::BUILDING_TYPES_TO_NAMES, false); | ||||
|  | ||||
| 	if(buildingName.empty()) | ||||
| 		return; | ||||
|  | ||||
| 	auto & currentFaction = getCurrentFactionForUpdateRoutine(); | ||||
|  | ||||
| 	if(currentFaction.isNull() || currentFaction.getType() != JsonNode::JsonType::DATA_STRUCT) | ||||
| 		return; | ||||
|  | ||||
| 	const auto & buildings = currentFaction["town"]["buildings"]; | ||||
| 	const auto & currentBuilding = buildings[buildingName]; | ||||
|  | ||||
| 	CTownHandler::loadSpecialBuildingBonuses(currentBuilding["bonuses"], buildingBonuses, this); | ||||
| 	CTownHandler::loadSpecialBuildingBonuses(currentBuilding["onVisitBonuses"], onVisitBonuses, this); | ||||
|  | ||||
| 	if(!onVisitBonuses.empty()) | ||||
| 	{ | ||||
| 		if(subId == BuildingSubID::NONE) | ||||
| 			subId = BuildingSubID::CUSTOM_VISITING_BONUS; | ||||
|  | ||||
| 		for(auto & bonus : onVisitBonuses) | ||||
| 			bonus->sid = Bonus::getSid32(town->faction->index, bid); | ||||
| 	} | ||||
| 	const auto & overriddenBids = currentBuilding["overrides"]; | ||||
|  | ||||
| 	if(overriddenBids.isNull()) | ||||
| 		return; | ||||
|  | ||||
| 	auto scope = town->getBuildingScope(); | ||||
|  | ||||
| 	for(auto b : overriddenBids.Vector()) | ||||
| 	{ | ||||
| 		auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).get()); | ||||
| 		overrideBids.insert(bid); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -258,6 +324,8 @@ JsonNode readBuilding(CLegacyConfigParser & parser) | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| TPropagatorPtr CTownHandler::emptyPropagator = std::make_shared<CPropagatorNodeType>(); | ||||
|  | ||||
| std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize) | ||||
| { | ||||
| 	std::vector<JsonNode> dest(dataSize); | ||||
| @@ -412,7 +480,7 @@ std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize) | ||||
| 	return dest; | ||||
| } | ||||
|  | ||||
| void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode & source) | ||||
| void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode & source, std::vector<BuildingRequirementsHelper> & bidsToLoad) | ||||
| { | ||||
| 	if (source.isNull()) | ||||
| 		return; | ||||
| @@ -421,7 +489,7 @@ void CTownHandler::loadBuildingRequirements(CBuilding * building, const JsonNode | ||||
| 	hlp.building = building; | ||||
| 	hlp.town = building->town; | ||||
| 	hlp.json = source; | ||||
| 	requirementsToLoad.push_back(hlp); | ||||
| 	bidsToLoad.push_back(hlp); | ||||
| } | ||||
|  | ||||
| template<typename R, typename K> | ||||
| @@ -445,6 +513,100 @@ R CTownHandler::getMappedValue(const JsonNode & node, const R defval, const std: | ||||
| 	return defval; | ||||
| } | ||||
|  | ||||
| void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building) | ||||
| { | ||||
| 	std::shared_ptr<Bonus> b; | ||||
| 	static TPropagatorPtr playerPropagator = std::make_shared<CPropagatorNodeType>(CBonusSystemNode::ENodeTypes::PLAYER); | ||||
|  | ||||
| 	if(building->subId == BuildingSubID::NONE) | ||||
| 	{ | ||||
| 		if(building->bid == BuildingID::TAVERN) | ||||
| 			b = createBonus(building, Bonus::MORALE, +1); | ||||
| 		else if(building->bid == BuildingID::GRAIL  | ||||
| 				&& building->town->faction != nullptr | ||||
| 				&& boost::algorithm::ends_with(building->town->faction->identifier, ":cove")) | ||||
| 		{ | ||||
| 				static TPropagatorPtr allCreaturesPropagator(new CPropagatorNodeType(CBonusSystemNode::ENodeTypes::ALL_CREATURES)); | ||||
| 				static auto factionLimiter = std::make_shared<CreatureFactionLimiter>(building->town->faction->index); | ||||
| 				b = createBonus(building, Bonus::NO_TERRAIN_PENALTY, 0, allCreaturesPropagator); | ||||
| 				b->addLimiter(factionLimiter); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		switch(building->subId) | ||||
| 		{ | ||||
| 		case BuildingSubID::BROTHERHOOD_OF_SWORD: | ||||
| 			b = createBonus(building, Bonus::MORALE, +2); | ||||
| 			building->overrideBids.insert(BuildingID::TAVERN); | ||||
| 			break; | ||||
| 		case BuildingSubID::FOUNTAIN_OF_FORTUNE: | ||||
| 			b = createBonus(building, Bonus::LUCK, +2); | ||||
| 			break; | ||||
| 		case BuildingSubID::SPELL_POWER_GARRISON_BONUS: | ||||
| 			b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER); | ||||
| 			break; | ||||
| 		case BuildingSubID::ATTACK_GARRISON_BONUS: | ||||
| 			b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK); | ||||
| 			break; | ||||
| 		case BuildingSubID::DEFENSE_GARRISON_BONUS: | ||||
| 			b = createBonus(building, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE); | ||||
| 			break; | ||||
| 		case BuildingSubID::LIGHTHOUSE: | ||||
| 			b = createBonus(building, Bonus::SEA_MOVEMENT, +500, playerPropagator); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if(b) | ||||
| 		building->addNewBonus(b, building->buildingBonuses); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, int subtype) | ||||
| { | ||||
| 	return createBonus(build, type, val, emptyPropagator, subtype); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype) | ||||
| { | ||||
| 	std::ostringstream descr; | ||||
| 	descr << build->name; | ||||
| 	return createBonusImpl(build->bid, type, val, prop, descr.str(), subtype); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<Bonus> CTownHandler::createBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype) | ||||
| { | ||||
| 	auto b = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype); | ||||
|  | ||||
| 	if(prop) | ||||
| 		b->addPropagator(prop); | ||||
|  | ||||
| 	return b; | ||||
| } | ||||
|  | ||||
| void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList & bonusList, CBuilding * building) | ||||
| { | ||||
| 	for(auto b : source.Vector()) | ||||
| 	{ | ||||
| 		auto bonus = JsonUtils::parseBuildingBonus(b, building->bid, building->name); | ||||
|  | ||||
| 		if(bonus == nullptr) | ||||
| 			continue; | ||||
|  | ||||
| 		if(bonus->limiter != nullptr) | ||||
| 		{ | ||||
| 			auto limPtr = dynamic_cast<CreatureFactionLimiter*>(bonus->limiter.get()); | ||||
|  | ||||
| 			if(limPtr != nullptr && limPtr->faction == (TFaction)-1) | ||||
| 				limPtr->faction = building->town->faction->index; | ||||
| 		} | ||||
| 		//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty. | ||||
| 		if(bonus->propagator != nullptr  | ||||
| 			&& bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN) | ||||
| 				bonus->addPropagator(emptyPropagator); | ||||
| 		building->addNewBonus(bonus, bonusList); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source) | ||||
| { | ||||
| 	auto ret = new CBuilding(); | ||||
| @@ -474,6 +636,26 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons | ||||
| 	ret->resources = TResources(source["cost"]); | ||||
| 	ret->produce =   TResources(source["produce"]); | ||||
|  | ||||
| 	if(ret->bid == BuildingID::TAVERN) | ||||
| 		addBonusesForVanilaBuilding(ret); | ||||
| 	else if(ret->bid.IsSpecialOrGrail()) | ||||
| 	{ | ||||
| 		loadSpecialBuildingBonuses(source["bonuses"], ret->buildingBonuses, ret); | ||||
|  | ||||
| 		if(ret->buildingBonuses.empty()) | ||||
| 			addBonusesForVanilaBuilding(ret); | ||||
|  | ||||
| 		loadSpecialBuildingBonuses(source["onVisitBonuses"], ret->onVisitBonuses, ret); | ||||
|  | ||||
| 		if(!ret->onVisitBonuses.empty()) | ||||
| 		{ | ||||
| 			if(ret->subId == BuildingSubID::NONE) | ||||
| 				ret->subId = BuildingSubID::CUSTOM_VISITING_BONUS; | ||||
|  | ||||
| 			for(auto & bonus : ret->onVisitBonuses) | ||||
| 				bonus->sid = Bonus::getSid32(ret->town->faction->index, ret->bid); | ||||
| 		} | ||||
| 	} | ||||
| 	//MODS COMPATIBILITY FOR 0.96 | ||||
| 	if(!ret->produce.nonZero()) | ||||
| 	{ | ||||
| @@ -501,8 +683,10 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	loadBuildingRequirements(ret, source["requires"], requirementsToLoad); | ||||
|  | ||||
| 	loadBuildingRequirements(ret, source["requires"]); | ||||
| 	if(ret->bid.IsSpecialOrGrail()) | ||||
| 		loadBuildingRequirements(ret, source["overrides"], overriddenBidsToLoad); | ||||
|  | ||||
| 	if (!source["upgrades"].isNull()) | ||||
| 	{ | ||||
| @@ -828,9 +1012,10 @@ ETerrainType::EETerrainType CTownHandler::getDefaultTerrainForAlignment(EAlignme | ||||
| 	return terrain; | ||||
| } | ||||
|  | ||||
| CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string & identifier) | ||||
| CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string & identifier, TFaction index) | ||||
| { | ||||
| 	auto  faction = new CFaction(); | ||||
| 	faction->index = index; | ||||
|  | ||||
| 	faction->name = source["name"].String(); | ||||
| 	faction->identifier = identifier; | ||||
| @@ -871,9 +1056,9 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, const std::string | ||||
|  | ||||
| void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data) | ||||
| { | ||||
| 	auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); | ||||
| 	auto index = static_cast<TFaction>(factions.size()); | ||||
| 	auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name), index); | ||||
|  | ||||
| 	object->index = static_cast<TFaction>(factions.size()); | ||||
| 	factions.push_back(object); | ||||
|  | ||||
| 	if (object->town) | ||||
| @@ -911,8 +1096,8 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod | ||||
|  | ||||
| void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) | ||||
| { | ||||
| 	auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); | ||||
| 	object->index = static_cast<TFaction>(index); | ||||
| 	auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name), static_cast<TFaction>(index)); | ||||
| 	 | ||||
| 	if (factions.size() > index) | ||||
| 		assert(factions[index] == nullptr); // ensure that this id was not loaded before | ||||
| 	else | ||||
| @@ -957,6 +1142,7 @@ void CTownHandler::loadCustom() | ||||
| void CTownHandler::afterLoadFinalization() | ||||
| { | ||||
| 	initializeRequirements(); | ||||
| 	initializeOverridden(); | ||||
| 	initializeWarMachines(); | ||||
| } | ||||
|  | ||||
| @@ -979,6 +1165,22 @@ void CTownHandler::initializeRequirements() | ||||
| 	requirementsToLoad.clear(); | ||||
| } | ||||
|  | ||||
| void CTownHandler::initializeOverridden() | ||||
| { | ||||
| 	for(auto & bidHelper : overriddenBidsToLoad) | ||||
| 	{ | ||||
| 		auto jsonNode = bidHelper.json; | ||||
| 		auto scope = bidHelper.town->getBuildingScope(); | ||||
|  | ||||
| 		for(auto b : jsonNode.Vector()) | ||||
| 		{ | ||||
| 			auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).get()); | ||||
| 			bidHelper.building->overrideBids.insert(bid); | ||||
| 		} | ||||
| 	} | ||||
| 	overriddenBidsToLoad.clear(); | ||||
| } | ||||
|  | ||||
| void CTownHandler::initializeWarMachines() | ||||
| { | ||||
| 	// must be done separately after all objects are loaded | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
| #include "IHandlerBase.h" | ||||
| #include "LogicalExpression.h" | ||||
| #include "battle/BattleHex.h" | ||||
| #include "HeroBonus.h" | ||||
|  | ||||
| class CLegacyConfigParser; | ||||
| class JsonNode; | ||||
| @@ -47,6 +48,9 @@ public: | ||||
| 	BuildingID bid; //structure ID | ||||
| 	BuildingID upgrade; /// indicates that building "upgrade" can be improved by this, -1 = empty | ||||
| 	BuildingSubID::EBuildingSubID subId; /// subtype for special buildings, -1 = the building is not special | ||||
| 	std::set<BuildingID> overrideBids; /// the building which bonuses should be overridden with bonuses of the current building | ||||
| 	BonusList buildingBonuses; | ||||
| 	BonusList onVisitBonuses; | ||||
|  | ||||
| 	enum EBuildMode | ||||
| 	{ | ||||
| @@ -95,14 +99,16 @@ public: | ||||
| 	bool IsVisitingBonus() const | ||||
| 	{ | ||||
| 		return subId == BuildingSubID::ATTACK_VISITING_BONUS || | ||||
| 			subId == BuildingSubID::DEFENSE_VISITING_BONUS ||  | ||||
| 			subId == BuildingSubID::DEFENSE_VISITING_BONUS || | ||||
| 			subId == BuildingSubID::SPELL_POWER_VISITING_BONUS || | ||||
| 			subId == BuildingSubID::KNOWLEDGE_VISITING_BONUS || | ||||
| 			subId == BuildingSubID::EXPERIENCE_VISITING_BONUS; | ||||
| 			subId == BuildingSubID::EXPERIENCE_VISITING_BONUS || | ||||
| 			subId == BuildingSubID::CUSTOM_VISITING_BONUS; | ||||
| 	} | ||||
|  | ||||
| 	/// input: faction, bid; output: subId, height; | ||||
| 	void update792(const BuildingID & bid, BuildingSubID::EBuildingSubID & subId, ETowerHeight & height); | ||||
| 	void addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList); | ||||
| 	void update792(); | ||||
| 	void update794(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -123,9 +129,17 @@ public: | ||||
| 			h & height; | ||||
| 		} | ||||
| 		if(!h.saving && version < 793) | ||||
| 			update792(); //adjust height, subId | ||||
|  | ||||
| 		if(version >= 794) | ||||
| 		{ | ||||
| 			update792(bid, subId, height); | ||||
| 			h & overrideBids; | ||||
| 			h & buildingBonuses; | ||||
| 			h & onVisitBonuses; | ||||
| 		} | ||||
| 		else if(!h.saving) | ||||
| 			update794(); //populate overrideBids, buildingBonuses, onVisitBonuses | ||||
|  | ||||
| 		if(!h.saving) | ||||
| 			deserializeFix(); | ||||
| 	} | ||||
| @@ -133,8 +147,8 @@ public: | ||||
| 	friend class CTownHandler; | ||||
|  | ||||
| private: | ||||
|  | ||||
| 	void deserializeFix(); | ||||
| 	const JsonNode & getCurrentFactionForUpdateRoutine() const; | ||||
| }; | ||||
|  | ||||
| /// This is structure used only by client | ||||
| @@ -354,19 +368,27 @@ class DLL_LINKAGE CTownHandler : public IHandlerBase | ||||
|  | ||||
| 	std::map<CTown *, JsonNode> warMachinesToLoad; | ||||
| 	std::vector<BuildingRequirementsHelper> requirementsToLoad; | ||||
| 	std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden. | ||||
|  | ||||
| 	const static ETerrainType::EETerrainType defaultGoodTerrain = ETerrainType::EETerrainType::GRASS; | ||||
| 	const static ETerrainType::EETerrainType defaultEvilTerrain = ETerrainType::EETerrainType::LAVA; | ||||
| 	const static ETerrainType::EETerrainType defaultNeutralTerrain = ETerrainType::EETerrainType::ROUGH; | ||||
|  | ||||
| 	static TPropagatorPtr emptyPropagator; | ||||
|  | ||||
| 	void initializeRequirements(); | ||||
| 	void initializeOverridden(); | ||||
| 	void initializeWarMachines(); | ||||
|  | ||||
| 	/// loads CBuilding's into town | ||||
| 	void loadBuildingRequirements(CBuilding * building, const JsonNode & source); | ||||
| 	void loadBuildingRequirements(CBuilding * building, const JsonNode & source, std::vector<BuildingRequirementsHelper> & bidsToLoad); | ||||
| 	void loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source); | ||||
| 	void loadBuildings(CTown * town, const JsonNode & source); | ||||
|  | ||||
| 	std::shared_ptr<Bonus> createBonus(CBuilding * build, Bonus::BonusType type, int val, int subtype = -1); | ||||
| 	std::shared_ptr<Bonus> createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype = -1); | ||||
| 	std::shared_ptr<Bonus> createBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype = -1); | ||||
|  | ||||
| 	/// loads CStructure's into town | ||||
| 	void loadStructure(CTown &town, const std::string & stringID, const JsonNode & source); | ||||
| 	void loadStructures(CTown &town, const JsonNode & source); | ||||
| @@ -383,7 +405,7 @@ class DLL_LINKAGE CTownHandler : public IHandlerBase | ||||
|  | ||||
| 	ETerrainType::EETerrainType getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const; | ||||
|  | ||||
| 	CFaction * loadFromJson(const JsonNode & data, const std::string & identifier); | ||||
| 	CFaction * loadFromJson(const JsonNode & data, const std::string & identifier, TFaction index); | ||||
|  | ||||
| 	void loadRandomFaction(); | ||||
|  | ||||
| @@ -404,6 +426,7 @@ public: | ||||
|  | ||||
| 	void loadObject(std::string scope, std::string name, const JsonNode & data) override; | ||||
| 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; | ||||
| 	void addBonusesForVanilaBuilding(CBuilding * building); | ||||
|  | ||||
| 	void loadCustom() override; | ||||
| 	void afterLoadFinalization() override; | ||||
| @@ -416,6 +439,7 @@ public: | ||||
|  | ||||
| 	//json serialization helper | ||||
| 	static std::string encodeFaction(const si32 index); | ||||
| 	static void loadSpecialBuildingBonuses(const JsonNode & source, BonusList & bonusList, CBuilding * building); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -297,7 +297,7 @@ class TeleportChannelID : public BaseForID<TeleportChannelID, si32> | ||||
| // Enum declarations | ||||
| namespace PrimarySkill | ||||
| { | ||||
| 	enum PrimarySkill { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE, | ||||
| 	enum PrimarySkill { NONE = -1, ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE, | ||||
| 				EXPERIENCE = 4}; //for some reason changePrimSkill uses it | ||||
| } | ||||
|  | ||||
| @@ -452,7 +452,8 @@ namespace BuildingSubID | ||||
| 		KNOWLEDGE_VISITING_BONUS, | ||||
| 		EXPERIENCE_VISITING_BONUS, | ||||
| 		LIGHTHOUSE, | ||||
| 		TREASURY | ||||
| 		TREASURY, | ||||
| 		CUSTOM_VISITING_BONUS | ||||
| 	}; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -71,7 +71,8 @@ const std::map<std::string, TLimiterPtr> bonusLimiterMap = | ||||
| 	{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)}, | ||||
| 	{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)}, | ||||
| 	{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)}, | ||||
| 	{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()} | ||||
| 	{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()}, | ||||
| 	{"CREATURE_FACTION", std::make_shared<CreatureFactionLimiter>()} | ||||
| }; | ||||
|  | ||||
| const std::map<std::string, TPropagatorPtr> bonusPropagatorMap = | ||||
| @@ -81,7 +82,8 @@ const std::map<std::string, TPropagatorPtr> bonusPropagatorMap = | ||||
| 	{"PLAYER_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::PLAYER)}, | ||||
| 	{"HERO", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO)}, | ||||
| 	{"TEAM_PROPAGATOR", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::TEAM)}, //untested | ||||
| 	{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)} | ||||
| 	{"GLOBAL_EFFECT", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::GLOBAL_EFFECTS)}, | ||||
| 	{"ALL_CREATURES", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::ALL_CREATURES)} | ||||
| }; //untested | ||||
|  | ||||
| const std::map<std::string, TUpdaterPtr> bonusUpdaterMap = | ||||
| @@ -1570,8 +1572,8 @@ std::string Bonus::nameForBonus() const | ||||
| 	} | ||||
| } | ||||
|  | ||||
| Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype) | ||||
| 	: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc) | ||||
| Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype) | ||||
| 	: duration((ui16)Duration), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc) | ||||
| { | ||||
| 	turnsRemain = 0; | ||||
| 	valType = ADDITIVE_VALUE; | ||||
| @@ -1579,8 +1581,8 @@ Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std:: | ||||
| 	boost::algorithm::trim(description); | ||||
| } | ||||
|  | ||||
| Bonus::Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType) | ||||
| 	: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType) | ||||
| Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType) | ||||
| 	: duration((ui16)Duration), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType) | ||||
| { | ||||
| 	turnsRemain = 0; | ||||
| 	effectRange = NO_LIMIT; | ||||
| @@ -1922,17 +1924,27 @@ bool IPropagator::shouldBeAttached(CBonusSystemNode *dest) | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CBonusSystemNode::ENodeTypes IPropagator::getPropagatorType() const | ||||
| { | ||||
| 	return CBonusSystemNode::ENodeTypes::NONE; | ||||
| } | ||||
|  | ||||
| CPropagatorNodeType::CPropagatorNodeType() | ||||
| 	:nodeType(0) | ||||
| 	:nodeType(CBonusSystemNode::ENodeTypes::UNKNOWN) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| CPropagatorNodeType::CPropagatorNodeType(int NodeType) | ||||
| CPropagatorNodeType::CPropagatorNodeType(CBonusSystemNode::ENodeTypes NodeType) | ||||
| 	: nodeType(NodeType) | ||||
| { | ||||
| } | ||||
|  | ||||
| CBonusSystemNode::ENodeTypes CPropagatorNodeType::getPropagatorType() const | ||||
| { | ||||
| 	return nodeType; | ||||
| } | ||||
|  | ||||
| bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest) | ||||
| { | ||||
| 	return nodeType == dest->getNodeType(); | ||||
|   | ||||
| @@ -418,8 +418,8 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus> | ||||
|  | ||||
| 	std::string description; | ||||
|  | ||||
| 	Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1); | ||||
| 	Bonus(ui16 Dur, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, ValueType ValType = ADDITIVE_VALUE); | ||||
| 	Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1); | ||||
| 	Bonus(BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype=-1, ValueType ValType = ADDITIVE_VALUE); | ||||
| 	Bonus(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -508,6 +508,10 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus> | ||||
| 	{ | ||||
| 		val += Val; | ||||
| 	} | ||||
| 	STRONG_INLINE static ui32 getSid32(ui32 high, ui32 low) | ||||
| 	{ | ||||
| 		return (high << 16) + low; | ||||
| 	} | ||||
|  | ||||
| 	std::string Description() const; | ||||
| 	JsonNode toJsonNode() const; | ||||
| @@ -639,30 +643,6 @@ inline BonusList::const_iterator range_end(BonusList const &x) | ||||
|  | ||||
| DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList); | ||||
|  | ||||
| class DLL_LINKAGE IPropagator | ||||
| { | ||||
| public: | ||||
| 	virtual ~IPropagator(); | ||||
| 	virtual bool shouldBeAttached(CBonusSystemNode *dest); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CPropagatorNodeType : public IPropagator | ||||
| { | ||||
| 	int nodeType; //CBonusSystemNode::ENodeTypes | ||||
| public: | ||||
| 	CPropagatorNodeType(); | ||||
| 	CPropagatorNodeType(int NodeType); | ||||
| 	bool shouldBeAttached(CBonusSystemNode *dest) override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & nodeType; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct BonusLimitationContext | ||||
| { | ||||
| 	std::shared_ptr<const Bonus> b; | ||||
| @@ -756,6 +736,7 @@ class DLL_LINKAGE CBonusSystemNode : public virtual IBonusBearer, public boost:: | ||||
| public: | ||||
| 	enum ENodeTypes | ||||
| 	{ | ||||
| 		NONE = -1,  | ||||
| 		UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALTY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM, | ||||
| 		TOWN_AND_VISITOR, BATTLE, COMMANDER, GLOBAL_EFFECTS, ALL_CREATURES | ||||
| 	}; | ||||
| @@ -857,6 +838,33 @@ public: | ||||
| 	friend class CBonusProxy; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE IPropagator | ||||
| { | ||||
| public: | ||||
| 	virtual ~IPropagator(); | ||||
| 	virtual bool shouldBeAttached(CBonusSystemNode *dest); | ||||
| 	virtual CBonusSystemNode::ENodeTypes getPropagatorType() const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CPropagatorNodeType : public IPropagator | ||||
| { | ||||
| 	CBonusSystemNode::ENodeTypes nodeType; | ||||
|  | ||||
| public: | ||||
| 	CPropagatorNodeType(); | ||||
| 	CPropagatorNodeType(CBonusSystemNode::ENodeTypes NodeType); | ||||
| 	bool shouldBeAttached(CBonusSystemNode *dest) override; | ||||
| 	CBonusSystemNode::ENodeTypes getPropagatorType() const override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & nodeType; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| namespace NBonus | ||||
| { | ||||
| 	//set of methods that may be safely called with nullptr objs | ||||
|   | ||||
| @@ -697,6 +697,19 @@ std::shared_ptr<Bonus> JsonUtils::parseBonus(const JsonNode &ability) | ||||
| 	return b; | ||||
| } | ||||
|  | ||||
| std::shared_ptr<Bonus> JsonUtils::parseBuildingBonus(const JsonNode &ability, BuildingID building, std::string description) | ||||
| { | ||||
| 	/*	duration = Bonus::PERMANENT | ||||
| 		source = Bonus::TOWN_STRUCTURE | ||||
| 		bonusType, val, subtype - get from json | ||||
| 	*/ | ||||
| 	auto b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::NONE, Bonus::TOWN_STRUCTURE, 0, building, description, -1); | ||||
|  | ||||
| 	if(!parseBonus(ability, b.get())) | ||||
| 		return nullptr; | ||||
| 	return b; | ||||
| } | ||||
|  | ||||
| bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) | ||||
| { | ||||
| 	const JsonNode *value; | ||||
| @@ -726,7 +739,8 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) | ||||
|  | ||||
| 	b->sid = static_cast<si32>(ability["sourceID"].Float()); | ||||
|  | ||||
| 	b->description = ability["description"].String(); | ||||
| 	if(!ability["description"].isNull()) | ||||
| 		b->description = ability["description"].String(); | ||||
|  | ||||
| 	value = &ability["effectRange"]; | ||||
| 	if (!value->isNull()) | ||||
| @@ -738,7 +752,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) | ||||
| 		switch (value->getType()) | ||||
| 		{ | ||||
| 		case JsonNode::JsonType::DATA_STRING: | ||||
| 			b->duration = parseByMap(bonusDurationMap, value, "duration type "); | ||||
| 			b->duration = (Bonus::BonusDuration)parseByMap(bonusDurationMap, value, "duration type "); | ||||
| 			break; | ||||
| 		case JsonNode::JsonType::DATA_VECTOR: | ||||
| 			{ | ||||
| @@ -747,7 +761,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) | ||||
| 				{ | ||||
| 					dur |= parseByMap(bonusDurationMap, &d, "duration type "); | ||||
| 				} | ||||
| 				b->duration = dur; | ||||
| 				b->duration = (Bonus::BonusDuration)dur; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
| #include "GameConstants.h" | ||||
|  | ||||
| class JsonNode; | ||||
| typedef std::map <std::string, JsonNode> JsonMap; | ||||
| @@ -168,6 +169,7 @@ namespace JsonUtils | ||||
| 	/// | ||||
| 	DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonVector &ability_vec); | ||||
| 	DLL_LINKAGE std::shared_ptr<Bonus> parseBonus(const JsonNode &ability); | ||||
| 	DLL_LINKAGE std::shared_ptr<Bonus> parseBuildingBonus(const JsonNode &ability, BuildingID building, std::string description); | ||||
| 	DLL_LINKAGE bool parseBonus(const JsonNode &ability, Bonus *placement); | ||||
| 	DLL_LINKAGE std::shared_ptr<ILimiter> parseLimiter(const JsonNode & limiter); | ||||
| 	DLL_LINKAGE void resolveIdentifier(si32 &var, const JsonNode &node, std::string name); | ||||
|   | ||||
| @@ -245,10 +245,21 @@ DLL_LINKAGE void GiveBonus::applyGs(CGameState *gs) | ||||
| 	std::string &descr = b->description; | ||||
|  | ||||
| 	if(!bdescr.message.size() | ||||
| 		&& bonus.source == Bonus::OBJECT | ||||
| 		&& (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE)) | ||||
| 	{ | ||||
| 		descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" | ||||
| 		if (bonus.source == Bonus::OBJECT) | ||||
| 		{ | ||||
| 			descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" | ||||
| 		} | ||||
| 		else if(bonus.source == Bonus::TOWN_STRUCTURE) | ||||
| 		{ | ||||
| 			descr = bonus.description; | ||||
| 			return; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			bdescr.toString(descr); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -556,16 +567,27 @@ void TryMoveHero::applyGs(CGameState *gs) | ||||
| DLL_LINKAGE void NewStructures::applyGs(CGameState *gs) | ||||
| { | ||||
| 	CGTownInstance *t = gs->getTown(tid); | ||||
|  | ||||
| 	for(const auto & id : bid) | ||||
| 	{ | ||||
| 		assert(t->town->buildings.at(id) != nullptr); | ||||
| 		t->builtBuildings.insert(id); | ||||
|  | ||||
| 		t->updateAppearance(); | ||||
| 		auto currentBuilding = t->town->buildings.at(id); | ||||
|  | ||||
| 		if(currentBuilding->overrideBids.empty()) | ||||
| 			continue; | ||||
|  | ||||
| 		for(auto overrideBid : currentBuilding->overrideBids) | ||||
| 		{ | ||||
| 			t->overriddenBuildings.insert(overrideBid); | ||||
| 			t->deleteTownBonus(overrideBid); | ||||
| 		} | ||||
| 	} | ||||
| 	t->builded = builded; | ||||
| 	t->recreateBuildingsBonuses(); | ||||
| } | ||||
|  | ||||
| DLL_LINKAGE void RazeStructures::applyGs(CGameState *gs) | ||||
| { | ||||
| 	CGTownInstance *t = gs->getTown(tid); | ||||
|   | ||||
| @@ -196,3 +196,8 @@ void LibClasses::setContent(std::shared_ptr<CContentHandler> content) | ||||
| { | ||||
| 	modh->content = content; | ||||
| } | ||||
|  | ||||
| void LibClasses::restoreAllCreaturesNodeType794() | ||||
| { | ||||
| 	creh->restoreAllCreaturesNodeType794(); | ||||
| } | ||||
|   | ||||
| @@ -36,6 +36,7 @@ class DLL_LINKAGE LibClasses | ||||
| 	void makeNull(); //sets all handler pointers to null | ||||
| 	std::shared_ptr<CContentHandler> getContent() const; | ||||
| 	void setContent(std::shared_ptr<CContentHandler> content); | ||||
| 	void restoreAllCreaturesNodeType794(); | ||||
|  | ||||
| public: | ||||
| 	bool IS_AI_ENABLED; //unused? | ||||
| @@ -69,6 +70,9 @@ public: | ||||
| 		h & heroh; | ||||
| 		h & arth; | ||||
| 		h & creh; | ||||
| 		if(!h.saving && version < 794) | ||||
| 			restoreAllCreaturesNodeType794(); | ||||
|  | ||||
| 		h & townh; | ||||
| 		h & objh; | ||||
| 		h & objtypeh; | ||||
|   | ||||
| @@ -21,6 +21,7 @@ | ||||
| #include "../mapping/CMap.h" | ||||
| #include "../CPlayerState.h" | ||||
| #include "../serializer/JsonSerializeFormat.h" | ||||
| #include "../HeroBonus.h" | ||||
|  | ||||
| std::vector<const CArtifact *> CGTownInstance::merchantArtifacts; | ||||
| std::vector<int> CGTownInstance::universitySkills; | ||||
| @@ -435,8 +436,6 @@ void CGDwelling::serializeJsonOptions(JsonSerializeFormat & handler) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| TPropagatorPtr CGTownInstance::emptyPropagator = TPropagatorPtr(); | ||||
|  | ||||
| int CGTownInstance::getSightRadius() const //returns sight distance | ||||
| { | ||||
| 	auto ret = CBuilding::HEIGHT_NO_TOWER; | ||||
| @@ -753,6 +752,17 @@ void CGTownInstance::tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID) | ||||
| 		bonusingBuildings.push_back(new COPWBonus(bid, subID, this)); | ||||
| } | ||||
|  | ||||
| void CGTownInstance::initOverriddenBids() | ||||
| { | ||||
| 	for(const auto & bid : builtBuildings) | ||||
| 	{ | ||||
| 		auto & overrideThem = town->buildings.at(bid)->overrideBids; | ||||
|  | ||||
| 		for(auto & overrideIt : overrideThem) | ||||
| 			overriddenBuildings.insert(overrideIt); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGTownInstance::tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID) | ||||
| { | ||||
| 	auto bid = town->getBuildingType(subID); | ||||
| @@ -765,6 +775,9 @@ void CGTownInstance::addTownBonuses() | ||||
| { | ||||
| 	for(const auto & kvp : town->buildings) | ||||
| 	{ | ||||
| 		if(vstd::contains(overriddenBuildings, kvp.first)) | ||||
| 			continue; | ||||
|  | ||||
| 		if(kvp.second->IsVisitingBonus()) | ||||
| 			bonusingBuildings.push_back(new CTownBonus(kvp.second->bid, kvp.second->subId, this)); | ||||
|  | ||||
| @@ -773,6 +786,36 @@ void CGTownInstance::addTownBonuses() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGTownInstance::deleteTownBonus(BuildingID::EBuildingID bid) | ||||
| { | ||||
| 	size_t i = 0; | ||||
| 	CGTownBuilding * freeIt = nullptr; | ||||
|  | ||||
| 	for(i = 0; i != bonusingBuildings.size(); i++) | ||||
| 	{ | ||||
| 		if(bonusingBuildings[i]->getBuildingType() == bid) | ||||
| 		{ | ||||
| 			freeIt = bonusingBuildings[i]; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if(freeIt == nullptr) | ||||
| 		return; | ||||
|  | ||||
| 	auto building = town->buildings.at(bid); | ||||
| 	auto isVisitingBonus = building->IsVisitingBonus(); | ||||
| 	auto isWeekBonus = building->IsWeekBonus(); | ||||
|  | ||||
| 	if(!isVisitingBonus && !isWeekBonus) | ||||
| 		return; | ||||
|  | ||||
| 	bonusingBuildings.erase(bonusingBuildings.begin() + i); | ||||
|  | ||||
| 	if(isVisitingBonus) | ||||
| 		delete (CTownBonus *)freeIt; | ||||
| 	else if(isWeekBonus) | ||||
| 		delete (COPWBonus *)freeIt; | ||||
| } | ||||
|  | ||||
| void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structures | ||||
| { | ||||
| @@ -794,17 +837,18 @@ void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structu | ||||
| 				creatures[level].second.push_back(town->creatures[level][upgradeNum]); | ||||
| 		} | ||||
| 	} | ||||
| 	initOverriddenBids(); | ||||
| 	addTownBonuses(); //add special bonuses from buildings to the bonusingBuildings vector. | ||||
| 	recreateBuildingsBonuses(); | ||||
| 	updateAppearance(); | ||||
| } | ||||
|  | ||||
| void CGTownInstance::updateBonusingBuildings() | ||||
| void CGTownInstance::updateBonusingBuildings() //update to version 792 | ||||
| { | ||||
| 	if (this->town->faction != nullptr) | ||||
| 	if(this->town->faction != nullptr) | ||||
| 	{ | ||||
| 		//firstly, update subtype for the Bonusing objects, which are already stored in the bonusing list | ||||
| 		for (auto building : bonusingBuildings) //no garrison bonuses here, only week and visiting bonuses | ||||
| 		for(auto building : bonusingBuildings) //no garrison bonuses here, only week and visiting bonuses | ||||
| 		{ | ||||
| 			switch (this->town->faction->index) | ||||
| 			{ | ||||
| @@ -838,7 +882,7 @@ void CGTownInstance::updateBonusingBuildings() | ||||
| 		} | ||||
| 	} | ||||
| 	//secondly, supplement bonusing buildings list and active bonuses; subtypes for these objects are already set in update792 | ||||
| 	for (auto & kvp : town->buildings) | ||||
| 	for(auto & kvp : town->buildings) | ||||
| 	{ | ||||
| 		auto & building = kvp.second; | ||||
|  | ||||
| @@ -864,6 +908,25 @@ void CGTownInstance::updateBonusingBuildings() | ||||
| 	recreateBuildingsBonuses(); ///Clear all bonuses and recreate | ||||
| } | ||||
|  | ||||
| void CGTownInstance::updateTown794() | ||||
| { | ||||
| 	for(auto builtBuilding : builtBuildings) | ||||
| 	{ | ||||
| 		auto building = town->buildings.at(builtBuilding); | ||||
|  | ||||
| 		for(auto overriddenBid : building->overrideBids) | ||||
| 			overriddenBuildings.insert(overriddenBid); | ||||
| 	} | ||||
| 	for(auto & kvp : town->buildings) | ||||
| 	{ | ||||
| 		auto & building = kvp.second; | ||||
| 		//The building acts as a visiting bonus and it has not been overridden. | ||||
| 		if(building->IsVisitingBonus() && overriddenBuildings.find(kvp.first) == overriddenBuildings.end()) | ||||
| 			tryAddVisitingBonus(building->subId); | ||||
| 	} | ||||
| 	recreateBuildingsBonuses(); | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const | ||||
| { | ||||
| 	return (this->town->faction != nullptr && this->town->faction->index == type && hasBuilt(bid)); | ||||
| @@ -1184,112 +1247,30 @@ void CGTownInstance::updateMoraleBonusFromArmy() | ||||
|  | ||||
| void CGTownInstance::recreateBuildingsBonuses() | ||||
| { | ||||
| 	static TPropagatorPtr playerProp(new CPropagatorNodeType(PLAYER)); | ||||
|  | ||||
| 	BonusList bl; | ||||
| 	getExportedBonusList().getBonuses(bl, Selector::sourceType()(Bonus::TOWN_STRUCTURE)); | ||||
|  | ||||
| 	for(auto b : bl) | ||||
| 		removeBonus(b); | ||||
|  | ||||
| 	//tricky! -> checks tavern only if no bratherhood of sword or not a castle | ||||
| 	if(!addBonusIfBuilt(BuildingSubID::BROTHERHOOD_OF_SWORD, Bonus::MORALE, +2)) | ||||
| 		addBonusIfBuilt(BuildingID::TAVERN, Bonus::MORALE, +1); | ||||
| 	for(auto bid : builtBuildings) | ||||
| 	{ | ||||
| 		if(vstd::contains(overriddenBuildings, bid)) //tricky! -> checks tavern only if no bratherhood of sword | ||||
| 			continue; | ||||
|  | ||||
| 	addBonusIfBuilt(BuildingSubID::FOUNTAIN_OF_FORTUNE, Bonus::LUCK, +2); //fountain of fortune | ||||
| 	addBonusIfBuilt(BuildingSubID::SPELL_POWER_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::SPELL_POWER);//works as Brimstone Clouds | ||||
| 	addBonusIfBuilt(BuildingSubID::ATTACK_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::ATTACK);//works as Blood Obelisk | ||||
| 	addBonusIfBuilt(BuildingSubID::DEFENSE_GARRISON_BONUS, Bonus::PRIMARY_SKILL, +2, PrimarySkill::DEFENSE);//works as Glyphs of Fear | ||||
| 	addBonusIfBuilt(BuildingSubID::LIGHTHOUSE, Bonus::SEA_MOVEMENT, +500, playerProp); | ||||
| 		auto building = town->buildings.at(bid); | ||||
|  | ||||
| 	if(subID == ETownType::CASTLE) //castle | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::MORALE, +2, playerProp); //colossus | ||||
| 	} | ||||
| 	else if(subID == ETownType::RAMPART) //rampart | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::LUCK, +2, playerProp); //guardian spirit | ||||
| 	} | ||||
| 	else if(subID == ETownType::TOWER) //tower | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +15, PrimarySkill::KNOWLEDGE); //grail | ||||
| 	} | ||||
| 	else if(subID == ETownType::NECROPOLIS) //necropolis | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::COVER_OF_DARKNESS,    Bonus::DARKNESS, +20); | ||||
| 		addBonusIfBuilt(BuildingID::NECROMANCY_AMPLIFIER, Bonus::SECONDARY_SKILL_PREMY, +10, playerProp, SecondarySkill::NECROMANCY); //necromancy amplifier | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::SECONDARY_SKILL_PREMY, +20, playerProp, SecondarySkill::NECROMANCY); //Soul prison | ||||
| 	} | ||||
| 	else if(subID == ETownType::DUNGEON) //Dungeon | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +12, PrimarySkill::SPELL_POWER); //grail | ||||
| 	} | ||||
| 	else if(subID == ETownType::STRONGHOLD) //Stronghold | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +20, PrimarySkill::ATTACK); //grail | ||||
| 	} | ||||
| 	else if(subID == ETownType::FORTRESS) //Fortress | ||||
| 	{ | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +10, PrimarySkill::ATTACK); //grail | ||||
| 		addBonusIfBuilt(BuildingID::GRAIL, Bonus::PRIMARY_SKILL, +10, PrimarySkill::DEFENSE); //grail | ||||
| 	} | ||||
| 	else if(boost::algorithm::ends_with(this->town->faction->identifier, ":cove") && hasBuilt(BuildingID::GRAIL)) | ||||
| 	{ | ||||
| 		static TPropagatorPtr lsProp(new CPropagatorNodeType(ALL_CREATURES)); | ||||
| 		static auto factionLimiter = std::make_shared<CreatureFactionLimiter>(this->town->faction->index); | ||||
| 		auto b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::NO_TERRAIN_PENALTY, Bonus::TOWN_STRUCTURE, 0, BuildingID::GRAIL, "", -1); | ||||
| 		if(building->buildingBonuses.empty()) | ||||
| 			continue; | ||||
|  | ||||
| 		b->addLimiter(factionLimiter); | ||||
| 		b->addPropagator(lsProp); | ||||
| 		VLC->creh->addBonusForAllCreatures(b); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype) | ||||
| { | ||||
| 	BuildingID currentBid = BuildingID::NONE; | ||||
| 	std::ostringstream descr; | ||||
|  | ||||
| 	for(const auto & bid : builtBuildings) | ||||
| 	{ | ||||
| 		if(town->buildings.at(bid)->subId == subId) | ||||
| 		for(auto bonus : building->buildingBonuses) | ||||
| 		{ | ||||
| 			descr << town->buildings.at(bid)->Name(); | ||||
| 			currentBid = bid; | ||||
| 			break; | ||||
| 			if(bonus->propagator != nullptr && bonus->propagator->getPropagatorType() == ALL_CREATURES) | ||||
| 				VLC->creh->addBonusForAllCreatures(bonus); | ||||
| 			else | ||||
| 				addNewBonus(bonus); | ||||
| 		} | ||||
| 	} | ||||
| 	return currentBid == BuildingID::NONE ? false | ||||
| 		: addBonusImpl(currentBid, type, val, prop, descr.str(), subtype); | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype) | ||||
| { | ||||
| 	return addBonusIfBuilt(subId, type, val, emptyPropagator, subtype); | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype) | ||||
| { | ||||
| 	if(!hasBuilt(building)) | ||||
| 		return false; | ||||
| 	 | ||||
| 	std::ostringstream descr; | ||||
| 	descr << town->buildings.at(building)->Name(); | ||||
| 	return addBonusImpl(building, type, val, prop, descr.str(), subtype); | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype) | ||||
| { | ||||
| 	return addBonusIfBuilt(building, type, val, emptyPropagator, subtype); | ||||
| } | ||||
|  | ||||
| bool CGTownInstance::addBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype) | ||||
| { | ||||
| 	auto b = std::make_shared<Bonus>(Bonus::PERMANENT, type, Bonus::TOWN_STRUCTURE, val, building, description, subtype); | ||||
|  | ||||
| 	if(prop) | ||||
| 		b->addPropagator(prop); | ||||
| 	addNewBonus(b); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGTownInstance::setVisitingHero(CGHeroInstance *h) | ||||
| @@ -1738,11 +1719,11 @@ void CTownBonus::setProperty (ui8 what, ui32 val) | ||||
| void CTownBonus::onHeroVisit(const CGHeroInstance * h) const | ||||
| { | ||||
| 	ObjectInstanceID heroID = h->id; | ||||
| 	if (town->hasBuilt(bID) && visitors.find(heroID) == visitors.end()) | ||||
| 	if(town->hasBuilt(bID) && visitors.find(heroID) == visitors.end()) | ||||
| 	{ | ||||
| 		si64 val = 0; | ||||
| 		InfoWindow iw; | ||||
| 		PrimarySkill::PrimarySkill what = PrimarySkill::ATTACK; | ||||
| 		PrimarySkill::PrimarySkill what = PrimarySkill::NONE; | ||||
|  | ||||
| 		switch (bType) | ||||
| 		{ | ||||
| @@ -1775,15 +1756,51 @@ void CTownBonus::onHeroVisit(const CGHeroInstance * h) const | ||||
| 			val = 1; | ||||
| 			iw.components.push_back(Component(Component::PRIM_SKILL, 1, 1, 0)); | ||||
| 			break; | ||||
|  | ||||
| 		case BuildingSubID::CUSTOM_VISITING_BONUS: | ||||
| 			const auto building = town->town->buildings.at(bID); | ||||
| 			if(!h->hasBonusFrom(Bonus::TOWN_STRUCTURE, Bonus::getSid32(building->town->faction->index, building->bid))) | ||||
| 			{ | ||||
| 				const auto & bonuses = building->onVisitBonuses; | ||||
| 				applyBonuses(const_cast<CGHeroInstance *>(h), bonuses); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		if(what != PrimarySkill::NONE) | ||||
| 		{ | ||||
| 			iw.player = cb->getOwner(heroID); | ||||
| 			iw.text << getVisitingBonusGreeting(); | ||||
| 			cb->showInfoDialog(&iw); | ||||
| 			cb->changePrimSkill(cb->getHero(heroID), what, val); | ||||
| 			town->addHeroToStructureVisitors(h, indexOnTV); | ||||
| 		} | ||||
| 		iw.player = cb->getOwner(heroID); | ||||
| 		iw.text << getVisitingBonusGreeting(); | ||||
| 		cb->showInfoDialog(&iw); | ||||
| 		cb->changePrimSkill(cb->getHero(heroID), what, val); | ||||
| 		town->addHeroToStructureVisitors(h, indexOnTV); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CTownBonus::applyBonuses(CGHeroInstance * h, const BonusList & bonuses) const | ||||
| { | ||||
| 	auto addToVisitors = false; | ||||
|  | ||||
| 	for(auto bonus : bonuses) | ||||
| 	{ | ||||
| 		GiveBonus gb; | ||||
| 		InfoWindow iw; | ||||
|  | ||||
| 		gb.bonus = * bonus; | ||||
| 		gb.id = h->id.getNum(); | ||||
| 		cb->giveHeroBonus(&gb); | ||||
|  | ||||
| 		if(bonus->duration == Bonus::PERMANENT) | ||||
| 			addToVisitors = true; | ||||
|  | ||||
| 		iw.player = cb->getOwner(h->id); | ||||
| 		iw.text << getCustomBonusGreeting(gb.bonus); | ||||
| 		cb->showInfoDialog(&iw); | ||||
| 	} | ||||
| 	if(addToVisitors) | ||||
| 		town->addHeroToStructureVisitors(h, indexOnTV); | ||||
| } | ||||
|  | ||||
| GrowthInfo::Entry::Entry(const std::string &format, int _count) | ||||
| 	: count(_count) | ||||
| { | ||||
| @@ -1851,3 +1868,22 @@ const std::string CGTownBuilding::getVisitingBonusGreeting() const | ||||
| 	town->town->setGreeting(bType, bonusGreeting); | ||||
| 	return bonusGreeting; | ||||
| } | ||||
|  | ||||
| const std::string CGTownBuilding::getCustomBonusGreeting(const Bonus & bonus) | ||||
| { | ||||
| 	auto bonusGreeting = std::string(VLC->generaltexth->localizedTexts["townHall"]["greetingCustomBonus"].String()); //"%s gives you +%d %s%s" | ||||
| 	std::string param = ""; | ||||
| 	std::string until = ""; | ||||
|  | ||||
| 	if(bonus.type == Bonus::MORALE) | ||||
| 		param = VLC->generaltexth->allTexts[384]; | ||||
| 	else if(bonus.type == Bonus::LUCK) | ||||
| 		param = VLC->generaltexth->allTexts[385]; | ||||
|  | ||||
| 	until = bonus.duration == (ui16)Bonus::ONE_BATTLE | ||||
| 		? VLC->generaltexth->localizedTexts["townHall"]["greetingCustomUntil"].String() : "."; | ||||
|  | ||||
| 	boost::format fmt = boost::format(bonusGreeting) % bonus.description % bonus.val % param % until; | ||||
| 	std::string greeting = fmt.str(); | ||||
| 	return greeting; | ||||
| } | ||||
|   | ||||
| @@ -133,6 +133,7 @@ protected: | ||||
| 	BuildingSubID::EBuildingSubID bType; | ||||
|  | ||||
| 	const std::string getVisitingBonusGreeting() const; | ||||
| 	static const std::string getCustomBonusGreeting(const Bonus & bonus); | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE COPWBonus : public CGTownBuilding | ||||
| @@ -169,6 +170,9 @@ public: | ||||
| 		h & static_cast<CGTownBuilding&>(*this); | ||||
| 		h & visitors; | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	void applyBonuses(CGHeroInstance * h, const BonusList & bonuses) const; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CTownAndVisitingHero : public CBonusSystemNode | ||||
| @@ -205,7 +209,9 @@ public: | ||||
| 	ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero; | ||||
| 	ui32 identifier; //special identifier from h3m (only > RoE maps) | ||||
| 	si32 alignment; | ||||
| 	std::set<BuildingID> forbiddenBuildings, builtBuildings; | ||||
| 	std::set<BuildingID> forbiddenBuildings; | ||||
| 	std::set<BuildingID> builtBuildings; | ||||
| 	std::set<BuildingID> overriddenBuildings; ///buildings which bonuses are overridden and should not be applied | ||||
| 	std::vector<CGTownBuilding*> bonusingBuildings; | ||||
| 	std::vector<SpellID> possibleSpells, obligatorySpells; | ||||
| 	std::vector<std::vector<SpellID> > spells; //spells[level] -> vector of spells, first will be available in guild | ||||
| @@ -237,8 +243,8 @@ public: | ||||
| 		h & events; | ||||
| 		h & bonusingBuildings; | ||||
|  | ||||
| 		for (std::vector<CGTownBuilding*>::iterator i = bonusingBuildings.begin(); i!=bonusingBuildings.end(); i++) | ||||
| 			(*i)->town = this; | ||||
| 		for(auto * bonusingBuilding : bonusingBuildings) | ||||
| 			bonusingBuilding->town = this; | ||||
|  | ||||
| 		h & town; | ||||
| 		h & townAndVis; | ||||
| @@ -256,6 +262,11 @@ public: | ||||
|  | ||||
| 		if(!h.saving && version < 793) | ||||
| 			updateBonusingBuildings(); | ||||
|  | ||||
| 		if(version >= 794) | ||||
| 			h & overriddenBuildings; | ||||
| 		else if(!h.saving) | ||||
| 			updateTown794(); | ||||
| 	} | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| @@ -264,11 +275,6 @@ public: | ||||
| 	void updateMoraleBonusFromArmy() override; | ||||
| 	void deserializationFix(); | ||||
| 	void recreateBuildingsBonuses(); | ||||
| 	///bid: param to bind a building with a bonus, subId: param to check if already built | ||||
| 	bool addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype = -1); | ||||
| 	bool addBonusIfBuilt(BuildingSubID::EBuildingSubID subId, Bonus::BonusType type, int val, int subtype = -1); | ||||
| 	bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr &prop, int subtype = -1); //returns true if building is built and bonus has been added | ||||
| 	bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype = -1); //convienence version of above | ||||
| 	void setVisitingHero(CGHeroInstance *h); | ||||
| 	void setGarrisonedHero(CGHeroInstance *h); | ||||
| 	const CArmedInstance *getUpperArmy() const; //garrisoned hero if present or the town itself | ||||
| @@ -318,6 +324,7 @@ public: | ||||
| 	void removeCapitols (PlayerColor owner) const; | ||||
| 	void clearArmy() const; | ||||
| 	void addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID) const; //hero must be visiting or garrisoned in town | ||||
| 	void deleteTownBonus(BuildingID::EBuildingID bid); | ||||
|  | ||||
| 	const CTown * getTown() const ; | ||||
|  | ||||
| @@ -336,7 +343,6 @@ public: | ||||
| 	static void reset(); | ||||
|  | ||||
| protected: | ||||
| 	static TPropagatorPtr emptyPropagator; | ||||
| 	void setPropertyDer(ui8 what, ui32 val) override; | ||||
| 	void serializeJsonOptions(JsonSerializeFormat & handler) override; | ||||
|  | ||||
| @@ -344,9 +350,10 @@ private: | ||||
| 	int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<ConstTransitivePtr<CGDwelling> >& dwellings) const; | ||||
| 	void updateBonusingBuildings(); | ||||
| 	bool hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const; | ||||
| 	bool addBonusImpl(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr & prop, const std::string & description, int subtype = -1); | ||||
| 	bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const; | ||||
| 	void tryAddOnePerWeekBonus(BuildingSubID::EBuildingSubID subID); | ||||
| 	void tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID); | ||||
| 	void initOverriddenBids(); | ||||
| 	void addTownBonuses(); | ||||
| 	void updateTown794(); //populate overriddenBuildings and vanila bonuses for old saves  | ||||
| }; | ||||
|   | ||||
| @@ -260,7 +260,7 @@ void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) con | ||||
| 	GiveBonus gbonus; | ||||
| 	gbonus.bonus.type = Bonus::NONE; | ||||
| 	gbonus.id = heroID.getNum(); | ||||
| 	gbonus.bonus.duration = duration; | ||||
| 	gbonus.bonus.duration = (Bonus::BonusDuration)duration; | ||||
| 	gbonus.bonus.source = Bonus::OBJECT; | ||||
| 	gbonus.bonus.sid = ID; | ||||
| 	cb->giveHeroBonus(&gbonus); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| #include "../ConstTransitivePtr.h" | ||||
| #include "../GameConstants.h" | ||||
|  | ||||
| const ui32 SERIALIZATION_VERSION = 793; | ||||
| const ui32 SERIALIZATION_VERSION = 794; | ||||
| const ui32 MINIMAL_SERIALIZATION_VERSION = 753; | ||||
| const std::string SAVEGAME_MAGIC = "VCMISVG"; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user