Browse Source

Last part of Seer Hut & Quest Guard code:
1.Required artifacts & army are now taken on completion.
2.Hoover tooltip.
3.Fixed bugs.

DjWarmonger 15 years ago
parent
commit
53365af90e
9 changed files with 219 additions and 78 deletions
  1. 1 1
      client/Client.h
  2. 0 9
      global.h
  3. 171 57
      hch/CObjectHandler.cpp
  4. 1 4
      hch/CObjectHandler.h
  5. 1 1
      lib/IGameCallback.h
  6. 1 1
      lib/NetPacksLib.cpp
  7. 0 1
      lib/map.cpp
  8. 43 3
      server/CGameHandler.cpp
  9. 1 1
      server/CGameHandler.h

+ 1 - 1
client/Client.h

@@ -84,7 +84,7 @@ public:
 	void showThievesGuildWindow(int requestingObjId){};
 	void giveResource(int player, int which, int val){};
 	void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures) {};
-	void takeCreatures (int objid, CCreatureSet creatures){};
+	void takeCreatures (int objid, TSlots creatures){};
 	void showCompInfo(ShowInInfobox * comp){};
 	void heroVisitCastle(int obj, int heroID){};
 	void stopHeroVisitCastle(int obj, int heroID){};

+ 0 - 9
global.h

@@ -150,15 +150,6 @@ namespace vstd
 	{
 		return c.find(i)!=c.end();
 	}
-#if 0
-	template <typename V, typename Item, typename Item2>
-	bool contains2(const std::map<Item,V> & c, const Item2 &i) //returns true if map c leads to item i
-	{
-		for (std::map<Item,V>::const_iterator it = c.begin(); it!= c.end(); ++it)
-			if (it->second == i) return true;
-		return false;
-	}
-#endif
 	template <typename Container1, typename Container2>
 	typename Container2::iterator findFirstNot(Container1 &c1, Container2 &c2)//returns first element of c2 not present in c1
 	{

+ 171 - 57
hch/CObjectHandler.cpp

@@ -3176,9 +3176,9 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const
 			return true;
 			break;
 		case MISSION_KILL_CREATURE:
-			if (h->cb->gameState()->map->monsters[m13489val])
-				return false;
-			return true;
+			if (h->cb->gameState()->map->monsters[m13489val]->pos == int3(-1,-1,-1))
+				return true;
+			return false;
 			break;
 		case MISSION_ART:
 			for (int i = 0; i < m5arts.size(); ++i)
@@ -3245,9 +3245,80 @@ void CGSeerHut::initObj()
 
 const std::string & CGSeerHut::getHoverText() const
 {
-	hoverName = VLC->generaltexth->allTexts[347];
-	boost::algorithm::replace_first(hoverName,"%s", seerName);
-	if (progress){}//what does it seek for?
+	switch (ID)
+	{
+			case 83:
+				hoverName = VLC->generaltexth->allTexts[347];
+				boost::algorithm::replace_first(hoverName,"%s", seerName);
+				break;
+			case 215:
+				hoverName = VLC->generaltexth->names[ID];
+				break;
+			default:
+				tlog5 << "unrecognized quest object\n";
+	}
+	if (progress & missionType) //rollover when the quest is active
+	{
+		MetaString ms;
+		ms << "\n\n" << VLC->generaltexth->quests[missionType-1][3][textOption];
+		std::string str;
+		switch (missionType)
+		{
+			case MISSION_LEVEL:
+				ms.addReplacement (m13489val);
+				break;
+			case MISSION_PRIMARY_STAT:
+			{
+				MetaString loot;
+				for (int i = 0; i < 4; ++i)
+				{
+					if (m2stats[i])
+					{
+						loot << "%d %s";
+						loot.addReplacement (m2stats[i]);
+						loot.addReplacement (VLC->generaltexth->primarySkillNames[i]);
+					}		
+				}
+				ms.addReplacement(loot.buildList());
+			}
+				break;
+			case MISSION_KILL_HERO:
+				ms.addReplacement(cb->gameState()->map->heroesToBeat[m13489val]->name);
+				break;
+			case MISSION_HERO:
+				ms.addReplacement(VLC->heroh->heroes[m13489val]->name);
+				break;
+			case MISSION_KILL_CREATURE:
+			{
+				const TStack* stack = cb->gameState()->map->monsters[m13489val]->army.getStack(0);
+				if (stack->first == 1)
+					ms.addReplacement (MetaString::CRE_SING_NAMES, stack->first);
+				else
+					ms.addReplacement (MetaString::CRE_PL_NAMES, stack->first);
+			}
+				break;
+			case MISSION_ART:
+			{
+				MetaString loot;
+				for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
+				{
+					loot << "%s";
+					loot.addReplacement (MetaString::ART_NAMES, *it);
+				}
+				ms.addReplacement(loot.buildList());
+			}
+				break;
+			case MISSION_ARMY:
+			case MISSION_RESOURCES:
+			case MISSION_PLAYER:
+				ms.addReplacement (VLC->generaltexth->colors[m13489val]);
+				break;
+			default:
+				break;
+		}
+		ms.toString(str);
+		hoverName += str; 
+	}
 	return hoverName;
 }
 
@@ -3375,57 +3446,104 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
 					break;
 			}
 			cb->setObjProperty (id,10,1);
