mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Feature: Lodestar Grail should work.
This commit is contained in:
		| @@ -135,9 +135,19 @@ std::string CCreature::nodeName() const | ||||
| 	return "\"" + namePl + "\""; | ||||
| } | ||||
|  | ||||
| bool CCreature::isItNativeTerrain(int terrain) const | ||||
| bool CCreature::isItNativeTerrain(ETerrainType::EETerrainType terrain) const | ||||
| { | ||||
| 	return VLC->townh->factions[faction]->nativeTerrain == terrain; | ||||
| 	auto native = getNativeTerrain(); | ||||
| 	return native == terrain || native == ETerrainType::ANY_TERRAIN; | ||||
| } | ||||
|  | ||||
| ETerrainType::EETerrainType CCreature::getNativeTerrain() const | ||||
| { | ||||
| 	//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses | ||||
| 	//and in the CGHeroInstance::getNativeTerrain() to setup mevement bonuses or/and penalties. | ||||
| 	return hasBonusOfType(Bonus::NO_TERRAIN_PENALTY) ? | ||||
| 		ETerrainType::ANY_TERRAIN | ||||
| 		: (ETerrainType::EETerrainType)VLC->townh->factions[faction]->nativeTerrain; | ||||
| } | ||||
|  | ||||
| void CCreature::setId(CreatureID ID) | ||||
| @@ -210,10 +220,11 @@ CCreatureHandler::CCreatureHandler() | ||||
| 	VLC->creh = this; | ||||
|  | ||||
| 	allCreatures.setDescription("All creatures"); | ||||
| 	allCreatures.setNodeType(CBonusSystemNode::ENodeTypes::ALL_CREATURES); | ||||
| 	creaturesOfLevel[0].setDescription("Creatures of unnormalized tier"); | ||||
|  | ||||
| 	for(int i = 1; i < ARRAY_COUNT(creaturesOfLevel); i++) | ||||
| 		creaturesOfLevel[i].setDescription("Creatures of tier " + boost::lexical_cast<std::string>(i)); | ||||
|  | ||||
| 	loadCommanders(); | ||||
| } | ||||
|  | ||||
| @@ -1194,6 +1205,11 @@ void CCreatureHandler::addBonusForAllCreatures(std::shared_ptr<Bonus> b) | ||||
| 	allCreatures.addNewBonus(b); | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::removeBonusesFromAllCreatures() | ||||
| { | ||||
| 	allCreatures.removeBonuses(Selector::all); | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::buildBonusTreeForTiers() | ||||
| { | ||||
| 	for(CCreature *c : creatures) | ||||
|   | ||||
| @@ -114,7 +114,14 @@ public: | ||||
|  | ||||
| 	ArtifactID warMachine; | ||||
|  | ||||
| 	bool isItNativeTerrain(int terrain) const; | ||||
| 	bool isItNativeTerrain(ETerrainType::EETerrainType terrain) const; | ||||
| 	/** | ||||
| 	Returns creature native terrain considering some terrain bonuses. | ||||
| 	@param considerBonus is used to avoid Dead Lock when this method is called inside getAllBonuses | ||||
| 	considerBonus = true is called from Pathfinder and fills actual nativeTerrain considering bonus(es). | ||||
| 	considerBonus = false is called on Battle init and returns already prepared nativeTerrain without Bonus system calling. | ||||
| 	*/ | ||||
| 	ETerrainType::EETerrainType getNativeTerrain() const; | ||||
| 	bool isDoubleWide() const; //returns true if unit is double wide on battlefield | ||||
| 	bool isFlying() const; //returns true if it is a flying unit | ||||
| 	bool isShooting() const; //returns true if unit can shoot | ||||
| @@ -241,6 +248,7 @@ public: | ||||
| 	CreatureID pickRandomMonster(CRandomGenerator & rand, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any | ||||
| 	void addBonusForTier(int tier, std::shared_ptr<Bonus> b); //tier must be <1-7> | ||||
| 	void addBonusForAllCreatures(std::shared_ptr<Bonus> b); | ||||
| 	void removeBonusesFromAllCreatures(); | ||||
|  | ||||
| 	CCreatureHandler(); | ||||
| 	~CCreatureHandler(); | ||||
|   | ||||
| @@ -1746,6 +1746,8 @@ void CGameState::initTowns() | ||||
| void CGameState::initMapObjects() | ||||
| { | ||||
| 	logGlobal->debug("\tObject initialization"); | ||||
| 	VLC->creh->removeBonusesFromAllCreatures(); | ||||
|  | ||||
| //	objCaller->preInit(); | ||||
| 	for(CGObjectInstance *obj : map->objects) | ||||
| 	{ | ||||
|   | ||||
| @@ -515,7 +515,7 @@ struct DLL_LINKAGE TurnInfo | ||||
| 	TConstBonusListPtr bonuses; | ||||
| 	mutable int maxMovePointsLand; | ||||
| 	mutable int maxMovePointsWater; | ||||
| 	int nativeTerrain; | ||||
| 	ETerrainType::EETerrainType nativeTerrain; | ||||
|  | ||||
| 	TurnInfo(const CGHeroInstance * Hero, const int Turn = 0); | ||||
| 	bool isLayerAvailable(const EPathfindingLayer layer) const; | ||||
|   | ||||
| @@ -29,14 +29,16 @@ CStack::CStack(const CStackInstance * Base, PlayerColor O, int I, ui8 Side, Slot | ||||
| 	owner(O), | ||||
| 	slot(S), | ||||
| 	side(Side), | ||||
| 	initialPosition() | ||||
| 	initialPosition(), | ||||
| 	nativeTerrain(ETerrainType::WRONG) | ||||
| { | ||||
| 	health.init(); //??? | ||||
| } | ||||
|  | ||||
| CStack::CStack() | ||||
| 	: CBonusSystemNode(STACK_BATTLE), | ||||
| 	CUnitState() | ||||
| 	CUnitState(), | ||||
| 	nativeTerrain(ETerrainType::WRONG) | ||||
| { | ||||
| 	base = nullptr; | ||||
| 	type = nullptr; | ||||
| @@ -84,8 +86,8 @@ void CStack::localInit(BattleInfo * battleInfo) | ||||
| 		attachTo(army); | ||||
| 		attachTo(const_cast<CCreature *>(type)); | ||||
| 	} | ||||
|  | ||||
| 	CUnitState::localInit(this); | ||||
| 	nativeTerrain = type->getNativeTerrain(); //save nativeTerrain in the variable on the battle start to avoid dead lock | ||||
| 	CUnitState::localInit(this); //it causes execution of the CStack::isOnNativeTerrain where nativeTerrain will be considered | ||||
| 	position = initialPosition; | ||||
| } | ||||
|  | ||||
| @@ -323,7 +325,9 @@ bool CStack::canBeHealed() const | ||||
|  | ||||
| bool CStack::isOnNativeTerrain() const | ||||
| { | ||||
| 	return type->isItNativeTerrain(battle->getTerrainType()); | ||||
| 	//this code is called from CreatureTerrainLimiter::limit on battle start | ||||
| 	auto res = nativeTerrain == ETerrainType::ANY_TERRAIN || nativeTerrain == battle->getTerrainType(); | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| bool CStack::isOnTerrain(int terrain) const | ||||
|   | ||||
| @@ -27,6 +27,7 @@ public: | ||||
|  | ||||
| 	ui32 ID; //unique ID of stack | ||||
| 	const CCreature * type; | ||||
| 	ETerrainType::EETerrainType nativeTerrain; //tmp variable to save native terrain value on battle init | ||||
| 	ui32 baseAmount; | ||||
|  | ||||
| 	PlayerColor owner; //owner - player color (255 for neutrals) | ||||
|   | ||||
| @@ -172,7 +172,7 @@ std::vector<BattleHex> CTown::defaultMoatHexes() | ||||
| 	return moatHexes; | ||||
| } | ||||
|  | ||||
| std::string CTown::getFactionName() const | ||||
| std::string CTown::getLocalizedFactionName() const | ||||
| { | ||||
| 	if(faction == nullptr) | ||||
| 		return "Random"; | ||||
| @@ -510,7 +510,7 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons | ||||
| 		if(stringID == source["upgrades"].String()) | ||||
| 		{ | ||||
| 			throw std::runtime_error(boost::str(boost::format("Building with ID '%s' of town '%s' can't be an upgrade of the same building.") % | ||||
| 												stringID % ret->town->getFactionName())); | ||||
| 												stringID % ret->town->getLocalizedFactionName())); | ||||
| 		} | ||||
|  | ||||
| 		VLC->modh->identifiers.requestIdentifier(ret->town->getBuildingScope(), source["upgrades"], [=](si32 identifier) | ||||
|   | ||||
| @@ -224,7 +224,7 @@ public: | ||||
| 	// TODO: remove once save and mod compatability not needed | ||||
| 	static std::vector<BattleHex> defaultMoatHexes(); | ||||
|  | ||||
| 	std::string getFactionName() const; | ||||
| 	std::string getLocalizedFactionName() const; | ||||
| 	std::string getBuildingScope() const; | ||||
| 	std::set<si32> getAllBuildings() const; | ||||
| 	const CBuilding * getSpecialBuilding(BuildingSubID::EBuildingSubID subID) const; | ||||
|   | ||||
| @@ -860,8 +860,9 @@ class DLL_LINKAGE ETerrainType | ||||
| public: | ||||
| 	enum EETerrainType | ||||
| 	{ | ||||
| 		ANY_TERRAIN = -3, | ||||
| 		WRONG = -2, BORDER = -1, DIRT, SAND, GRASS, SNOW, SWAMP, | ||||
| 		ROUGH, SUBTERRANEAN, LAVA, WATER, ROCK | ||||
| 		ROUGH, SUBTERRANEAN, LAVA, WATER, ROCK // ROCK is also intended to be max value. | ||||
| 	}; | ||||
|  | ||||
| 	ETerrainType(EETerrainType _num = WRONG) : num(_num) | ||||
|   | ||||
| @@ -1980,13 +1980,13 @@ JsonNode CreatureTerrainLimiter::toJsonNode() const | ||||
| 	return root; | ||||
| } | ||||
|  | ||||
| CreatureFactionLimiter::CreatureFactionLimiter(int Faction) | ||||
| 	: faction(Faction) | ||||
| CreatureFactionLimiter::CreatureFactionLimiter(TFaction creatureFaction) | ||||
| 	: faction(creatureFaction) | ||||
| { | ||||
| } | ||||
|  | ||||
| CreatureFactionLimiter::CreatureFactionLimiter() | ||||
| 	: faction(-1) | ||||
| 	: faction((TFaction)-1) | ||||
| { | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -520,7 +520,6 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus> | ||||
|  | ||||
| DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus); | ||||
|  | ||||
|  | ||||
| class DLL_LINKAGE BonusList | ||||
| { | ||||
| public: | ||||
| @@ -758,7 +757,7 @@ public: | ||||
| 	enum ENodeTypes | ||||
| 	{ | ||||
| 		UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALTY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM, | ||||
| 		TOWN_AND_VISITOR, BATTLE, COMMANDER, GLOBAL_EFFECTS | ||||
| 		TOWN_AND_VISITOR, BATTLE, COMMANDER, GLOBAL_EFFECTS, ALL_CREATURES | ||||
| 	}; | ||||
| private: | ||||
| 	BonusList bonuses; //wielded bonuses (local or up-propagated here) | ||||
| @@ -1062,9 +1061,9 @@ public: | ||||
| class DLL_LINKAGE CreatureFactionLimiter : public ILimiter //applies only to creatures of given faction | ||||
| { | ||||
| public: | ||||
| 	si8 faction; | ||||
| 	TFaction faction; | ||||
| 	CreatureFactionLimiter(); | ||||
| 	CreatureFactionLimiter(int TerrainType); | ||||
| 	CreatureFactionLimiter(TFaction faction); | ||||
|  | ||||
| 	int limit(const BonusLimitationContext &context) const override; | ||||
| 	virtual std::string toString() const override; | ||||
|   | ||||
| @@ -89,10 +89,13 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	else if(ti->nativeTerrain != from.terType && !ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType)) | ||||
| 	else if(ti->nativeTerrain != from.terType //the terrain is not native | ||||
| 		&& ti->nativeTerrain != ETerrainType::ANY_TERRAIN //no special creature bonus | ||||
| 		&& !ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType) //no special movement bonus | ||||
| 		) | ||||
| 	{ | ||||
| 		static const CSelector selectorPATHFINDING = Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::PATHFINDING); | ||||
| 		static const std::string keyPATHFINDING = "type_"+std::to_string((si32)Bonus::SECONDARY_SKILL_PREMY)+"s_"+std::to_string((si32)SecondarySkill::PATHFINDING); | ||||
| 		static const std::string keyPATHFINDING = "type_" + std::to_string((si32)Bonus::SECONDARY_SKILL_PREMY) + "s_" + std::to_string((si32)SecondarySkill::PATHFINDING); | ||||
|  | ||||
| 		ret = VLC->heroh->terrCosts[from.terType]; | ||||
| 		ret -= valOfBonuses(selectorPATHFINDING, keyPATHFINDING); | ||||
| @@ -102,7 +105,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int CGHeroInstance::getNativeTerrain() const | ||||
| ETerrainType::EETerrainType CGHeroInstance::getNativeTerrain() const | ||||
| { | ||||
| 	// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army. | ||||
| 	// This is clearly bug in H3 however intended behaviour is not clear. | ||||
| @@ -110,19 +113,19 @@ int CGHeroInstance::getNativeTerrain() const | ||||
| 	// will always have best penalty without any influence from player-defined stacks order | ||||
|  | ||||
| 	// TODO: What should we do if all hero stacks are neutral creatures? | ||||
| 	int nativeTerrain = -1; | ||||
| 	ETerrainType::EETerrainType nativeTerrain = ETerrainType::BORDER; | ||||
|  | ||||
| 	for(auto stack : stacks) | ||||
| 	{ | ||||
| 		int stackNativeTerrain = VLC->townh->factions[stack.second->type->faction]->nativeTerrain; | ||||
| 		if(stackNativeTerrain == -1) | ||||
| 			continue; | ||||
| 		ETerrainType::EETerrainType stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar. | ||||
|  | ||||
| 		if(nativeTerrain == -1) | ||||
| 		if(stackNativeTerrain == ETerrainType::BORDER) | ||||
| 			continue; | ||||
| 		if(nativeTerrain == ETerrainType::BORDER) | ||||
| 			nativeTerrain = stackNativeTerrain; | ||||
| 		else if(nativeTerrain != stackNativeTerrain) | ||||
| 			return -1; | ||||
| 			return ETerrainType::BORDER; | ||||
| 	} | ||||
|  | ||||
| 	return nativeTerrain; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -162,7 +162,7 @@ public: | ||||
| 	bool needsLastStack()const override; | ||||
| 	TFaction getFaction() const; | ||||
| 	ui32 getTileCost(const TerrainTile &dest, const TerrainTile &from, const TurnInfo * ti) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling | ||||
| 	int getNativeTerrain() const; | ||||
| 	ETerrainType::EETerrainType getNativeTerrain() const; | ||||
| 	ui32 getLowestCreatureSpeed() const; | ||||
| 	int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation' | ||||
| 	si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day | ||||
|   | ||||
| @@ -1232,6 +1232,16 @@ void CGTownInstance::recreateBuildingsBonuses() | ||||
| 		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); | ||||
|  | ||||
| 		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) | ||||
| @@ -1275,6 +1285,7 @@ bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, | ||||
| 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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user