Pārlūkot izejas kodu

Heroes will be properly marked as visited on visiting

Ivan Savenko 11 gadi atpakaļ
vecāks
revīzija
dab9fd7148
3 mainītis faili ar 64 papildinājumiem un 24 dzēšanām
  1. 12 13
      lib/CObjectWithReward.cpp
  2. 32 8
      lib/NetPacks.h
  3. 20 3
      lib/NetPacksLib.cpp

+ 12 - 13
lib/CObjectWithReward.cpp

@@ -39,18 +39,18 @@ bool CRewardLimiter::heroAllowed(const CGHeroInstance * hero) const
 	if (!IObjectInterface::cb->getPlayer(hero->tempOwner)->resources.canAfford(resources))
 		return false;
 
-	if (hero->level < minLevel)
+	if (minLevel > hero->level)
 		return false;
 
 	for (size_t i=0; i<primary.size(); i++)
 	{
-		if (primary[i] < hero->getPrimSkillLevel(PrimarySkill::PrimarySkill(i)))
+		if (primary[i] > hero->getPrimSkillLevel(PrimarySkill::PrimarySkill(i)))
 			return false;
 	}
 
 	for (auto & skill : secondary)
 	{
-		if (skill.second < hero->getSecSkillLevel(skill.first))
+		if (skill.second > hero->getSecSkillLevel(skill.first))
 			return false;
 	}
 
@@ -98,6 +98,8 @@ void CObjectWithReward::onHeroVisit(const CGHeroInstance *h) const
 			}
 			case 1: // one reward. Just give it with message
 			{
+				//FIXME: merge into grantReward call?
+				cb->setObjProperty(id, ObjProperty::REWARD_SELECT, rewards[0]);
 				grantReward(info[rewards[0]], h);
 				InfoWindow iw;
 				iw.player = h->tempOwner;
@@ -109,7 +111,7 @@ void CObjectWithReward::onHeroVisit(const CGHeroInstance *h) const
 				break;
 			}
 			default: // multiple rewards. Let player select
-			{
+			{//TODO: implement various modes
 				BlockingDialog sd(false,true);
 				sd.player = h->tempOwner;
 				sd.soundID = soundID;
@@ -141,6 +143,7 @@ void CObjectWithReward::blockingDialogAnswered(const CGHeroInstance *hero, ui32
 	if (answer > 0 && answer-1 < info.size())
 	{
 		auto list = getAvailableRewards(hero);
+		cb->setObjProperty(id, ObjProperty::REWARD_SELECT, list[answer - 1]);
 		grantReward(info[list[answer - 1]], hero);
 	}
 	else
@@ -162,6 +165,10 @@ void CObjectWithReward::grantReward(const CVisitInfo & info, const CGHeroInstanc
 	assert(info.reward.creatures.size() <= GameConstants::ARMY_SIZE);
 	assert(!cb->isVisitCoveredByAnotherQuery(this, hero));
 
+	//FIXME: move somewhere?
+	ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD, id, hero->id);
+	cb->sendAndApply(&cov);
+
 	cb->giveResources(hero->tempOwner, info.reward.resources);
 
 	for (auto & entry : info.reward.secondary)
@@ -349,16 +356,8 @@ void CObjectWithReward::setPropertyDer(ui8 what, ui32 val)
 			break;
 		case ObjProperty::REWARD_SELECT:
 			selectedReward = val;
+			info[val].numOfGrants++;
 			break;
-		case ObjProperty::REWARD_ADD_VISITOR:
-		{
-			//FIXME: Not sure if modifying another object here is a good idea
-			CGHeroInstance * hero = cb->gameState()->getHero(ObjectInstanceID(val));
-			assert(hero && hero->tempOwner.isValidPlayer());
-			hero->visitedObjects.insert(ObjectInstanceID(ID));
-			cb->gameState()->getPlayer(hero->tempOwner)->visitedObjects.insert(ObjectInstanceID(ID));
-			break;
-		}
 	}
 }
 

+ 32 - 8
lib/NetPacks.h

@@ -1025,11 +1025,8 @@ namespace ObjProperty
 		BANK_DAYCOUNTER, BANK_CLEAR_ARTIFACTS, BANK_ADD_ARTIFACT, BANK_MULTIPLIER, BANK_CONFIG_PRESET, 
 		BANK_CLEAR_CONFIG, BANK_INIT_ARMY, BANK_RESET,
 
-		//magic spring
-		LEFT_VISITED, RIGHT_VISITED, LEFTRIGHT_CLEAR,
-
-		//object with reward
-		REWARD_RESET, REWARD_ADD_VISITOR, REWARD_SELECT
+		//object with reward
+		REWARD_RESET, REWARD_SELECT
 	};
 }
 
