Browse Source

* Garrison dialogs for garrisons. Required a bit restructuring of the code to take removable units into account. All showGarrisonDialog methods and the GarrisonDialog struct now takes it as a parameter. Visiting ally towns would benefit from this other than garrisons.
* Garrison right-click information shown, but not taking detailed info into account.
* Town info dialogs centered around cursor.

OnionKnight 16 years ago
parent
commit
3d2ab9c753

+ 1 - 1
AI/GeniusAI/CGeniusAI.cpp

@@ -940,7 +940,7 @@ void CGeniusAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector
 	callback(rand() % skills.size());
 }
 
-void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd )
+void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd )
 {
 	onEnd();
 }

+ 1 - 1
AI/GeniusAI/CGeniusAI.h

@@ -187,7 +187,7 @@ public:
 	virtual void tileRevealed(int3 pos);
 	virtual void tileHidden(int3 pos);
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
-	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd);
+	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd);
 	virtual void playerBlocked(int reason);
 
 	virtual void objectRemoved(const CGObjectInstance *obj); //eg. collected resource, picked artifact, beaten hero

+ 1 - 1
CGameInterface.h

@@ -90,7 +90,7 @@ public:
 	virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level){}
 	virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
-	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
+	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void tileHidden(const std::set<int3> &pos){};
 	virtual void tileRevealed(const std::set<int3> &pos){};
 	virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard

+ 27 - 4
client/CAdvmapInterface.cpp

@@ -609,8 +609,8 @@ void CTerrainRect::clickRight(tribool down, bool previousState)
 				if(LOCPLINT->cb->getTownInfo(obj, iah))
 				{
 					SDL_Surface *iwin = graphics->drawTownInfoWin(iah);
-					CInfoPopup * ip = new CInfoPopup(iwin, GH.current->motion.x-iwin->w,
-						GH.current->motion.y-iwin->h, true);
+					CInfoPopup * ip = new CInfoPopup(iwin, GH.current->motion.x - iwin->w/2,
+						GH.current->motion.y - iwin->h/2, true);
 					GH.pushInt(ip);
 				}
 				else
@@ -621,13 +621,36 @@ void CTerrainRect::clickRight(tribool down, bool previousState)
 			else
 			{
 				CInfoPopup * ip = new CInfoPopup(graphics->townWins[obj->id],
-					GH.current->motion.x-graphics->townWins[obj->id]->w,
-					GH.current->motion.y-graphics->townWins[obj->id]->h,false
+					GH.current->motion.x - graphics->townWins[obj->id]->w/2,
+					GH.current->motion.y - graphics->townWins[obj->id]->h/2,false
 					);
 				GH.pushInt(ip);
 			}
 			break;
 		}
+	case 33: // Garrison
+		{
+			const CGGarrison *garr = dynamic_cast<const CGGarrison *>(obj);
+
+			if (garr != NULL) {
+				InfoAboutTown iah;
+
+				iah.fortLevel = 0;
+				iah.army = garr->army;
+				iah.name = std::string("Garrison");
+				iah.owner = garr->tempOwner;
+				iah.built = false;
+				iah.details = NULL; // TODO: Find a suitable way to show detailed info.
+				iah.tType = NULL;
+
+				SDL_Surface *iwin = graphics->drawTownInfoWin(iah);
+				CInfoPopup * ip = new CInfoPopup(iwin,
+					GH.current->motion.x - iwin->w/2,
+					GH.current->motion.y - iwin->h/2, true);
+				GH.pushInt(ip);
+			}
+			break;
+		}
 	default:
 		{
 			LOCPLINT->adventureInt->handleRightClick(obj->getHoverText(),down,this);

+ 2 - 2
client/CPlayerInterface.cpp

@@ -1476,7 +1476,7 @@ bool CPlayerInterface::shiftPressed() const
 	return SDL_GetKeyState(NULL)[SDLK_LSHIFT]  ||  SDL_GetKeyState(NULL)[SDLK_RSHIFT];
 }
 
-void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd )
+void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd )
 {
 	{
 		boost::unique_lock<boost::mutex> un(showingDialog->mx);
@@ -1491,7 +1491,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
 		SDL_Delay(20);
 		pim->lock();
 	}
-	CGarrisonWindow *cgw = new CGarrisonWindow(up,down);
+	CGarrisonWindow *cgw = new CGarrisonWindow(up,down,removableUnits);
 	cgw->quit->callback += onEnd;
 	GH.pushInt(cgw);
 }

