瀏覽代碼

* magic well support
* improvements in the recruitment window
* improvements for pregame
[cf http://vcmi.antypika.aplus.pl/forum/viewtopic.php?t=97 issues 12-15 and 21 - 22]
* minor changes

Michał W. Urbańczyk 16 年之前
父節點
當前提交
05b3e3215c
共有 16 個文件被更改,包括 200 次插入67 次删除
  1. 8 1
      AdventureMapButton.cpp
  2. 1 0
      AdventureMapButton.h
  3. 5 1
      CGameState.cpp
  4. 12 5
      CPlayerInterface.cpp
  5. 1 0
      CPlayerInterface.h
  6. 73 48
      CPreGame.cpp
  7. 1 0
      ChangeLog
  8. 1 0
      client/Client.h
  9. 43 0
      hch/CObjectHandler.cpp
  10. 13 0
      hch/CObjectHandler.h
  11. 14 1
      lib/HeroBonus.h
  12. 1 0
      lib/IGameCallback.h
  13. 10 7
      map.cpp
  14. 8 4
      map.h
  15. 8 0
      server/CGameHandler.cpp
  16. 1 0
      server/CGameHandler.h

+ 8 - 1
AdventureMapButton.cpp

@@ -40,6 +40,13 @@ AdventureMapButton::AdventureMapButton( const std::string &Name, const std::stri
 	pom[0] = Name;
 	init(Callback, pom, HelpBox, info->playerColoured, info->defName, &info->additionalDefs, info->x, info->y, key);
 }
+
+AdventureMapButton::AdventureMapButton( const std::pair<std::string, std::string> help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key/*=0*/, std::vector<std::string> * add /*= NULL*/, bool playerColoredButton /*= false */ )
+{
+	std::map<int,std::string> pom;
+	pom[0] = help.first;
+	init(Callback, pom, help.second, playerColoredButton, defName, add, x, y, key);
+}
 void AdventureMapButton::clickLeft (tribool down)
 {
 	if(blocked)
@@ -79,7 +86,7 @@ void AdventureMapButton::hover (bool on)
 	std::string *name = (vstd::contains(hoverTexts,state)) 
 							? (&hoverTexts[state]) 
 							: (vstd::contains(hoverTexts,0) ? (&hoverTexts[0]) : NULL);
-	if(name) //if there is no name, there is nohing to display also
+	if(name && !blocked) //if there is no name, there is nohing to display also
 	{
 		if (LOCPLINT->curint == static_cast<CMainInterface*>(LOCPLINT->battleInt)) //for battle buttons
 		{

+ 1 - 0
AdventureMapButton.h

@@ -29,6 +29,7 @@ public:
 	AdventureMapButton(); //c-tor
 	AdventureMapButton( const std::map<int,std::string> &, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 	AdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
+	AdventureMapButton( const std::pair<std::string, std::string> help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 	AdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
 	//AdventureMapButton( std::string Name, std::string HelpBox, boost::function<void()> Callback, int x, int y, std::string defName, bool activ=false,  std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 

+ 5 - 1
CGameState.cpp

@@ -434,7 +434,6 @@ CGHeroInstance* CGameState::HeroesPool::pickHeroFor(bool native, int player, con
 	}
 }
 
-
 void CGameState::applyNL(IPack * pack)
 {
 	switch(pack->getType())
@@ -455,6 +454,11 @@ void CGameState::applyNL(IPack * pack)
 			if(n->resetBuilded) //reset amount of structures set in this turn in towns
 				BOOST_FOREACH(CGTownInstance* t, map->towns)
 					t->builded = 0;
+			BOOST_FOREACH(CGHeroInstance *h, map->heroes)
+				h->bonuses.remove_if(HeroBonus::OneDay);
+			if(getDate(1) == 7) //new week
+				BOOST_FOREACH(CGHeroInstance *h, map->heroes)
+					h->bonuses.remove_if(HeroBonus::OneDay);
 			break;
 		}
 	case 102: //set resource amount

+ 12 - 5
CPlayerInterface.cpp

@@ -2372,6 +2372,7 @@ void CPlayerInterface::availableCreaturesChanged( const CGTownInstance *town )
 
 void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const HeroBonus &bonus, bool gain )
 {
+	if(bonus.type == HeroBonus::NONE)	return;
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	redrawHeroWin(hero);
 }
@@ -2989,6 +2990,7 @@ void CRecrutationWindow::Cancel()
 }
 void CRecrutationWindow::sliderMoved(int to)
 {
+	buy->block(!to);
 }
 void CRecrutationWindow::clickLeft(tribool down)
 {
@@ -3045,6 +3047,7 @@ void CRecrutationWindow::activate()
 	max->activate();
 	cancel->activate();
 	slider->activate();
+	LOCPLINT->statusbar = bar;
 }
 void CRecrutationWindow::deactivate()
 {
@@ -3089,6 +3092,7 @@ void CRecrutationWindow::show(SDL_Surface * to)
 		curx += 120;
 	}
 	c++;
+	bar->show();
 }
 CRecrutationWindow::CRecrutationWindow(const std::vector<std::pair<int,int> > &Creatures, const boost::function<void(int,int)> &Recruit) //creatures - pairs<creature_ID,amount>
 :recruit(Recruit)
@@ -3115,6 +3119,10 @@ CRecrutationWindow::CRecrutationWindow(const std::vector<std::pair<int,int> > &C
 	pos.y = screen->h/2 - bitmap->h/2;
 	pos.w = bitmap->w;
 	pos.h = bitmap->h;
+	bar = new CStatusBar(pos.x+8, pos.y+370, "APHLFTRT.bmp", 471);
+	max = new AdventureMapButton(CGI->generaltexth->zelp[553],boost::bind(&CRecrutationWindow::Max,this),pos.x+134,pos.y+313,"IRCBTNS.DEF",SDLK_m);
+	buy = new AdventureMapButton(CGI->generaltexth->zelp[554],boost::bind(&CRecrutationWindow::Buy,this),pos.x+212,pos.y+313,"IBY6432.DEF",SDLK_RETURN);
+	cancel = new AdventureMapButton(CGI->generaltexth->zelp[555],boost::bind(&CRecrutationWindow::Cancel,this),pos.x+290,pos.y+313,"ICN6432.DEF",SDLK_ESCAPE);
 	slider = new CSlider(pos.x+176,pos.y+279,135,boost::bind(&CRecrutationWindow::sliderMoved,this, _1),1,std::min(amounts[0],creatures[0].amount),0,true);
 	std::string pom;
 	printAtMiddle(CGI->generaltexth->allTexts[346],113,231,GEOR13,zwykly,bitmap); //cost per troop t
@@ -3144,14 +3152,12 @@ CRecrutationWindow::CRecrutationWindow(const std::vector<std::pair<int,int> > &C
 		curx += 120;
 	}
 
-	max = new AdventureMapButton("","",boost::bind(&CRecrutationWindow::Max,this),pos.x+134,pos.y+313,"IRCBTNS.DEF",SDLK_m);
-	buy = new AdventureMapButton("","",boost::bind(&CRecrutationWindow::Buy,this),pos.x+212,pos.y+313,"IBY6432.DEF",SDLK_RETURN);
-	cancel = new AdventureMapButton("","",boost::bind(&CRecrutationWindow::Cancel,this),pos.x+290,pos.y+313,"ICN6432.DEF",SDLK_ESCAPE);
-	if(!creatures[0].amount)
+	if(!creatures[0].amount ||  !amounts[0])
 	{
 		max->block(true);
-		buy->block(true);
+		slider->block(true);
 	}
+	//buy->block(true); //not needed, will be blocked by initing slider on 0
 }
 CRecrutationWindow::~CRecrutationWindow()
 {
@@ -3164,6 +3170,7 @@ CRecrutationWindow::~CRecrutationWindow()
 	delete cancel;
 	SDL_FreeSurface(bitmap);
 	delete slider;
+	delete bar;
 }
 
 CSplitWindow::CSplitWindow(int cid, int max, CGarrisonInt *Owner)

+ 1 - 0
CPlayerInterface.h

@@ -527,6 +527,7 @@ public:
 	CSlider *slider;
 	AdventureMapButton *max, *buy, *cancel;
 	SDL_Surface *bitmap;
+	CStatusBar *bar;
 	int which; //which creature is active
 
 	void close();

+ 73 - 48
CPreGame.cpp

@@ -38,6 +38,48 @@ CPreGame * CPG;
 namespace fs = boost::filesystem;
 namespace s = CSDL_Ext;
 
+int getNextCastle(int current, PlayerInfo * ourInf, bool next=true) //next=flase => previous castle
+{
+	int dir = next ? 1 : -1;
+	if (current==-2) //no castle - no change
+		return current;
+	else if (current==-1) //random => first/last available
+	{
+		int pom = (next) ? (0) : (F_NUMBER-1); // last or first
+		for (;pom>=0 && pom<F_NUMBER;pom+=dir)
+		{
+			if (((int)pow((double)2,pom))&ourInf->allowedFactions)
+			{
+				current=pom;
+				break;
+			}
+			else continue;
+		}
+	}
+	else // next/previous available
+	{
+		for (;;)
+		{
+			current+=dir;
+			if (((int)pow((double)2,(int)current))&ourInf->allowedFactions)
+			{
+				break;
+			}
+			if (current>=F_NUMBER || current<0)
+			{
+				double p1 = log((double)ourInf->allowedFactions)/log(2.0f)+0.000001f;
+				double check = p1-((int)p1);
+				if (check < 0.001)
+					current=(int)p1;
+				else
+					current=-1;
+				break;
+			}
+		}
+	}
+	return current;
+}
+
 HighButton::HighButton( SDL_Rect Pos, CDefHandler* Imgs, bool Sel, int id)
 {
 	type=0;
@@ -441,6 +483,7 @@ int Options::nextAllowedHero(int min, int max, int incl, int dir) //incl 0 - wla
 	}
 	return -1;
 }
+
 void Options::OptionSwitch::press(bool down)
 {
 	HighButton::press(down);
@@ -452,51 +495,22 @@ void Options::OptionSwitch::press(bool down)
 	{
 	case -1: //castle change
 		{
-			int oCas = ourOpt->castle;
-			if (ourOpt->castle==-2) //no castle - no change
-				return;
-			else if (ourOpt->castle==-1) //random => first/last available
+			int nCas = getNextCastle(ourOpt->castle,ourInf,!left);
+
+			if (nCas!=ourOpt->castle) //changed castle
 			{
-				int pom = (left) ? (F_NUMBER-1) : (0); // last or first
-				for (;pom>=0 && pom<F_NUMBER;pom+=dir)
+				ourOpt->castle = nCas;
+				if(ourOpt->hero != -2)
 				{
-					if (((int)pow((double)2,pom))&ourInf->allowedFactions)
-					{
-						ourOpt->castle=pom;
-						break;
-					}
-					else continue;
+					ourOpt->hero=-1;
+					CPG->ourOptions->showIcon(0,serialID,false);
 				}
-			}
-			else // next/previous available
-			{
-				for (;;)
+				if(ourOpt->bonus==bresource)
 				{
-					ourOpt->castle+=dir;
-					if (((int)pow((double)2,(int)ourOpt->castle))&ourInf->allowedFactions)
-					{
-						break;
-					}
-					if (ourOpt->castle>=F_NUMBER || ourOpt->castle<0)
-					{
-						double p1 = log((double)ourInf->allowedFactions)/log(2.0f)+0.000001f;
-						double check = p1-((int)p1);
-						if (check < 0.001)
-							ourOpt->castle=(int)p1;
-						else
-							ourOpt->castle=-1;
-						break;
-					}
+					ourOpt->bonus = brandom;
+					CPG->ourOptions->showIcon(1,serialID,false);
 				}
 			}
-
-			if (oCas!=ourOpt->castle) //changed castle
-			{
-				ourOpt->hero=-1;
-				ourOpt->bonus = brandom;
-				CPG->ourOptions->showIcon(0,serialID,false);
-				CPG->ourOptions->showIcon(1,serialID,false);
-			}
 			break;
 		}
 	case 0: //hero change
@@ -754,18 +768,29 @@ void Options::show()
 		poptions.push_back(new PlayerOptions(playersSoFar,i));
 		poptions[poptions.size()-1]->nr=playersSoFar;
 		poptions[poptions.size()-1]->color=(Ecolor)i;
-		poptions[poptions.size()-1]->Cleft.show();
-		poptions[poptions.size()-1]->Cright.show();
-		poptions[poptions.size()-1]->Hleft.show();
-		poptions[poptions.size()-1]->Hright.show();
+
+		if(CPG->ret.playerInfos[playersSoFar].hero != -2)
+		{
+			poptions[poptions.size()-1]->Hleft.show();
+			poptions[poptions.size()-1]->Hright.show();
+			CPG->btns.push_back(&poptions[poptions.size()-1]->Hleft);
+			CPG->btns.push_back(&poptions[poptions.size()-1]->Hright);
+		}
+
+		if(getNextCastle(CPG->ret.playerInfos[playersSoFar].castle,&ms.ourMaps[ms.selected].players[i]) != CPG->ret.playerInfos[playersSoFar].castle)
+		{
+			poptions[poptions.size()-1]->Cleft.show();
+			poptions[poptions.size()-1]->Cright.show();
+			CPG->btns.push_back(&poptions[poptions.size()-1]->Cleft);
+			CPG->btns.push_back(&poptions[poptions.size()-1]->Cright);
+		}
+
 		poptions[poptions.size()-1]->Bleft.show();
 		poptions[poptions.size()-1]->Bright.show();
-		CPG->btns.push_back(&poptions[poptions.size()-1]->Cleft);
-		CPG->btns.push_back(&poptions[poptions.size()-1]->Cright);
-		CPG->btns.push_back(&poptions[poptions.size()-1]->Hleft);
-		CPG->btns.push_back(&poptions[poptions.size()-1]->Hright);
 		CPG->btns.push_back(&poptions[poptions.size()-1]->Bleft);
 		CPG->btns.push_back(&poptions[poptions.size()-1]->Bright);
+
+
 		CSDL_Ext::printAtMiddle(CPG->ret.playerInfos[playersSoFar].name,111,137+playersSoFar*50,GEOR13,zwykly);
 		if (ms.ourMaps[ms.selected].players[i].canHumanPlay)
 		{
@@ -1289,7 +1314,7 @@ void MapSel::select(int which, bool updateMapsList, bool forceSettingsUpdate)
 			}
 			pset.heroPortrait=-1;
 			if (!
-				((curVector()[which].players[i].generateHeroAtMainTown 
+				(((curVector()[which].players[i].generateHeroAtMainTown || curVector()[which].version==RoE)
 					&& curVector()[which].players[i].hasMainTown) 
 				|| curVector()[which].players[i].p8)
 			  )

+ 1 - 0
ChangeLog

@@ -15,6 +15,7 @@ TOWN INTERFACE:
 
 OBJECTS:
 New objects supported:
+ * Magic Well
  *	Faerie Ring
  *	Swan Pond
  *	Idol of Fortune

+ 1 - 0
client/Client.h

@@ -87,6 +87,7 @@ public:
 	void moveHero(int hid, int3 pos, bool instant){};
 	void giveHeroBonus(GiveBonus * bonus){};
 	void setMovePoints(SetMovePoints * smp){};
+	void setManaPoints(int hid, int val){};
 	//////////////////////////////////////////////////////////////////////////
 	friend class CCallback; //handling players actions
 	friend void processCommand(const std::string &message, CClient *&client); //handling console

+ 43 - 0
hch/CObjectHandler.cpp

@@ -1719,6 +1719,49 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
 }
 
 const std::string & CGBonusingObject::getHoverText() const
+{
+	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
+	hoverName = VLC->generaltexth->names[ID];
+	if(h) 
+	{
+		if(!h->getBonus(HeroBonus::OBJECT,ID))
+			hoverName += " " + VLC->generaltexth->allTexts[353]; //not visited
+		else
+			hoverName += " " + VLC->generaltexth->allTexts[352]; //visited
+	}
+	return hoverName;
+}
+
+void CGMagicWell::onHeroVisit( const CGHeroInstance * h ) const
+{
+	int message;
+	InfoWindow iw;
+	iw.player = h->tempOwner;
+	if(h->getBonus(HeroBonus::OBJECT,ID)) //has already visited Well today
+	{
+		message = 78;
+	}
+	else if(h->mana < h->manaLimit())
+	{
+		GiveBonus gbonus;
+		gbonus.bonus.type = HeroBonus::NONE;
+		gbonus.hid = h->id;
+		gbonus.bonus.duration = HeroBonus::ONE_DAY;
+		gbonus.bonus.source = HeroBonus::OBJECT;
+		gbonus.bonus.id = ID;
+		cb->giveHeroBonus(&gbonus);
+		cb->setManaPoints(h->id,h->manaLimit());
+		message = 77;
+	}
+	else
+	{
+		message = 79;
+	}
+	iw.text << std::pair<ui8,ui32>(11,message); //"A second drink at the well in one day will not help you."
+	cb->showInfoDialog(&iw);
+}
+
+const std::string & CGMagicWell::getHoverText() const
 {
 	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
 	hoverName = VLC->generaltexth->names[ID];

+ 13 - 0
hch/CObjectHandler.h

@@ -623,6 +623,19 @@ public:
 	}
 };
 
+class DLL_EXPORT CGMagicWell : public CGObjectInstance //objects giving bonuses to luck/morale/movement
+{
+public:
+	void onHeroVisit(const CGHeroInstance * h) const;
+	const std::string & getHoverText() const;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CGObjectInstance&>(*this);
+	}
+};
+
+
 
 
 class DLL_EXPORT CObjectHandler

+ 14 - 1
lib/HeroBonus.h

@@ -23,4 +23,17 @@ struct DLL_EXPORT HeroBonus
 	{
 		h & duration & type & source & val & id & description;
 	}
-};
+
+	static bool OneDay(const HeroBonus &hb)
+	{
+		return hb.duration==HeroBonus::ONE_DAY;
+	}
+	static bool OneWeek(const HeroBonus &hb)
+	{
+		return hb.duration==HeroBonus::ONE_WEEK;
+	}
+	static bool OneBattle(const HeroBonus &hb)
+	{
+		return hb.duration==HeroBonus::ONE_BATTLE;
+	}
+};