+			cb->showInfoDialog(&iw);
 		}
-		else
+		else if (!checkQuest(h))
 		{
-			if (!checkQuest(h))
-				iw.text << nextVisitText;
-			else
+			iw.text << nextVisitText;
+			cb->showInfoDialog(&iw);
+		}
+		if (checkQuest(h)) // propose completion, also on first visit
+		{
+			BlockingDialog bd (true, false);
+			bd.player = h->getOwner();
+			bd.soundID = soundBase::QUEST;
+			bd.text << completedText;
+			switch (missionType)
 			{
-				BlockingDialog bd (true, false);
-				bd.player = h->getOwner();
-				bd.soundID = soundBase::QUEST;
-				bd.text << completedText;
-				switch (missionType)
-				{
-					case CQuest::MISSION_LEVEL:
-						bd.text.addReplacement(m13489val);
-						break;
-					case CQuest::MISSION_PRIMARY_STAT:
-						if (vstd::contains (completedText,'%')) //there's one case when there's nothing to replace
+				case CQuest::MISSION_LEVEL:
+					bd.text.addReplacement(m13489val);
+					break;
+				case CQuest::MISSION_PRIMARY_STAT:
+					if (vstd::contains (completedText,'%')) //there's one case when there's nothing to replace
+					{
+						MetaString loot;
+						for (int i = 0; i < 4; ++i)
 						{
-							MetaString loot;
-							for (int i = 0; i < 4; ++i)
+							if (m2stats[i])
 							{
-								if (m2stats[i])
-								{
-									loot << "%d %s";
-									loot.addReplacement (m2stats[i]);
-									loot.addReplacement (VLC->generaltexth->primarySkillNames[i]);
-								}
+								loot << "%d %s";
+								loot.addReplacement (m2stats[i]);
+								loot.addReplacement (VLC->generaltexth->primarySkillNames[i]);
 							}
-							bd.text.addReplacement (loot.buildList());
 						}
-						break;
-					case CQuest::MISSION_ART:
-						for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
-							bd.components.push_back (Component (Component::ARTIFACT, *it, 0, 0));
-						break;
-					case CQuest::MISSION_ARMY:
-						for (TSlots::const_iterator it = m6creatures.begin(); it != m6creatures.end(); ++it)
-							bd.components.push_back (Component (Component::CREATURE, it->second.first, it->second.second, 0));
-						break;
-					case CQuest::MISSION_RESOURCES:
-						for (int i = 0; i < 7; ++i)
+						bd.text.addReplacement (loot.buildList());
+					}
+					break;
+				case CQuest::MISSION_ART:
+				{
+					MetaString loot;
+					for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
+					{
+						bd.components.push_back (Component (Component::ARTIFACT, *it, 0, 0));
+						loot << "%s";
+						loot.addReplacement (MetaString::ART_NAMES, *it);
+					}
+					bd.text.addReplacement (loot.buildList());
+				}
+					break;
+				case CQuest::MISSION_ARMY:
+				{
+					MetaString loot;
+					for (TSlots::const_iterator it = m6creatures.begin(); it != m6creatures.end(); ++it)
+					{
+						bd.components.push_back (Component (Component::CREATURE, it->second.first, it->second.second, 0));
+						loot << "%s";
+						if (it->second.second == 1)
+							loot.addReplacement (MetaString::CRE_SING_NAMES, it->second.first);
+						else
+							loot.addReplacement (MetaString::CRE_PL_NAMES, it->second.first);
+					}
+					bd.text.addReplacement	(loot.buildList());
+				}
+					break;
+				case CQuest::MISSION_RESOURCES:
+				{
+					MetaString loot;
+					for (int i = 0; i < 7; ++i)
+					{
+						if (m7resources[i])
 						{
-							if (m7resources[i])
-								bd.components.push_back (Component (Component::RESOURCE, i, m7resources[i], 0));
+							bd.components.push_back (Component (Component::RESOURCE, i, m7resources[i], 0));
+							loot << "%d %s";
+							loot.addReplacement (iw.components.back().val);
+							loot.addReplacement (MetaString::RES_NAMES, iw.components.back().subtype);
 						}
-						break;
+					}
+					bd.text.addReplacement (loot.buildList());
+				}
+					break;
+				case MISSION_KILL_HERO:
+					bd.text.addReplacement(cb->gameState()->map->heroesToBeat[m13489val]->name);
+					break;
+				case MISSION_HERO:
+					bd.text.addReplacement(VLC->heroh->heroes[m13489val]->name);
+					break;
+				case MISSION_KILL_CREATURE:
+				{
+					const TStack* stack = cb->gameState()->map->monsters[m13489val]->army.getStack(0);
+					if (stack->first == 1)
+						bd.text.addReplacement (MetaString::CRE_SING_NAMES, stack->first);
+					else
+						bd.text.addReplacement (MetaString::CRE_PL_NAMES, stack->first);
+					if (std::count(firstVisitText.begin(), firstVisitText.end(), '%') == 2) //say where is placed monster
+					{
+						bd.text.addReplacement (VLC->generaltexth->arraytxt[147+checkDirection()]);
+					}
 				}
-				cb->showBlockingDialog (&bd, boost::bind (&CGSeerHut::finishQuest, this, h, _1));
-				return;
 			}
+			cb->showBlockingDialog (&bd, boost::bind (&CGSeerHut::finishQuest, this, h, _1));
+			return;
 		}
 	}
 	else