+ 1 - 1
client/CPlayerInterface.h

@@ -149,7 +149,7 @@ public:
 	void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level);
 	void showShipyardDialog(const IShipyard *obj); //obj may be town or shipyard; 
 	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
-	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd);
+	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd);
 	void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war
 	void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles
 	void newObject(const CGObjectInstance * obj);

+ 1 - 1
client/Client.h

@@ -97,7 +97,7 @@ public:
 	void showInfoDialog(InfoWindow *iw){};
 	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback){};
 	ui32 showBlockingDialog(BlockingDialog *iw){return 0;}; //synchronous version of above
-	void showGarrisonDialog(int upobj, int hid, const boost::function<void()> &cb){};
+	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb){};
 	void giveResource(int player, int which, int val){};
 	void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet *creatures){};
 	void showCompInfo(ShowInInfobox * comp){};

+ 58 - 44
client/GUIClasses.cpp

@@ -222,52 +222,66 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
 				refr = true;
 				delete pom2;
 			}
-			else if((owner->splitting || LOCPLINT->shiftPressed())
-				&& (!creature
-					|| (creature == owner->highlighted->creature))
-			) //we want to split
-			{
-				owner->p2 = ID; //store the second stack pos
-				owner->pb = upg;//store the second stack owner (up or down army)
-				owner->splitting = false;
-
-				int totalAmount = owner->highlighted->count;
-				if(creature) 
-					totalAmount += count;
-
-				int last = -1;
-				if(upg != owner->highlighted->upg) //not splitting within same army
+			else {
+				// Only allow certain moves if troops aren't removable.
+				if (owner->removableUnits
+					|| (upg == 0 && (owner->highlighted->upg == 1 && !creature))
+					|| (upg == 1 && owner->highlighted->upg == 1))
 				{
-					if(owner->highlighted->getObj()->army.slots.size() == 1
-						&& owner->highlighted->getObj()->needsLastStack() )
+					//we want to split
+					if((owner->splitting || LOCPLINT->shiftPressed())
+						&& (!creature
+							|| (creature == owner->highlighted->creature)))
 					{
-						last = 0;
+						owner->p2 = ID; //store the second stack pos
+						owner->pb = upg;//store the second stack owner (up or down army)
+						owner->splitting = false;
+
+						int totalAmount = owner->highlighted->count;
+						if(creature) 
+							totalAmount += count;
+
+						int last = -1;
+						if(upg != owner->highlighted->upg) //not splitting within same army
+						{
+							if(owner->highlighted->getObj()->army.slots.size() == 1
+								&& owner->highlighted->getObj()->needsLastStack() )
+							{
+								last = 0;
+							}
+							if(getObj()->army.slots.size() == 1
+								&& getObj()->needsLastStack() )
+							{
+								last += 2;
+							}
+						}
+
+
+						CSplitWindow * spw = new CSplitWindow(owner->highlighted->creature->idNumber, totalAmount, owner, last, count);
+						GH.pushInt(spw);
+						refr = true;
 					}
-					if(getObj()->army.slots.size() == 1
-						&& getObj()->needsLastStack() )
+					else if(creature != owner->highlighted->creature) //swap
 					{
-						last += 2;
+						LOCPLINT->cb->swapCreatures(
+							(!upg)?(owner->oup):(owner->odown),
+							(!owner->highlighted->upg)?(owner->oup):(owner->odown),
+							ID,owner->highlighted->ID);
+					}
+					else //merge
+					{
+						LOCPLINT->cb->mergeStacks(
+							(!owner->highlighted->upg)?(owner->oup):(owner->odown),
+							(!upg)?(owner->oup):(owner->odown),
+							owner->highlighted->ID,ID);
 					}
 				}
-
-
-				CSplitWindow * spw = new CSplitWindow(owner->highlighted->creature->idNumber, totalAmount, owner, last, count);
-				GH.pushInt(spw);
-				refr = true;
-			}
-			else if(creature != owner->highlighted->creature) //swap
-			{
-				LOCPLINT->cb->swapCreatures(
-					(!upg)?(owner->oup):(owner->odown),
-					(!owner->highlighted->upg)?(owner->oup):(owner->odown),
-					ID,owner->highlighted->ID);
-			}
-			else //merge
-			{
-				LOCPLINT->cb->mergeStacks(
-					(!owner->highlighted->upg)?(owner->oup):(owner->odown),
-					(!upg)?(owner->oup):(owner->odown),
-					owner->highlighted->ID,ID);
+				else { // Highlight
+					if(creature)
+						owner->highlighted = this;
+					show(screen2);
+					refr = true;
+				}
 			}
 		}
 		else //highlight
