浏览代码

* fixes for moving War Machines
* automatic merging same creatures stacks if needed when moving hero to town garrison
* minor improvements

Michał W. Urbańczyk 16 年之前
父节点
当前提交
df87b34662
共有 8 个文件被更改,包括 125 次插入45 次删除
  1. 19 18
      client/AdventureMapButton.cpp
  2. 4 4
      client/AdventureMapButton.h
  3. 3 1
      client/CAdvmapInterface.cpp
  4. 5 5
      client/CCastleInterface.cpp
  5. 33 7
      client/GUIClasses.cpp
  6. 46 7
      int3.h
  7. 1 0
      lib/CGameState.cpp
  8. 14 3
      server/CGameHandler.cpp

+ 19 - 18
client/AdventureMapButton.cpp

@@ -199,27 +199,28 @@ void AdventureMapButton::hover (bool on)
 	}
 }
 
-void AdventureMapButton::activate()
-{
-// 	if (active) return;
-// 	active=true;
-	activateLClick();
-	activateRClick();
-	activateHover();
-	activateKeys();
-}
-void AdventureMapButton::deactivate()
-{
-// 	if (!active) return;
-// 	active=false;
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-	deactivateKeys();
-}
+//void AdventureMapButton::activate()
+//{
+//// 	if (active) return;
+//// 	active=true;
+//	activateLClick();
+//	activateRClick();
+//	activateHover();
+//	activateKeys();
+//}
+//void AdventureMapButton::deactivate()
+//{
+//// 	if (!active) return;
+//// 	active=false;
+//	deactivateLClick();
+//	deactivateRClick();
+//	deactivateHover();
+//	deactivateKeys();
+//}
 
 void AdventureMapButton::init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key)
 {
+	used = LCLICK | RCLICK | HOVER | KEYBOARD;
 	callback = Callback;
 	blocked = actOnDown = false;
 	type=2;

+ 4 - 4
client/AdventureMapButton.h

@@ -42,8 +42,8 @@ public:
 	int curimg; //curently displayed image from imgs
 	virtual void show(SDL_Surface * to);
 	virtual void showAll(SDL_Surface * to);
-	virtual void activate()=0;
-	virtual void deactivate()=0;
+	//virtual void activate()=0;
+	//virtual void deactivate()=0;
 	CButtonBase(); //c-tor
 	virtual ~CButtonBase(); //d-tor
 };
@@ -63,8 +63,8 @@ public:
 	virtual void clickLeft(tribool down, bool previousState);
 	void hover (bool on);
 	void block(ui8 on); //if button is blocked then it'll change it's graphic to inactive (offset==2) and won't react on l-clicks
-	void activate(); // makes button active
-	void deactivate(); // makes button inactive (but doesn't delete)
+	//void activate(); // makes button active
+	//void deactivate(); // makes button inactive (but doesn't delete)
 
 	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

+ 3 - 1
client/CAdvmapInterface.cpp

@@ -571,7 +571,7 @@ void CTerrainRect::clickRight(tribool down, bool previousState)
 	if(!objs.size())
 		return;
 
-	const CGObjectInstance * obj = objs.front();
+	const CGObjectInstance * obj = objs.back();
 	switch(obj->ID)
 	{
 	case HEROI_TYPE:
@@ -1728,6 +1728,8 @@ void CAdvMapInt::centerOn(int3 on)
 	LOCPLINT->adventureInt->position = on;
 	LOCPLINT->adventureInt->updateScreen=true;
 	updateMinimap=true;
+	underground.curimg = on.z; //change underground switch button image 
+	underground.redraw();
 }
 void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 {

+ 5 - 5
client/CCastleInterface.cpp

@@ -270,7 +270,7 @@ void CHeroGSlot::clickLeft(tribool down, bool previousState)
 		else if(other->hero && other->highlight)
 		{
 			bool allow = true;
-			if(upg) //moving hero out of town - check if it is allowed
+			if(!upg) //moving hero out of town - check if it is allowed
 			{
 				if(!hero && LOCPLINT->cb->howManyHeroes(false) >= 8)
 				{
@@ -505,7 +505,7 @@ CCastleInterface::~CCastleInterface()
 	SDL_FreeSurface(townInt);
 	SDL_FreeSurface(cityBg);
 	delete exit;
-	delete split;
+	//delete split;
 	delete hall;
 	delete fort;
 	delete garr;
@@ -749,7 +749,7 @@ void CCastleInterface::showAll( SDL_Surface * to/*=NULL*/)
 	if(screen->w != 800 || screen->h !=600)
 		CMessage::drawBorder(LOCPLINT->playerID,to,828,628,pos.x-14,pos.y-15);
 	exit->show(to);
-	split->show(to);
+	//split->show(to);
 }
 
 void CCastleInterface::townChange()
@@ -796,7 +796,7 @@ void CCastleInterface::activate()
 	garr->activate();
 	LOCPLINT->statusbar = statusbar;
 	exit->activate();
-	split->activate();
+	//split->activate();
 	for(size_t i=0;i<buildings.size();i++) //XXX pls use iterators or at() but not []
 	{
 		buildings[i]->activate();
@@ -812,7 +812,7 @@ void CCastleInterface::deactivate()
 	townlist->deactivate();
 	garr->deactivate();
 	exit->deactivate();
-	split->deactivate();
+	//split->deactivate();
 	for(size_t i=0;i<buildings.size();i++) //XXX iterators
 	{
 		buildings[i]->deactivate();

+ 33 - 7
client/GUIClasses.cpp

@@ -386,6 +386,9 @@ CGarrisonInt::~CGarrisonInt()
 		}
 		delete sdown;
 	}
+
+	for(size_t i = 0; i<splitButtons.size(); i++)
+		delete splitButtons[i];
 }
 
 void CGarrisonInt::show(SDL_Surface * to)
@@ -459,9 +462,6 @@ void CGarrisonInt::activeteSlots()
 			}
 		}
 	}
