Pārlūkot izejas kodu

fixed several bugs reported on forum:
- necromancy issues
- fix for lookout tower
- Sir Mullich is unavailable
- first hero is awakened on next turn
- give 500 XP on defeating hero

Ivan Savenko 12 gadi atpakaļ
vecāks
revīzija
491bd557ef

+ 17 - 4
client/CPlayerInterface.cpp

@@ -2180,13 +2180,26 @@ void CPlayerInterface::acceptTurn()
 	if(howManyPeople > 1)
 		adventureInt->startTurn();
 
-	//select first hero if available.
-	//TODO: check if hero is slept
 	adventureInt->heroList.update();
 	adventureInt->townList.update();
 
-	if(wanderingHeroes.size())
-		adventureInt->select(wanderingHeroes.front());
+	const CGHeroInstance * heroToSelect = nullptr;
+
+	// find first non-sleeping hero
+	for (auto hero : wanderingHeroes)
+	{
+		if (boost::range::find(sleepingHeroes, hero) == sleepingHeroes.end())
+		{
+			heroToSelect = hero;
+			break;
+		}
+	}
+
+	//select first hero if available.
+	if(heroToSelect != nullptr)
+	{
+		adventureInt->select(heroToSelect);
+	}
 	else
 		adventureInt->select(towns.front());
 

+ 0 - 1
client/NetPacksClient.cpp

@@ -165,7 +165,6 @@ void SetMovePoints::applyCl( CClient *cl )
 
 void FoWChange::applyCl( CClient *cl )
 {
-
 	for(auto &i : cl->playerint)
 		if(cl->getPlayerRelations(i.first, player) != PlayerRelations::ENEMIES)
 		{

+ 1 - 1
config/heroes/special.json

@@ -5,7 +5,7 @@
 		"index": 144,
 		"class" : "knight",
 		"female": false,
-		"special" : true,
+		"special" : false, // available in single scenario, replacement for no longer available Lord Haart
 		"skills":
 		[
 			{ "skill" : "leadership", "level": "advanced" }

+ 6 - 8
lib/CObjectHandler.cpp

@@ -1410,8 +1410,8 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
 {
 	const ui8 necromancyLevel = getSecSkillLevel(SecondarySkill::NECROMANCY);
 
-	// Hero knows necromancy.
-	if (necromancyLevel > 0)
+	// Hero knows necromancy or has Necromancer Cloak
+	if (necromancyLevel > 0 || hasBonusOfType(Bonus::IMPROVED_NECROMANCY))
 	{
 		double necromancySkill = valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::NECROMANCY)/100.0;
 		vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
@@ -1429,11 +1429,9 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
 		{
 			// Get lost enemy hit points convertible to units.
 			CCreature * c = VLC->creh->creatures[casualtie.first];
-			if (c->isLiving())
-			{
-				const ui32 raisedHP = c->valOfBonuses(Bonus::STACK_HEALTH) * casualtie.second * necromancySkill;
-				raisedUnits += std::min<ui32>(raisedHP / raisedUnitHP, casualtie.second * necromancySkill); //limit to % of HP and % of original stack count
-			}
+
+			const ui32 raisedHP = c->valOfBonuses(Bonus::STACK_HEALTH) * casualtie.second * necromancySkill;
+			raisedUnits += std::min<ui32>(raisedHP / raisedUnitHP, casualtie.second * necromancySkill); //limit to % of HP and % of original stack count
 		}
 
 		// Make room for new units.
@@ -1966,7 +1964,7 @@ int CGTownInstance::getSightRadious() const //returns sight distance
 	{
 		if (hasBuilt(BuildingID::GRAIL)) //skyship
 			return -1; //entire map
-		else if (hasBuilt(BuildingID::LOOKOUT_TOWER)) //lookout tower
+		if (hasBuilt(BuildingID::LOOKOUT_TOWER)) //lookout tower
 			return 20;
 	}
 	return 5;

+ 2 - 2
lib/CObjectHandler.h

@@ -633,8 +633,8 @@ public:
 	//////////////////////////////////////////////////////////////////////////
 
 	ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
-	int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
-	int getSightRadious() const; //returns sight distance
+	int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
+	int getSightRadious() const override; //returns sight distance
 	int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
 	void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
 	int getMarketEfficiency() const override; //=market count

+ 23 - 11
server/CGameHandler.cpp

@@ -414,6 +414,15 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 
 	//Fill BattleResult structure with exp info
 	giveExp(*battleResult.data);
+
+	if (battleResult.get()->result == BattleResult::NORMAL) // give 500 exp for defeating hero, unless he escaped
+	{
+		if (hero1)
+			battleResult.data->exp[1] += 500;
+		if (hero2)
+			battleResult.data->exp[0] += 500;
+	}
+
 	if (hero1)
 		battleResult.data->exp[0] = hero1->calculateXp(battleResult.data->exp[0]);//scholar skill
 	if (hero2)
@@ -2440,7 +2449,7 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
 			ssi.creatures[level].second.push_back(crea->idNumber);
 			sendAndApply(&ssi);
 		}
-		else if ( t->subID == ETownType::DUNGEON && buildingID == BuildingID::PORTAL_OF_SUMMON )
+		if ( t->subID == ETownType::DUNGEON && buildingID == BuildingID::PORTAL_OF_SUMMON )
 		{
 			setPortalDwelling(t);
 		}
@@ -2464,8 +2473,6 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
 		return true;
 	};
 
-
-
 	//Init the vectors
 	for(auto & build : t->town->buildings)
 	{
@@ -2499,13 +2506,6 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
 		}
 	}
 
-	//reveal ground for lookout tower
-	FoWChange fw;
-	fw.player = t->tempOwner;
-	fw.mode = 1;
-	t->getSightTiles(fw.tiles);
-	sendAndApply(&fw);
-
 	//Other post-built events
 	for(auto builtID : ns.bid)
 		processBuiltStructure(builtID);
@@ -2522,6 +2522,13 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
 	//We know what has been built, appluy changes. Do this as final step to properly update town window
 	sendAndApply(&ns);
 
+	// now when everything is built - reveal tiles for lookout tower
+	FoWChange fw;
+	fw.player = t->tempOwner;
+	fw.mode = 1;
+	t->getSightTiles(fw.tiles);
+	sendAndApply(&fw);
+
 	if(t->visitingHero)
 		vistiCastleObjects (t, t->visitingHero);
 	if(t->garrisonHero)
@@ -3665,7 +3672,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 
 			bsa.creID = CreatureID(summoner->getBonusLocalFirst(Selector::type(Bonus::DAEMON_SUMMONING))->subtype); //in case summoner can summon more than one type of monsters... scream!
 			ui64 risedHp = summoner->count * summoner->valOfBonuses(Bonus::DAEMON_SUMMONING, bsa.creID.toEnum());
-			bsa.amount = std::min ((ui32)(risedHp / VLC->creh->creatures[bsa.creID]->MaxHealth()), destStack->baseAmount);
+			ui64 targetHealth = destStack->getCreature()->MaxHealth() * destStack->baseAmount;
+
+			ui64 canRiseHp = std::min(targetHealth, risedHp);
+			ui32 canRiseAmount = canRiseHp / VLC->creh->creatures[bsa.creID]->MaxHealth();
+
+			bsa.amount = std::min(canRiseAmount, destStack->baseAmount);
 
 			bsa.pos = gs->curB->getAvaliableHex(bsa.creID, bsa.attacker, destStack->position);
 			bsa.summoned = false;