@@ -1039,7 +1036,7 @@ struct SetObjectProperty : public CPackForClient//1001
 	void applyCl(CClient *cl);
 
 	ObjectInstanceID id;
-	ui8 what; //1 - owner; 2 - blockvis; 3 - first stack count; 4 - visitors; 5 - visited; 6 - ID (if 34 then also def is replaced)
+	ui8 what; // see ObjProperty enum
 	ui32 val;
 	SetObjectProperty(){type = 1001;};
 	SetObjectProperty(ObjectInstanceID ID, ui8 What, ui32 Val):id(ID),what(What),val(Val){type = 1001;};
@@ -1056,14 +1053,41 @@ struct SetHoverName : public CPackForClient//1002
 
 	ObjectInstanceID id;
 	MetaString name;
-	SetHoverName(){type = 1002;};
-	SetHoverName(ObjectInstanceID ID, MetaString& Name):id(ID),name(Name){type = 1002;};
+	SetHoverName(){type = 1002;}
+	SetHoverName(ObjectInstanceID ID, MetaString& Name):id(ID),name(Name){type = 1002;}
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & id & name;
 	}
 };
+
+struct ChangeObjectVisitors : public CPackForClient // 1003
+{
+	enum VisitMode
+	{
+		VISITOR_ADD,    // mark hero as one that have visited this object
+		VISITOR_REMOVE, // unmark visitor, reversed to ADD
+		VISITOR_CLEAR   // clear all visitors from this object (object reset)
+	};
+	ui32 mode; // uses VisitMode enum
+	ObjectInstanceID object;
+	ObjectInstanceID hero; // note: hero owner will be also marked as "visited" this object
+
+	DLL_LINKAGE void applyGs(CGameState *gs);
+
+	ChangeObjectVisitors(ui32 mode, ObjectInstanceID object, ObjectInstanceID heroID = ObjectInstanceID(-1)):
+		mode(mode),
+		object(object),
+		hero(heroID)
+	{ type = 1003; }
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & object & hero & mode;
+	}
+};
+
 struct HeroLevelUp : public Query//2000
 {
 	void applyCl(CClient *cl);

+ 20 - 3
lib/NetPacksLib.cpp

@@ -251,9 +251,9 @@ DLL_LINKAGE void GiveBonus::applyGs( CGameState *gs )
 	{
 		bdescr.toString(descr);
 	}
-	// Some of(?) versions of H3 use %s here instead of %d. Try to replace both of them
-	boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val)));
-	boost::replace_first(descr,"%s",boost::lexical_cast<std::string>(std::abs(bonus.val)));
+	// Some of(?) versions of H3 use %s here instead of %d. Try to replace both of them
+	boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val)));
+	boost::replace_first(descr,"%s",boost::lexical_cast<std::string>(std::abs(bonus.val)));
 }
 
 DLL_LINKAGE void ChangeObjPos::applyGs( CGameState *gs )
@@ -269,6 +269,23 @@ DLL_LINKAGE void ChangeObjPos::applyGs( CGameState *gs )
 	gs->map->addBlockVisTiles(obj);
 }
 
+DLL_LINKAGE void ChangeObjectVisitors::applyGs( CGameState *gs )
+{
+	switch (mode) {
+		case VISITOR_ADD:
+			gs->getHero(hero)->visitedObjects.insert(object);
+			gs->getPlayer(gs->getHero(hero)->tempOwner)->visitedObjects.insert(object);
+			break;
+		case VISITOR_CLEAR:
+			for (CGHeroInstance * hero : gs->map->allHeroes)
+				hero->visitedObjects.erase(object); // remove visit info from all heroes, including those that are not present on map
+			break;
+		case VISITOR_REMOVE:
+			gs->getHero(hero)->visitedObjects.erase(object);
+			break;
+	}
+}
+
 DLL_LINKAGE void PlayerEndsGame::applyGs( CGameState *gs )
 {
 	PlayerState *p = gs->getPlayer(player);