+ 1 - 0
lib/IGameCallback.h

@@ -59,5 +59,6 @@ public:
 	virtual void moveHero(int hid, int3 pos, bool instant)=0;
 	virtual void giveHeroBonus(GiveBonus * bonus)=0;
 	virtual void setMovePoints(SetMovePoints * smp)=0;
+	virtual void setManaPoints(int hid, int val)=0;
 };
 #endif // __IGAMECALLBACK_H__

+ 10 - 7
map.cpp

@@ -1790,6 +1790,11 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 				nobj = new CGBonusingObject();
 				break;
 			}
+		case 49: //Magic Well
+			{
+				nobj = new CGMagicWell();
+				break;
+			}
 		case 214: //hero placeholder
 			{
 				i+=3; //TODO: handle it more properly
@@ -1830,13 +1835,11 @@ void Mapa::readEvents( unsigned char * bufor, int &i )
 		{
 			ne.message +=bufor[i]; ++i;
 		}
-		ne.wood = readNormalNr(bufor,i); i+=4;
-		ne.mercury = readNormalNr(bufor,i); i+=4;
-		ne.ore = readNormalNr(bufor,i); i+=4;
-		ne.sulfur = readNormalNr(bufor,i); i+=4;
-		ne.crystal = readNormalNr(bufor,i); i+=4;
-		ne.gems = readNormalNr(bufor,i); i+=4;
-		ne.gold = readNormalNr(bufor,i); i+=4;
+		ne.resources.resize(RESOURCE_QUANTITY);
+		for(int k=0; k < 7; k++)
+		{
+			ne.resources[k] = readNormalNr(bufor,i); i+=4;
+		}
 		ne.players = bufor[i]; ++i;
 		if(version>AB)
 		{

+ 8 - 4
map.h

@@ -7,6 +7,7 @@
 #include <vector>
 #include <map>
 #include <set>
+#include <list>
 #include "global.h"
 #ifndef _MSC_VER
 #include "hch/CObjectHandler.h"
@@ -185,15 +186,15 @@ class DLL_EXPORT CMapEvent
 {
 public:
 	std::string name, message;
-	si32 wood, mercury, ore, sulfur, crystal, gems, gold; //gained / taken resources
+	std::vector<si32> resources; //gained / taken resources
 	ui8 players; //affected players
 	ui8 humanAffected;
 	ui8 computerAffected;
 	ui32 firstOccurence;
-	ui32 nextOccurence; //after nextOccurance day event will occure; if it it 0, event occures only one time;
+	ui32 nextOccurence; //after nextOccurance day event will occur; if it it 0, event occures only one time;
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & name & message & wood & mercury & ore & sulfur & crystal & gems & gold
+		h & name & message & resources
 			& players & humanAffected & computerAffected & firstOccurence & nextOccurence;
 	}
 };
@@ -296,7 +297,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	std::vector<ui8> allowedArtifact; //allowedArtifact[artifact_ID] - if the artifact is allowed
 	std::vector<ui8> allowedAbilities; //allowedAbilities[ability_ID] - if the ability is allowed
 	std::vector<ui8> allowedHeroes; //allowedHeroes[hero_ID] - if the hero is allowed
-	std::vector<CMapEvent> events;
+	std::list<CMapEvent> events;
 
 	int3 grailPos;
 	int grailRadious;
@@ -506,6 +507,9 @@ struct DLL_EXPORT Mapa : public CMapHeader
 			case 31: //Fountain of Youth
 				SERIALIZE(CGBonusingObject);
 				break;
+			case 49: //Magic Well
+				SERIALIZE(CGMagicWell);
+				break;
 			default:
 				SERIALIZE(CGObjectInstance);
 			}

+ 8 - 0
server/CGameHandler.cpp

@@ -2459,4 +2459,12 @@ void CGameHandler::giveHeroBonus( GiveBonus * bonus )
 void CGameHandler::setMovePoints( SetMovePoints * smp )
 {
 	sendAndApply(smp);
+}
+
+void CGameHandler::setManaPoints( int hid, int val )
+{
+	SetMana sm;
+	sm.hid = hid;
+	sm.val = val;
+	sendAndApply(&sm);
 }

+ 1 - 0
server/CGameHandler.h

@@ -105,6 +105,7 @@ public:
 	void moveHero(int hid, int3 pos, bool instant);
 	void giveHeroBonus(GiveBonus * bonus);
 	void setMovePoints(SetMovePoints * smp);
+	void setManaPoints(int hid, int val);
 	//////////////////////////////////////////////////////////////////////////
 
 	void init(StartInfo *si, int Seed);