-
-	for(size_t i = 0; i<splitButtons.size(); i++)
-		splitButtons[i]->activate();
 }
 void CGarrisonInt::createSlots()
 {
@@ -3424,6 +3424,12 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 		{
 			if(ourArt) //to prevent selecting empty slots (bugfix to what GrayFace reported)
 			{
+				if(ourArt->id == 3) //catapult cannot be highlighted
+				{
+					std::vector<SComponent *> catapult(1, new SComponent(SComponent::artifact, 3, 0));
+					LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[312], catapult); //The Catapult must be equipped.
+					return;
+				}
 				clicked = true;
 				ourOwner->commonInfo->activeArtPlace = this;
 			}
@@ -3432,8 +3438,24 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
 		{
 			if(slotID >= 19)	//we are an backpack slot - remove active artifact and put it to the last free pos in backpack
 			{					//TODO: putting artifacts in the middle of backpack (pushing following arts)
-				
-				LOCPLINT->cb->swapArtifacts(ourOwner->commonInfo->activeArtPlace->ourOwner->curHero, ourOwner->commonInfo->activeArtPlace->slotID, ourOwner->curHero, ourOwner->curHero->artifacts.size()+19);
+				const CArtifact *cur = ourOwner->commonInfo->activeArtPlace->ourArt;
+				assert(cur); //there is highlighted slot, it must contain an art
+				switch(cur->id)
+				{
+				case 3:
+					//should not happen, catapult cannot be selected
+					break;
+				case 4: case 5: case 6:
+					{
+						std::string text = CGI->generaltexth->allTexts[153];
+						boost::algorithm::replace_first(text, "%s", cur->Name());
+						LOCPLINT->showInfoDialog(text);
+					}
+					break;
+				default:
+					LOCPLINT->cb->swapArtifacts(ourOwner->commonInfo->activeArtPlace->ourOwner->curHero, ourOwner->commonInfo->activeArtPlace->slotID, ourOwner->curHero, ourOwner->curHero->artifacts.size()+19);
+					break;
+				}
 			}
 			//check if swap is possible
 			else if(this->fitsHere(ourOwner->commonInfo->activeArtPlace->ourArt) && ourOwner->commonInfo->activeArtPlace->fitsHere(this->ourArt))
@@ -3495,8 +3517,12 @@ bool CArtPlace::fitsHere(const CArtifact * art)
 {
 	if(!art)
 		return true; //you can have no artifact somewhere
-	if(slotID > 18   ||   vstd::contains(art->possibleSlots,slotID)) //backpack or right slot
+	if(slotID > 18 && art->id >= 3 && art->id <= 6		//everything can bee placed in backpack exept of War Machines
+	  || vstd::contains(art->possibleSlots,slotID))
+	{
 		return true;
+	}
+
 	return false;
 }
 CArtPlace::~CArtPlace()
@@ -4075,7 +4101,7 @@ CExchangeWindow::CExchangeWindow(si32 hero1, si32 hero2) : bg(NULL)
 	ourBar = new CStatusBar(pos.x + 3, pos.y + 577, "TSTATBAR.bmp", 726);
 
 	//garrison interface
-	garr = new CGarrisonInt(pos.x + 69, pos.y + 131, 4, Point(418,0), bg, Point(69,131), heroInst[0],heroInst[1], true);
+	garr = new CGarrisonInt(pos.x + 69, pos.y + 131, 4, Point(418,0), bg, Point(69,131), heroInst[0],heroInst[1], true, true);
 
 	garr->splitButtons.push_back(new AdventureMapButton(CGI->generaltexth->tcommands[3],"",boost::bind(&CGarrisonInt::splitClick,garr),pos.x+10,pos.y+132,"TSBTNS.DEF"));
 	garr->splitButtons.push_back(new AdventureMapButton(CGI->generaltexth->tcommands[3],"",boost::bind(&CGarrisonInt::splitClick,garr),pos.x+740,pos.y+132,"TSBTNS.DEF"));

+ 46 - 7
int3.h

@@ -15,20 +15,28 @@
  */
 
 class CCreature;
+
+//a few typedefs for CCreatureSet
+typedef si32 TSlot, TQuantity;
+typedef ui32 TCreature;
+typedef std::pair<TCreature, TQuantity> TStack;
+typedef std::map<TSlot, TStack> TSlots;
+
 class CCreatureSet //seven combined creatures
 {
 public:
-	std::map<si32, std::pair<ui32,si32> > slots; //slots[slot_id]=> pair(creature_id,creature_quantity)
-	bool formation; //false - wide, true - tight
-	bool setCreature (si32 slot, ui32 type, si32 quantity) //slots 0 to 6
+	TSlots slots; //slots[slot_id]=> pair(creature_id,creature_quantity)
+	ui8 formation; //false - wide, true - tight
+
+	bool setCreature (TSlot slot, TCreature type, TQuantity quantity) //slots 0 to 6
 	{
-		slots[slot] = std::pair<ui32, si32>(type, quantity);  //brutal force
+		slots[slot] = TStack(type, quantity);  //brutal force
 		if (slots.size() > 7) return false;
 		else return true;
 	}
-	si32 getSlotFor(ui32 creature, ui32 slotsAmount=7) const //returns -1 if no slot available
+	TSlot getSlotFor(TCreature creature, ui32 slotsAmount=7) const //returns -1 if no slot available
 	{	
-		for(std::map<si32,std::pair<ui32,si32> >::const_iterator i=slots.begin(); i!=slots.end(); ++i)
+		for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
 		{
 			if(i->second.first == creature)
 			{
@@ -44,6 +52,37 @@ public:
 		}
 		return -1; //no slot available
 	}
+	bool mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable = -1) //looks for two same stacks, returns slot positions
+	{
+		//try to match creature to our preferred stack
+		if(preferable >= 0  &&  slots.find(preferable) != slots.end())
+		{
+			TCreature id = slots[preferable].first;
+			for(TSlots::const_iterator j=slots.begin(); j!=slots.end(); ++j)
+			{
+				if(id == j->second.first)
+				{
+					out.first = preferable;
+					out.second = j->first;
+					return true;
+				}
+			}
+		}
+
+		for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i)
+		{
+			for(TSlots::const_iterator j=slots.begin(); j!=slots.end(); ++j)
+			{
+				if(i->second.first == j->second.first)
+				{
+					out.first = i->first;
+					out.second = j->first;
+					return true;
+				}
+			}
+		}
+		return false;
+	}
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & slots & formation;
@@ -54,7 +93,7 @@ public:
 	}
 	void sweep()
 	{
-		for(std::map<si32,std::pair<ui32,si32> >::iterator i=slots.begin(); i!=slots.end(); ++i)
+		for(TSlots::iterator i=slots.begin(); i!=slots.end(); ++i)
 		{
 			if(!i->second.second)
 			{

+ 1 - 0
lib/CGameState.cpp

@@ -2097,6 +2097,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
 				|| dp.turns > turn
 				|| (dp.turns >= turn  &&  dp.moveRemains < remains)) //this route is faster
 			{
+				assert(&dp != cp->theNodeBefore); //two tiles can't point to each other
 				dp.moveRemains = remains;
 				dp.turns = turn;
 				dp.theNodeBefore = cp;

+ 14 - 3
server/CGameHandler.cpp

@@ -2162,10 +2162,21 @@ bool CGameHandler::garrisonSwap( si32 tid )
 			int pos = csn.getSlotFor(cso.slots.begin()->second.first);
 			if(pos<0)
 			{
-				complain("Cannot make garrison swap, not enough free slots!");
-				return false;
+				//try to merge two other stacks to make place
+				std::pair<TSlot, TSlot> toMerge;
+				if(csn.mergableStacks(toMerge, cso.slots.begin()->first))
+				{
+					//merge
+					csn.slots[toMerge.second].second += csn.slots[toMerge.first].second;
+					csn.slots[toMerge.first] = cso.slots.begin()->second;
+				}
+				else
+				{
+					complain("Cannot make garrison swap, not enough free slots!");
+					return false;
+				}
 			}
-			if(csn.slots.find(pos)!=csn.slots.end()) //add creatures to the existing stack
+			else if(csn.slots.find(pos) != csn.slots.end()) //add creatures to the existing stack
 			{
 				csn.slots[pos].second += cso.slots.begin()->second.second;
 			}