Browse Source

Merge pull request #3435 from IvanSavenko/bugfixing

[1.4.3] Bugfixing
Ivan Savenko 1 year ago
parent
commit
cf47fbb729

+ 12 - 3
client/CVideoHandler.cpp

@@ -634,6 +634,8 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
 	pos.y = y;
 	frameTime = 0.0;
 
+	auto lastTimePoint = boost::chrono::steady_clock::now();
+
 	while(nextFrame())
 	{
 		if(stopOnKey)
@@ -654,10 +656,17 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
 #else
 		auto packet_duration = frame->duration;
 #endif
-		double frameDurationSec = packet_duration * av_q2d(format->streams[stream]->time_base);
-		uint32_t timeToSleepMillisec = 1000 * (frameDurationSec);
+		// Framerate delay
+		double targetFrameTimeSeconds = packet_duration * av_q2d(format->streams[stream]->time_base);
+		auto targetFrameTime = boost::chrono::milliseconds(static_cast<int>(1000 * (targetFrameTimeSeconds)));
+
+		auto timePointAfterPresent = boost::chrono::steady_clock::now();
+		auto timeSpentBusy = boost::chrono::duration_cast<boost::chrono::milliseconds>(timePointAfterPresent - lastTimePoint);
+
+		if (targetFrameTime > timeSpentBusy)
+			boost::this_thread::sleep_for(targetFrameTime - timeSpentBusy);
 
-		boost::this_thread::sleep_for(boost::chrono::milliseconds(timeToSleepMillisec));
+		lastTimePoint = boost::chrono::steady_clock::now();
 	}
 
 	return true;

+ 5 - 5
config/artifacts.json