@@ -559,9 +573,9 @@ void CGarrisonInt::splitStacks(int am2)
 
 }
 CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *&pomsur, const Point& SurOffset, 
-						   const CArmedInstance *s1, const CArmedInstance *s2, bool smallImgs)
+						   const CArmedInstance *s1, const CArmedInstance *s2, bool _removableUnits, bool smallImgs)
 	 :interx(inx),garOffset(garsOffset),highlighted(NULL),sur(pomsur),surOffset(SurOffset),sup(NULL),
-	 sdown(NULL),oup(s1),odown(s2), smallIcons(smallImgs)
+	 sdown(NULL),oup(s1),odown(s2), removableUnits(_removableUnits), smallIcons(smallImgs)
 {
 	active = false;
 	splitting = false;
@@ -3320,7 +3334,7 @@ void CGarrisonWindow::show(SDL_Surface * to)
 	printAtMiddle(CGI->generaltexth->allTexts[709],pos.x+275,pos.y+30,GEOR16,tytulowy,to);
 }
 
-CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down )
+CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits )
 {
 	bg = BitmapHandler::loadBitmap("GARRISON.bmp");
 	SDL_SetColorKey(bg,SDL_SRCCOLORKEY,SDL_MapRGB(bg->format,0,255,255));
@@ -3330,7 +3344,7 @@ CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance
 	pos.w = screen->w;
 	pos.h = screen->h;
 
-	garr = new CGarrisonInt(pos.x+92, pos.y+127, 4, Point(0,96), bg, Point(93,127), up, down);
+	garr = new CGarrisonInt(pos.x+92, pos.y+127, 4, Point(0,96), bg, Point(93,127), up, down, removableUnits);
 	garr->splitButtons.push_back(new AdventureMapButton(CGI->generaltexth->tcommands[3],"",boost::bind(&CGarrisonInt::splitClick,garr),pos.x+88,pos.y+314,"IDV6432.DEF"));
 	quit = new AdventureMapButton(CGI->generaltexth->tcommands[8],"",boost::bind(&CGarrisonWindow::close,this),pos.x+399,pos.y+314,"IOK6432.DEF",SDLK_RETURN);
 }

+ 3 - 2
client/GUIClasses.h

@@ -211,6 +211,7 @@ public:
 	int p2; //TODO: comment me
 	bool ignoreEvent, update, active, splitting, pb, 
 		smallIcons; //true - 32x32 imgs, false - 58x64
+	bool removableUnits;
 
 	const CCreatureSet *set1; //top set of creatures
 	const CCreatureSet *set2; //bottom set of creatures
@@ -230,7 +231,7 @@ public:
 	void splitClick(); //handles click on split button
 	void splitStacks(int am2); //TODO: comment me
 
-	CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *&pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=NULL, bool smallImgs = false); //c-tor
+	CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *&pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=NULL, bool _removableUnits = true, bool smallImgs = false); //c-tor
 	~CGarrisonInt(); //d-tor
 };
 
@@ -689,7 +690,7 @@ public:
 	void deactivate();
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to){show(to);};
-	CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down); //c-tor
+	CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor
 	~CGarrisonWindow(); //d-tor
 };
 

+ 8 - 6
client/Graphics.cpp

@@ -117,12 +117,14 @@ SDL_Surface * Graphics::drawTownInfoWin( const InfoAboutTown & curh )
 	}
 
 	//blit town icon
-	pom = curh.tType->typeID*2;
-	if (!curh.fortLevel)
-		pom += F_NUMBER*2;
-	if(curh.built)
-		pom++;
-	blitAt(bigTownPic->ourImages[pom].bitmap,13,13,ret);
+	if (curh.tType) {
+		pom = curh.tType->typeID*2;
+		if (!curh.fortLevel)
+			pom += F_NUMBER*2;
+		if(curh.built)
+			pom++;
+		blitAt(bigTownPic->ourImages[pom].bitmap,13,13,ret);
+	}
 
 	if(curh.details)
 	{

+ 1 - 1
client/NetPacksClient.cpp

@@ -327,7 +327,7 @@ void GarrisonDialog::applyCl(CClient *cl)
 		return;
 
 	boost::function<void()> callback = boost::bind(&CCallback::selectionMade,LOCPLINT->cb,0,id);
-	cl->playerint[h->getOwner()]->showGarrisonDialog(obj,h,callback);
+	cl->playerint[h->getOwner()]->showGarrisonDialog(obj,h,removableUnits,callback);
 }
 
 void BattleStart::applyCl( CClient *cl )