@@ -3433,8 +3551,8 @@ void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
 		iw.text << VLC->generaltexth->seerEmpty[textOption];
 		if (ID == 83)
 			iw.text.addReplacement(seerName);
+		cb->showInfoDialog(&iw);
 	}
-	cb->showInfoDialog(&iw);
 }
 int CGSeerHut::checkDirection() const
 {
@@ -3475,10 +3593,12 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
 		{
 			case CQuest::MISSION_ART:
 				for (std::vector<ui16>::const_iterator it = m5arts.begin(); it != m5arts.end(); ++it)
-				{}
+				{
+					cb->removeArtifact(*it, h->id);
+				}
 				break;
 			case CQuest::MISSION_ARMY:
-					//cb->takeCreatures (h->id, m7creatures);
+					cb->takeCreatures (h->id, m6creatures);
 				break;
 			case CQuest::MISSION_RESOURCES:
 				for (int i = 0; i < 7; ++i)
@@ -3489,7 +3609,8 @@ void CGSeerHut::finishQuest (const CGHeroInstance * h, ui32 accept) const
 			default:
 				break;
 		}
-		completeQuest(h);
+		cb->setObjProperty (id,11,0); //no more mission avaliable	
+		completeQuest(h); //make sure to remove QuestQuard at the very end	
 	}
 }
 void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
@@ -3555,7 +3676,6 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 			break;
 	}
 	cb->showInfoDialog(&iw);
-	cb->setObjProperty (id,11,0); //no more mission avaliable
 }
 
 void CGQuestGuard::initObj()
@@ -3572,12 +3692,6 @@ void CGQuestGuard::initObj()
 	else
 		firstVisitText = VLC->generaltexth->seerEmpty[textOption];
 }
-const std::string & CGQuestGuard::getHoverText() const
-{
-	hoverName = VLC->generaltexth->names[ID];
-	if (progress){}//what does it seek for?
-	return hoverName;
-}
 void CGQuestGuard::completeQuest(const CGHeroInstance *h) const
 {
 	cb->removeObject(id);

+ 1 - 4
hch/CObjectHandler.h

@@ -248,7 +248,6 @@ public:
 	std::vector<si32> primSkills; //0-attack, 1-defence, 2-spell power, 3-knowledge
 	std::vector<std::pair<ui8,ui8> > secSkills; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert); if hero has ability (-1, -1) it meansthat it should have default secondary abilities
 	si32 movement; //remaining movement points
-	si32 identifier; //from the map file
 	ui8 sex;
 	ui8 inTownGarrison; // if hero is in town garrison 
 	CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