@@ -1730,7 +1730,7 @@
 		"bonuses" : [
 			{
 				"type" : "CREATURE_GROWTH",
-				"subtype" : "creatureLevel1",
+				"subtype" : "creatureLevel2",
 				"val" : 5,
 				"propagator": "VISITED_TOWN_AND_VISITOR"
 			}
@@ -1743,7 +1743,7 @@
 		"bonuses" : [
 			{
 				"type" : "CREATURE_GROWTH",
-				"subtype" : "creatureLevel2",
+				"subtype" : "creatureLevel3",
 				"val" : 4,
 				"propagator": "VISITED_TOWN_AND_VISITOR"
 			}
@@ -1756,7 +1756,7 @@
 		"bonuses" : [
 			{
 				"type" : "CREATURE_GROWTH",
-				"subtype" : "creatureLevel3",
+				"subtype" : "creatureLevel4",
 				"val" : 3,
 				"propagator": "VISITED_TOWN_AND_VISITOR"
 			}
@@ -1769,7 +1769,7 @@
 		"bonuses" : [
 			{
 				"type" : "CREATURE_GROWTH",
-				"subtype" : "creatureLevel4",
+				"subtype" : "creatureLevel5",
 				"val" : 2,
 				"propagator": "VISITED_TOWN_AND_VISITOR"
 			}
@@ -1782,7 +1782,7 @@
 		"bonuses" : [
 			{
 				"type" : "CREATURE_GROWTH",
-				"subtype" : "creatureLevel5",
+				"subtype" : "creatureLevel6",
 				"val" : 1,
 				"propagator": "VISITED_TOWN_AND_VISITOR"
 			}

+ 1 - 1
docs/modders/Bonus/Bonus_Types.md

@@ -244,7 +244,7 @@ Increased effect of spell affecting creature, ie. Aenain makes Disrupting Ray de
     "subtype" : "spell.disruptingRay",
     "type" : "SPECIAL_ADD_VALUE_ENCHANT"
 }
-``````
+```
 
 - subtype: affected spell identifier
 - additionalInfo: value to add

+ 2 - 1
lib/BattleFieldHandler.cpp

@@ -21,6 +21,7 @@ BattleFieldInfo * BattleFieldHandler::loadFromJson(const std::string & scope, co
 
 	auto * info = new BattleFieldInfo(BattleField(index), identifier);
 
+	info->modScope = scope;
 	info->graphics = ImagePath::fromJson(json["graphics"]);
 	info->icon = json["icon"].String();
 	info->name = json["name"].String();
@@ -66,7 +67,7 @@ int32_t BattleFieldInfo::getIconIndex() const
 
 std::string BattleFieldInfo::getJsonKey() const
 {
-	return identifier;
+	return modScope + ':' + identifier;
 }
 
 std::string BattleFieldInfo::getNameTextID() const

+ 1 - 0
lib/BattleFieldHandler.h

@@ -27,6 +27,7 @@ public:
 	bool isSpecial;
 	ImagePath graphics;
 	std::string name;
+	std::string modScope;
 	std::string identifier;
 	std::string icon;
 	si32 iconIndex;

+ 13 - 3
lib/CCreatureHandler.cpp

@@ -612,10 +612,20 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
 	cre->addBonus(node["attack"].Integer(), BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::ATTACK));
 	cre->addBonus(node["defense"].Integer(), BonusType::PRIMARY_SKILL, BonusSubtypeID(PrimarySkill::DEFENSE));
 
-	cre->addBonus(node["damage"]["min"].Integer(), BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin);
-	cre->addBonus(node["damage"]["max"].Integer(), BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax);
+	int minDamage = node["damage"]["min"].Integer();
+	int maxDamage = node["damage"]["max"].Integer();
 
-	assert(node["damage"]["min"].Integer() <= node["damage"]["max"].Integer());
+	if (minDamage <= maxDamage)
+	{
+		cre->addBonus(minDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin);
+		cre->addBonus(maxDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax);
+	}
+	else
+	{
+		logGlobal->error("Mod %s: creature %s has minimal damage (%d) greater than maximal damage (%d)!", scope, identifier, minDamage, maxDamage);
+		cre->addBonus(maxDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMin);
+		cre->addBonus(minDamage, BonusType::CREATURE_DAMAGE, BonusCustomSubtype::creatureDamageMax);
+	}
 
 	if(!node["shots"].isNull())
 		cre->addBonus(node["shots"].Integer(), BonusType::SHOTS);

+ 1 - 1
lib/mapObjects/CGDwelling.cpp

@@ -320,7 +320,7 @@ void CGDwelling::newTurn(CRandomGenerator & rand) const
 				creaturesAccumulate = VLC->settings()->getBoolean(EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL);
 
 			const CCreature * cre =creatures[i].second[0].toCreature();
-			TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(BonusType::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(BonusType::CREATURE_GROWTH);
+			TQuantity amount = cre->getGrowth() * (1 + cre->valOfBonuses(BonusType::CREATURE_GROWTH_PERCENT)/100) + cre->valOfBonuses(BonusType::CREATURE_GROWTH, BonusCustomSubtype::creatureLevel(cre->getLevel()));
 			if (creaturesAccumulate && ID != Obj::REFUGEE_CAMP) //camp should not try to accumulate different kinds of creatures
 				sac.creatures[i].first += amount;
 			else

+ 2 - 1
lib/mapObjects/CGTownInstance.cpp

@@ -164,7 +164,8 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
 	}
 
 	//other *-of-legion-like bonuses (%d to growth cumulative with grail)
-	TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusCustomSubtype::creatureLevel(level)));
+	// Note: bonus uses 1-based levels (Pikeman is level 1), town list uses 0-based (Pikeman in 0-th creatures entry)
+	TConstBonusListPtr bonuses = getBonuses(Selector::typeSubtype(BonusType::CREATURE_GROWTH, BonusCustomSubtype::creatureLevel(level+1)));
 	for(const auto & b : *bonuses)
 		ret.entries.emplace_back(b->val, b->Description());
 

+ 1 - 8
lib/mapping/MapFormatH3M.cpp

@@ -2223,17 +2223,10 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
 	}
 
 	{
-		std::set<SpellID> spellsMask;
+		std::set<SpellID> spellsMask = VLC->spellh->getDefaultAllowed(); // by default - include spells from mods
 
 		reader->readBitmaskSpells(spellsMask, true);
 		std::copy(spellsMask.begin(), spellsMask.end(), std::back_inserter(object->possibleSpells));
-
-		auto defaultAllowed = VLC->spellh->getDefaultAllowed();
-
-		//add all spells from mods
-		for(int i = features.spellsCount; i < defaultAllowed.size(); ++i)
-			if(defaultAllowed.count(i))
-				object->possibleSpells.emplace_back(i);
 	}
 
 	if(features.levelHOTA1)

+ 2 - 1
lib/spells/ObstacleCasterProxy.cpp

@@ -71,7 +71,8 @@ SilentCaster::SilentCaster(PlayerColor owner_, const Caster * hero_):
 
 void SilentCaster::getCasterName(MetaString & text) const
 {
-	logGlobal->error("Unexpected call to SilentCaster::getCasterName");
+	// NOTE: can be triggered (for example) if creature steps into Tower mines/moat while hero has Recanter's Cloak
+	logGlobal->debug("Unexpected call to SilentCaster::getCasterName");
 }
 
 void SilentCaster::getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const

+ 5 - 1
server/CGameHandler.cpp

@@ -3292,7 +3292,11 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
 
 			for (auto & i : ev.buildings)
 			{
-				if (!town->hasBuilt(i))
+				// Only perform action if:
+				// 1. Building exists in town (don't attempt to build Lvl 5 guild in Fortress
+				// 2. Building was not built yet
+				// othervice, silently ignore / skip it
+				if (town->town->buildings.count(i) && !town->hasBuilt(i))
 				{
 					buildStructure(town->id, i, true);
 					iw.components.emplace_back(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), i));

+ 1 - 0
server/battles/BattleActionProcessor.cpp

@@ -1301,6 +1301,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		// send empty event to client
 		// temporary(?) workaround to force animations to trigger
 		StacksInjured fakeEvent;
+		fakeEvent.battleID = battle.getBattle()->getBattleID();
 		gameHandler->sendAndApply(&fakeEvent);
 	}
 

+ 2 - 2
server/battles/BattleFlowProcessor.cpp

@@ -181,6 +181,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle,
 	// send empty event to client
 	// temporary(?) workaround to force animations to trigger
 	StacksInjured fakeEvent;
+	fakeEvent.battleID = battle.getBattle()->getBattleID();
 	gameHandler->sendAndApply(&fakeEvent);
 }
 
@@ -676,8 +677,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
 		}
 		if(st->hasBonusOfType(BonusType::MANA_DRAIN) && !st->drainedMana)
 		{
-			const PlayerColor opponent = battle.otherPlayer(battle.battleGetOwner(st));
-			const CGHeroInstance * opponentHero = battle.battleGetFightingHero(opponent);
+			const CGHeroInstance * opponentHero = battle.battleGetFightingHero(battle.otherSide(st->unitSide()));
 			if(opponentHero)
 			{
 				ui32 manaDrained = st->valOfBonuses(BonusType::MANA_DRAIN);

+ 4 - 4
server/battles/BattleResultProcessor.cpp

@@ -498,10 +498,10 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 
 	BattleResultAccepted raccepted;
 	raccepted.battleID = battle.getBattle()->getBattleID();
-	raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(0));
-	raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(1));
-	raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(0));
-	raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(1));
+	raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::ATTACKER));
+	raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::DEFENDER));
+	raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::ATTACKER));
+	raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::DEFENDER));
 	raccepted.heroResult[0].exp = battleResult->exp[0];
 	raccepted.heroResult[1].exp = battleResult->exp[1];
 	raccepted.winnerSide = finishingBattle->winnerSide;