浏览代码

Merge pull request #3280 from IvanSavenko/hotfix

[1.4.1] Hotfixes
Ivan Savenko 1 年之前
父节点
当前提交
a1a317aef4

+ 5 - 0
client/widgets/Slider.cpp

@@ -156,6 +156,11 @@ void CSlider::clickPressed(const Point & cursorPosition)
 
 bool CSlider::receiveEvent(const Point &position, int eventType) const
 {
+	if (eventType == LCLICK)
+	{
+		return pos.isInside(position) && !left->pos.isInside(position) && !right->pos.isInside(position);
+	}
+
 	if(eventType != WHEEL && eventType != GESTURE)
 	{
 		return CIntObject::receiveEvent(position, eventType);

+ 1 - 1
launcher/modManager/cmodlistview_moc.cpp

@@ -313,7 +313,7 @@ QString CModListView::genModInfoText(CModEntry & mod)
 
 	result += replaceIfNotEmpty(getModNames(mod.getDependencies()), lineTemplate.arg(tr("Required mods")));
 	result += replaceIfNotEmpty(getModNames(mod.getConflicts()), lineTemplate.arg(tr("Conflicting mods")));
-	result += replaceIfNotEmpty(getModNames(mod.getValue("description").toStringList()), textTemplate.arg(tr("Description")));
+	result += replaceIfNotEmpty(mod.getValue("description"), textTemplate.arg(tr("Description")));
 
 	result += "<p></p>"; // to get some empty space
 

+ 4 - 1
lib/MetaString.cpp

@@ -168,7 +168,10 @@ DLL_LINKAGE std::string MetaString::toString() const
 				boost::replace_first(dst, "%d", std::to_string(numbers[nums++]));
 				break;
 			case EMessage::REPLACE_POSITIVE_NUMBER:
-				boost::replace_first(dst, "%+d", '+' + std::to_string(numbers[nums++]));
+				if (dst.find("%+d") != std::string::npos)
+					boost::replace_first(dst, "%+d", '+' + std::to_string(numbers[nums++]));
+				else
+					boost::replace_first(dst, "%d", std::to_string(numbers[nums++]));
 				break;
 			default:
 				logGlobal->error("MetaString processing error! Received message of type %d", static_cast<int>(elem));

+ 3 - 0
lib/battle/DamageCalculator.cpp

@@ -132,6 +132,9 @@ int DamageCalculator::getActorAttackSlayer() const
 	const std::string cachingStrSlayer = "type_SLAYER";
 	static const auto selectorSlayer = Selector::type()(BonusType::SLAYER);
 
+	if (!info.defender->hasBonusOfType(BonusType::KING))
+		return 0;
+
 	auto slayerEffects = info.attacker->getBonuses(selectorSlayer, cachingStrSlayer);
 	auto slayerAffected = info.defender->unitType()->valOfBonuses(Selector::type()(BonusType::KING));
 

+ 7 - 3
lib/gameState/CGameState.cpp

@@ -1444,18 +1444,22 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		{
 			// list of players that need to control object to fulfull condition
 			// NOTE: cgameinfocallback specified explicitly in order to get const version
-			const auto & team = CGameInfoCallback::getPlayerTeam(player)->players;
+			const auto * team = CGameInfoCallback::getPlayerTeam(player);
 
 			if (condition.objectID != ObjectInstanceID::NONE) // mode A - flag one specific object, like town
 			{
-				return team.count(getObjInstance(condition.objectID)->tempOwner) != 0;
+				const auto * object = getObjInstance(condition.objectID);
+
+				if (!object)
+					return false;
+				return team->players.count(object->getOwner()) != 0;
 			}
 			else
 			{
 				for(const auto & elem : map->objects) // mode B - flag all objects of this type
 				{
 					 //check not flagged objs
-					if ( elem && elem->ID == condition.objectType.as<MapObjectID>() && team.count(elem->tempOwner) == 0 )
+					if ( elem && elem->ID == condition.objectType.as<MapObjectID>() && team->players.count(elem->getOwner()) == 0 )
 						return false;
 				}
 				return true;

+ 1 - 1
lib/mapObjectConstructors/CommonConstructors.cpp

@@ -133,7 +133,7 @@ void CHeroInstanceConstructor::afterLoadFinalization()
 	{
 		filters[entry.first] = LogicalExpression<HeroTypeID>(entry.second, [](const JsonNode & node)
 		{
-			return HeroTypeID(VLC->identifiers()->getIdentifier("hero", node.Vector()[0]).value());
+			return HeroTypeID(VLC->identifiers()->getIdentifier("hero", node.Vector()[0]).value_or(-1));
 		});
 	}
 }

+ 11 - 2
lib/mapObjects/CGTownInstance.cpp

@@ -1224,12 +1224,21 @@ TerrainId CGTownInstance::getNativeTerrain() const
 GrowthInfo::Entry::Entry(const std::string &format, int _count)
 	: count(_count)
 {
-	description = boost::str(boost::format(format) % count);
+	MetaString formatter;
+	formatter.appendRawString(format);
+	formatter.replacePositiveNumber(count);
+
+	description = formatter.toString();
 }
 
 GrowthInfo::Entry::Entry(int subID, const BuildingID & building, int _count): count(_count)
 {
-	description = boost::str(boost::format("%s %+d") % (*VLC->townh)[subID]->town->buildings.at(building)->getNameTranslated() % count);
+	MetaString formatter;
+	formatter.appendRawString("%s %+d");
+	formatter.replaceRawString((*VLC->townh)[subID]->town->buildings.at(building)->getNameTranslated());
+	formatter.replacePositiveNumber(count);
+
+	description = formatter.toString();
 }
 
 GrowthInfo::Entry::Entry(int _count, std::string fullDescription):

+ 1 - 1
lib/mapObjects/CRewardableObject.cpp

@@ -59,7 +59,7 @@ std::vector<Component> CRewardableObject::loadComponents(const CGHeroInstance *
 	if (rewardIndices.empty())
 		return result;
 
-	if (configuration.selectMode != Rewardable::SELECT_FIRST)
+	if (configuration.selectMode != Rewardable::SELECT_FIRST && rewardIndices.size() > 1)
 	{
 		for (auto index : rewardIndices)
 			result.push_back(configuration.info.at(index).reward.getDisplayedComponent(contextHero));

+ 1 - 1
lib/mapObjects/MiscObjects.cpp

@@ -937,7 +937,7 @@ void CGSignBottle::initObj(CRandomGenerator & rand)
 	{
 		auto vector = VLC->generaltexth->findStringsWithPrefix("core.randsign");
 		std::string messageIdentifier = *RandomGeneratorUtil::nextItem(vector, rand);
-		message.appendTextID(TextIdentifier("core", "randsign", messageIdentifier).get());
+		message.appendTextID(messageIdentifier);
 	}
 
 	if(ID == Obj::OCEAN_BOTTLE)

+ 1 - 1
lib/modding/CModVersion.h

@@ -10,7 +10,7 @@
 
 #pragma once
 
-#ifdef __UCLIBC__
+#if defined(__UCLIBC__) || defined(__FreeBSD__)
 #undef major
 #undef minor
 #undef patch

+ 0 - 3
lib/pathfinder/CPathfinder.cpp

@@ -162,9 +162,6 @@ void CPathfinder::calculatePaths()
 			if(neighbour->locked)
 				continue;
 
-			if (source.node->theNodeBefore && source.node->theNodeBefore->coord == neighbour->coord )
-				continue; // block U-turns
-
 			if(!hlp->isLayerAvailable(neighbour->layer))
 				continue;
 

+ 2 - 0
lib/rewardable/Limiter.cpp

@@ -30,6 +30,7 @@ Rewardable::Limiter::Limiter()
 	, heroLevel(-1)
 	, manaPercentage(0)
 	, manaPoints(0)
+	, canLearnSkills(false)
 	, primary(GameConstants::PRIMARY_SKILLS, 0)
 {
 }
@@ -45,6 +46,7 @@ bool operator==(const Rewardable::Limiter & l, const Rewardable::Limiter & r)
 	&& l.manaPoints == r.manaPoints
 	&& l.manaPercentage == r.manaPercentage
 	&& l.secondary == r.secondary
+	&& l.canLearnSkills == r.canLearnSkills
 	&& l.creatures == r.creatures
 	&& l.spells == r.spells
 	&& l.artifacts == r.artifacts

+ 2 - 2
lib/spells/CSpellHandler.cpp

@@ -107,8 +107,8 @@ const CSpell::LevelInfo & CSpell::getLevelInfo(const int32_t level) const
 {
 	if(level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
 	{
-		logGlobal->error("CSpell::getLevelInfo: invalid school level %d", level);
-		return levels.at(0);
+		logGlobal->error("CSpell::getLevelInfo: invalid school mastery level %d", level);
+		return levels.at(MasteryLevel::EXPERT);
 	}
 
 	return levels.at(level);

+ 6 - 0
lib/spells/effects/Summon.cpp

@@ -42,6 +42,12 @@ void Summon::adjustTargetTypes(std::vector<TargetType> & types) const
 
 bool Summon::applicable(Problem & problem, const Mechanics * m) const
 {
+	if (creature == CreatureID::NONE)
+	{
+		logMod->error("Attempt to summon non-existing creature!");
+		return m->adaptGenericProblem(problem);
+	}
+
 	if(exclusive)
 	{
 		//check if there are summoned creatures of other type

+ 1 - 1
server/CGameHandler.cpp

@@ -1133,7 +1133,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
 	if (guardian && getVisitingHero(guardian) != nullptr)
 		return complainRet("Cannot move hero, destination monster is busy!");
 
-	if (objectToVisit && getVisitingHero(objectToVisit) != nullptr)
+	if (objectToVisit && getVisitingHero(objectToVisit) != nullptr && getVisitingHero(objectToVisit) != h)
 		return complainRet("Cannot move hero, destination object is busy!");
 
 	if (objectToVisit &&

+ 5 - 2
server/battles/BattleActionProcessor.cpp

@@ -1032,7 +1032,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 			const CStack * actor = item.first;
 			int64_t rawDamage = item.second;
 
-			const CGHeroInstance * actorOwner = battle.battleGetFightingHero(actor->unitOwner());
+			const CGHeroInstance * actorOwner = battle.battleGetFightingHero(actor->unitSide());
 
 			if(actorOwner)
 			{
@@ -1088,7 +1088,10 @@ void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bo
 		TConstBonusListPtr spells = attacker->getBonuses(Selector::type()(attackMode));
 		for(const auto & sf : *spells)
 		{
-			spellsToCast.insert(sf->subtype.as<SpellID>());
+			if (sf->subtype.as<SpellID>() != SpellID())
+				spellsToCast.insert(sf->subtype.as<SpellID>());
+			else
+				logMod->error("Invalid spell to cast during attack!");
 		}
 		for(SpellID spellID : spellsToCast)
 		{