@@ -276,7 +275,7 @@ public:
 	{
 		h & static_cast<CArmedInstance&>(*this);
 		h & exp & level & name & biography & portrait & mana & primSkills & secSkills & movement
-			& identifier & sex & inTownGarrison & artifacts & artifWorn & spells & patrol & bonuses
+			& sex & inTownGarrison & artifacts & artifWorn & spells & patrol & bonuses
 			& moveDir;
 
 		ui8 standardType = (VLC->heroh->heroes[subID] == type);
@@ -636,8 +635,6 @@ class DLL_EXPORT CGQuestGuard : public CGSeerHut
 {
 public:
 	void initObj();
-	const std::string & getHoverText() const;
-	//void onHeroVisit( const CGHeroInstance * h ) const;
 	void completeQuest (const CGHeroInstance * h) const;
  
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 1 - 1
lib/IGameCallback.h

@@ -80,7 +80,7 @@ public:
 	virtual void showThievesGuildWindow(int requestingObjId) =0;
 	virtual void giveResource(int player, int which, int val)=0;
 	virtual void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures) =0;
-	virtual void takeCreatures (int objid, CCreatureSet creatures) =0;
+	virtual void takeCreatures (int objid, TSlots creatures) =0;
 	virtual void showCompInfo(ShowInInfobox * comp)=0;
 	virtual void heroVisitCastle(int obj, int heroID)=0;
 	virtual void stopHeroVisitCastle(int obj, int heroID)=0;

+ 1 - 1
lib/NetPacksLib.cpp

@@ -252,7 +252,7 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
 	else if (obj->ID==CREI_TYPE) //only fixed monsters can be a part of quest
 	{
 		CGCreature *cre = static_cast<CGCreature*>(obj);
-		gs->map->monsters[cre->identifier] = NULL;	
+		gs->map->monsters[cre->identifier]->pos = int3 (-1,-1,-1);	//use nonexistent monster for quest :>
 	}
 	gs->map->objects[id] = NULL;	
 

+ 0 - 1
lib/map.cpp

@@ -922,7 +922,6 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int
 			break;
 		}
 	}
-	nhi->identifier = identifier; //probably redundant
 	heroesToBeat[identifier] = nhi;
 	if(readChar(bufor,i))//true if hero has nonstandard name
 		nhi->name = readString(bufor,i);

+ 43 - 3
server/CGameHandler.cpp

@@ -1734,8 +1734,25 @@ void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, CCreature
 		return;
 	}
 }
-void CGameHandler::takeCreatures (int objid, CCreatureSet creatures)
-{}
+void CGameHandler::takeCreatures (int objid, TSlots creatures) //probably we could use ArmedInstance as well
+{
+	if (creatures.size() <= 0)
+		return;
+	const CArmedInstance* obj = static_cast<const CArmedInstance*>(getObj(objid));
+	CCreatureSet newArmy = obj->army;
+	while (creatures.size() > 0)
+	{
+		int slot = newArmy.getSlotFor (creatures.begin()->second.first);
+		if (slot < 0)
+			break;
+		newArmy.slots[slot].first = creatures.begin()->second.first;
+		newArmy.slots[slot].second -= creatures.begin()->second.second;
+		creatures.erase (creatures.begin());
+	}
+	SetGarrisons sg;
+	sg.garrs[objid] = newArmy;
+	sendAndApply(&sg);
+}
 void CGameHandler::showCompInfo(ShowInInfobox * comp)
 {
 	sendToAllClients(comp);
@@ -1816,7 +1833,30 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
 	sendAndApply(&sha);
 }
 void CGameHandler::removeArtifact(int artid, int hid)
-{}
+{
+	const CGHeroInstance* h = getHero(hid);
+
+	SetHeroArtifacts sha;
+	sha.hid = hid;
+	sha.artifacts = h->artifacts;
+	sha.artifWorn = h->artifWorn;
+	
+	std::vector<ui32>::iterator it;
+	if 	((it = std::find(sha.artifacts.begin(), sha.artifacts.end(), artid)) != sha.artifacts.end()) //it is in backpack
+		sha.artifacts.erase(it);
+	else //worn
+	{
+		for (std::map<ui16,ui32>::iterator itr = sha.artifWorn.begin(); itr != sha.artifWorn.end(); ++itr)
+		{
+			if (itr->second == artid)
+			{
+				sha.artifWorn.erase(itr);
+				break;
+			}
+		}
+	}
+	sendAndApply(&sha);
+}
 
 void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town) //use hero=NULL for no hero
 {

+ 1 - 1
server/CGameHandler.h

@@ -129,7 +129,7 @@ public:
 	void showThievesGuildWindow(int requestingObjId); //TODO: make something more general?
 	void giveResource(int player, int which, int val);
 	void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures);
-	void takeCreatures (int objid, CCreatureSet creatures);
+	void takeCreatures (int objid, TSlots creatures);
 	void showCompInfo(ShowInInfobox * comp);
 	void heroVisitCastle(int obj, int heroID);
 	void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);