+ 4 - 4
hch/CObjectHandler.cpp

@@ -2219,7 +2219,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
 		}
 		else
 		{
-			cb->showGarrisonDialog(id,h->id,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends
+			cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends
 		}
 	}
 }
@@ -2245,7 +2245,7 @@ void CGMine::onHeroVisit( const CGHeroInstance * h ) const
 
 	if(h->tempOwner == tempOwner) //we're visiting our mine
 	{
-		cb->showGarrisonDialog(id,h->id,0);
+		cb->showGarrisonDialog(id,h->id,true,0);
 		return; 
 	}
 
@@ -3350,7 +3350,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
 		SetGarrisons sg;
 		sg.garrs[id] = creatures;
 		cb->sendAndApply(&sg);
-		cb->showGarrisonDialog(id,h->id,boost::bind(&IGameCallback::removeObject,cb,id));
+		cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id));
 	}
 
 	if(!afterBattle && message.size())
@@ -3631,7 +3631,7 @@ void CGGarrison::onHeroVisit (const CGHeroInstance *h) const
 	if (h->tempOwner != tempOwner)
 		cb->setOwner(id, h->tempOwner);
 
-	//TODO: Garrison visit screen.
+	cb->showGarrisonDialog(id, h->id, removableUnits, 0);
 }
 
 void CGGarrison::fightOver (const CGHeroInstance *h, BattleResult *result) const

+ 1 - 1
lib/IGameCallback.h

@@ -73,7 +73,7 @@ public:
 	virtual void showInfoDialog(InfoWindow *iw)=0;
 	virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
 	virtual ui32 showBlockingDialog(BlockingDialog *iw) =0; //synchronous version of above //TODO:
-	virtual void showGarrisonDialog(int upobj, int hid, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
+	virtual void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
 	virtual void giveResource(int player, int which, int val)=0;
 	virtual void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet *creatures)=0;
 	virtual void showCompInfo(ShowInInfobox * comp)=0;

+ 2 - 1
lib/NetPacks.h

@@ -722,10 +722,11 @@ struct GarrisonDialog : public Query//2004
 	GarrisonDialog(){type = 2004;}
 	void applyCl(CClient *cl);
 	si32 objid, hid;
+	bool removableUnits;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & id & objid & hid;
+		h & id & objid & hid & removableUnits;
 	}
 };
 

+ 3 - 2
server/CGameHandler.cpp

@@ -1587,7 +1587,7 @@ void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, CCreature
 		SetGarrisons sg;
 		sg.garrs[objid] = *creatures;
 		sendAndApply(&sg);
-		showGarrisonDialog(objid, h->id, 0);
+		showGarrisonDialog(objid, h->id, true, 0);
 		return;
 	}
 }
@@ -3191,7 +3191,7 @@ ui32 CGameHandler::getQueryResult( ui8 player, int queryID )
 	return 0;
 }
 
-void CGameHandler::showGarrisonDialog( int upobj, int hid, const boost::function<void()> &cb )
+void CGameHandler::showGarrisonDialog( int upobj, int hid, bool removableUnits, const boost::function<void()> &cb )
 {
 	ui8 player = getOwner(hid);
 	GarrisonDialog gd;
@@ -3205,6 +3205,7 @@ void CGameHandler::showGarrisonDialog( int upobj, int hid, const boost::function
 		allowedExchanges[QID] = std::pair<si32,si32>(upobj,hid);
 		states.addQuery(player,QID);
 		QID++; 
+		gd.removableUnits = removableUnits;
 		sendAndApply(&gd);
 	}
 }

+ 1 - 1
server/CGameHandler.h

@@ -113,7 +113,7 @@ public:
 	void showInfoDialog(InfoWindow *iw);
 	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback);
 	ui32 showBlockingDialog(BlockingDialog *iw); //synchronous version of above
-	void showGarrisonDialog(int upobj, int hid, const boost::function<void()> &cb);
+	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb);
 	void giveResource(int player, int which, int val);
 	void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet *creatures);
 	void showCompInfo(ShowInInfobox * comp);