mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Reducing size of GUIClasses. Moved Garrison Int into a separate file.
This commit is contained in:
		| @@ -16,6 +16,7 @@ set(client_SRCS | ||||
|  | ||||
| 		gui/CArtifactHolder.cpp | ||||
| 		gui/CComponent.cpp | ||||
| 		gui/CGarrisonInt.cpp | ||||
| 		gui/CGuiHandler.cpp | ||||
| 		gui/CIntObject.cpp | ||||
| 		gui/CIntObjectClasses.cpp | ||||
|   | ||||
| @@ -259,454 +259,6 @@ CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town): | ||||
| 	init(InfoAboutTown(town, true)); | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::setHighlight(bool on) | ||||
| { | ||||
| 	if (on) | ||||
| 		selectionImage->enable(); //show | ||||
| 	else | ||||
| 		selectionImage->disable(); //hide | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::hover (bool on) | ||||
| { | ||||
| 	////Hoverable::hover(on); | ||||
| 	if(on) | ||||
| 	{ | ||||
| 		std::string temp; | ||||
| 		if(creature) | ||||
| 		{ | ||||
| 			if(owner->getSelection()) | ||||
| 			{ | ||||
| 				if(owner->getSelection() == this) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[4]; //View %s | ||||
| 					boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 				} | ||||
| 				else if (owner->getSelection()->creature == creature) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[2]; //Combine %s armies | ||||
| 					boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 				} | ||||
| 				else if (owner->getSelection()->creature) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[7]; //Exchange %s with %s | ||||
| 					boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing); | ||||
| 					boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
|                     logGlobal->warnStream() << "Warning - shouldn't be - highlighted void slot "<<owner->getSelection(); | ||||
|                     logGlobal->warnStream() << "Highlighted set to nullptr"; | ||||
| 					owner->selectSlot(nullptr); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if(upg) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting) | ||||
| 				} | ||||
| 				else if(owner->armedObjs[0] && owner->armedObjs[0]->ID == Obj::TOWN) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison) | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->allTexts[481]; //Select %s | ||||
| 				} | ||||
| 				boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 			}; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if(owner->getSelection()) | ||||
| 			{ | ||||
| 				const CArmedInstance *highl = owner->getSelection()->getObj(); | ||||
| 				if(  highl->needsLastStack()		//we are moving stack from hero's | ||||
| 				  && highl->stacksCount() == 1	//it's only stack | ||||
| 				  && owner->getSelection()->upg != upg	//we're moving it to the other garrison | ||||
| 				  ) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[5]; //Cannot move last army to garrison | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[6]; //Move %s | ||||
| 					boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				temp = CGI->generaltexth->tcommands[11]; //Empty | ||||
| 			} | ||||
| 		} | ||||
| 		GH.statusbar->setText(temp); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		GH.statusbar->clear(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const CArmedInstance * CGarrisonSlot::getObj() const | ||||
| { | ||||
| 	return 	(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]); | ||||
| } | ||||
|  | ||||
| bool CGarrisonSlot::our() const | ||||
| { | ||||
| 	return 	upg?(owner->owned[1]):(owner->owned[0]); | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::clickRight(tribool down, bool previousState) | ||||
| { | ||||
| 	if(down && creature) | ||||
| 	{ | ||||
| 		GH.pushInt(createCreWindow(myStack, CCreatureWindow::ARMY)); | ||||
| 	} | ||||
| } | ||||
| void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
| { | ||||
| 	if(down) | ||||
| 	{ | ||||
| 		bool refr = false; | ||||
| 		if(owner->getSelection()) | ||||
| 		{ | ||||
| 			if(owner->getSelection() == this) //view info | ||||
| 			{ | ||||
| 				UpgradeInfo pom; | ||||
| 				LOCPLINT->cb->getUpgradeInfo(getObj(), ID, pom); | ||||
|  | ||||
| 				bool canUpgrade = getObj()->tempOwner == LOCPLINT->playerID && pom.oldID>=0; //upgrade is possible | ||||
| 				bool canDismiss = getObj()->tempOwner == LOCPLINT->playerID && (getObj()->stacksCount()>1  || !getObj()->needsLastStack()); | ||||
| 				std::function<void()> upgr = nullptr; | ||||
| 				std::function<void()> dism = nullptr; | ||||
| 				if(canUpgrade) upgr = [=] { LOCPLINT->cb->upgradeCreature(getObj(), ID, pom.newID[0]); }; | ||||
| 				if(canDismiss) dism = [=] { LOCPLINT->cb->dismissCreature(getObj(), ID); }; | ||||
|  | ||||
| 				owner->selectSlot(nullptr); | ||||
| 				owner->setSplittingMode(false); | ||||
|  | ||||
| 				for(auto & elem : owner->splitButtons) | ||||
| 					elem->block(true); | ||||
|  | ||||
| 				redraw(); | ||||
| 				refr = true; | ||||
| 				CIntObject *creWindow = createCreWindow(myStack, CCreatureWindow::HERO, upgr, dism, &pom); | ||||
| 				GH.pushInt(creWindow); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				// Only allow certain moves if troops aren't removable or not ours. | ||||
| 				if (  ( owner->getSelection()->our()//our creature is selected | ||||
| 				     || owner->getSelection()->creature == creature )//or we are rebalancing army | ||||
| 				   && ( owner->removableUnits | ||||
| 				     || (upg == 0 &&  ( owner->getSelection()->upg == 1 && !creature ) ) | ||||
| 					 || (upg == 1 &&    owner->getSelection()->upg == 1 ) ) ) | ||||
| 				{ | ||||
| 					//we want to split | ||||
| 					if((owner->getSplittingMode() || LOCPLINT->shiftPressed()) | ||||
| 						&& (!creature | ||||
| 							|| (creature == owner->getSelection()->creature))) | ||||
| 					{ | ||||
| 						owner->p2 = ID; //store the second stack pos | ||||
| 						owner->pb = upg;//store the second stack owner (up or down army) | ||||
| 						owner->setSplittingMode(false); | ||||
|  | ||||
| 						int minLeft=0, minRight=0; | ||||
|  | ||||
| 						if(upg != owner->getSelection()->upg) //not splitting within same army | ||||
| 						{ | ||||
| 							if(owner->getSelection()->getObj()->stacksCount() == 1 //we're splitting away the last stack | ||||
| 								&& owner->getSelection()->getObj()->needsLastStack() ) | ||||
| 							{ | ||||
| 								minLeft = 1; | ||||
| 							} | ||||
| 							if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature | ||||
| 								&& owner->getSelection()->creature == creature | ||||
| 								&& getObj()->needsLastStack() ) | ||||
| 							{ | ||||
| 								minRight = 1; | ||||
| 							} | ||||
| 						} | ||||
|  | ||||
| 						int countLeft = owner->getSelection()->myStack ? owner->getSelection()->myStack->count : 0; | ||||
| 						int countRight = myStack ? myStack->count : 0; | ||||
|  | ||||
| 						GH.pushInt(new CSplitWindow(owner->getSelection()->creature, boost::bind(&CGarrisonInt::splitStacks, owner, _1, _2), | ||||
| 						                            minLeft, minRight, countLeft, countRight)); | ||||
| 						refr = true; | ||||
| 					} | ||||
| 					else if(creature != owner->getSelection()->creature) //swap | ||||
| 					{ | ||||
| 						LOCPLINT->cb->swapCreatures( | ||||
| 							(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							ID,owner->getSelection()->ID); | ||||
| 					} | ||||
| 					else //merge | ||||
| 					{ | ||||
| 						LOCPLINT->cb->mergeStacks( | ||||
| 							(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							owner->getSelection()->ID,ID); | ||||
| 					} | ||||
| 				} | ||||
| 				else // Highlight | ||||
| 				{ | ||||
| 					if(creature) | ||||
| 						owner->selectSlot(this); | ||||
| 					redraw(); | ||||
| 					refr = true; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else //highlight or drop artifact | ||||
| 		{ | ||||
| 			bool artSelected = false; | ||||
| 			if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt())) //dirty solution | ||||
| 			{ | ||||
| 				const CArtifactsOfHero::SCommonPart *commonInfo = chw->artSets.front()->commonInfo; | ||||
| 				if (const CArtifactInstance *art = commonInfo->src.art) | ||||
| 				{ | ||||
| 					const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero(); | ||||
| 					artSelected = true; | ||||
| 					ArtifactLocation src(srcHero, commonInfo->src.slotID); | ||||
| 					ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT); | ||||
| 					if (art->canBePutAt(dst, true)) | ||||
| 					{	//equip clicked stack | ||||
| 						if(dst.getArt()) | ||||
| 						{ | ||||
| 							//creature can wear only one active artifact | ||||
| 							//if we are placing a new one, the old one will be returned to the hero's backpack | ||||
| 							LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero))); | ||||
| 						} | ||||
| 						LOCPLINT->cb->swapArtifacts(src, dst); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (!artSelected && creature) | ||||
| 			{ | ||||
| 				owner->selectSlot(this); | ||||
| 				if(creature) | ||||
| 				{ | ||||
| 					for(auto & elem : owner->splitButtons) | ||||
| 						elem->block(false); | ||||
| 				} | ||||
| 			} | ||||
| 			redraw(); | ||||
| 			refr = true; | ||||
| 		} | ||||
| 		if(refr) {hover(false);	hover(true); } //to refresh statusbar | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::update() | ||||
| { | ||||
| 	if (getObj() != nullptr) | ||||
| 	{ | ||||
| 		addUsedEvents(LCLICK | RCLICK | HOVER); | ||||
| 		myStack = getObj()->getStackPtr(ID); | ||||
| 		creature = myStack ? myStack->type : nullptr; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		removeUsedEvents(LCLICK | RCLICK | HOVER); | ||||
| 		myStack = nullptr; | ||||
| 		creature = nullptr; | ||||
| 	} | ||||
|  | ||||
| 	if (creature) | ||||
| 	{ | ||||
| 		creatureImage->enable(); | ||||
| 		creatureImage->setFrame(creature->iconIndex); | ||||
|  | ||||
| 		stackCount->enable(); | ||||
| 		stackCount->setText(boost::lexical_cast<std::string>(myStack->count)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		creatureImage->disable(); | ||||
| 		stackCount->disable(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg, const CStackInstance * Creature): | ||||
|     ID(IID), | ||||
|     owner(Owner), | ||||
|     myStack(Creature), | ||||
|     creature(Creature ? Creature->type : nullptr), | ||||
|     upg(Upg) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| 	if (getObj()) | ||||
| 		addUsedEvents(LCLICK | RCLICK | HOVER); | ||||
| 	pos.x += x; | ||||
| 	pos.y += y; | ||||
|  | ||||
| 	std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT"; | ||||
|  | ||||
| 	creatureImage = new CAnimImage(imgName, creature ? creature->iconIndex : 0); | ||||
| 	if (!creature) | ||||
| 		creatureImage->disable(); | ||||
|  | ||||
| 	selectionImage = new CAnimImage(imgName, 1); | ||||
| 	selectionImage->disable(); | ||||
|  | ||||
| 	if(Owner->smallIcons) | ||||
| 	{ | ||||
| 		pos.w = 32; | ||||
| 		pos.h = 32; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		pos.w = 58; | ||||
| 		pos.h = 64; | ||||
| 	} | ||||
|  | ||||
| 	stackCount = new CLabel(pos.w, pos.h, owner->smallIcons ? FONT_TINY : FONT_MEDIUM, BOTTOMRIGHT, Colors::WHITE); | ||||
| 	if (!creature) | ||||
| 		stackCount->disable(); | ||||
| 	else | ||||
| 		stackCount->setText(boost::lexical_cast<std::string>(myStack->count)); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::addSplitBtn(CAdventureMapButton * button) | ||||
| { | ||||
| 	addChild(button); | ||||
| 	button->recActions = defActions; | ||||
| 	splitButtons.push_back(button); | ||||
| 	button->block(getSelection() == nullptr); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int posY, int distance, int Upg ) | ||||
| { | ||||
| 	ret.resize(7); | ||||
|  | ||||
| 	if (set) | ||||
| 	{ | ||||
| 		for(auto & elem : set->Slots()) | ||||
| 		{ | ||||
| 			ret[elem.first.getNum()] = new CGarrisonSlot(this, posX + (elem.first.getNum()*distance), posY, elem.first, Upg, elem.second); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for(int i=0; i<ret.size(); i++) | ||||
| 		if(!ret[i]) | ||||
| 			ret[i] = new CGarrisonSlot(this, posX + (i*distance), posY, SlotID(i), Upg, nullptr); | ||||
|  | ||||
| 	if (twoRows) | ||||
| 		for (int i=4; i<ret.size(); i++) | ||||
| 		{ | ||||
| 			ret[i]->pos.x -= 126; | ||||
| 			ret[i]->pos.y += 37; | ||||
| 		}; | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::createSlots() | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
|  | ||||
| 	int width = smallIcons? 32 : 58; | ||||
|  | ||||
| 	createSet(slotsUp, armedObjs[0], 0, 0, width+interx, 0); | ||||
| 	createSet(slotsDown, armedObjs[1], garOffset.x, garOffset.y, width+interx, 1); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::recreateSlots() | ||||
| { | ||||
| 	selectSlot(nullptr); | ||||
| 	setSplittingMode(false); | ||||
|  | ||||
| 	for(auto & elem : splitButtons) | ||||
| 		elem->block(true); | ||||
|  | ||||
|  | ||||
| 	for(CGarrisonSlot * slot : slotsUp) | ||||
| 		slot->update(); | ||||
|  | ||||
| 	for(CGarrisonSlot * slot : slotsDown) | ||||
| 		slot->update(); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::splitClick() | ||||
| { | ||||
| 	if(!getSelection()) | ||||
| 		return; | ||||
| 	setSplittingMode(!getSplittingMode()); | ||||
| 	redraw(); | ||||
| } | ||||
| void CGarrisonInt::splitStacks(int, int amountRight) | ||||
| { | ||||
| 	LOCPLINT->cb->splitStack(armedObjs[getSelection()->upg], armedObjs[pb], getSelection()->ID, p2, amountRight); | ||||
| } | ||||
|  | ||||
| CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset, | ||||
|                            SDL_Surface *pomsur, const Point& SurOffset, | ||||
|                            const CArmedInstance *s1, const CArmedInstance *s2, | ||||
|                            bool _removableUnits, bool smallImgs, bool _twoRows ) : | ||||
|     highlighted(nullptr), | ||||
|     inSplittingMode(false), | ||||
|     interx(inx), | ||||
|     garOffset(garsOffset), | ||||
|     smallIcons(smallImgs), | ||||
|     removableUnits(_removableUnits), | ||||
|     twoRows(_twoRows) | ||||
| { | ||||
| 	setArmy(s1, false); | ||||
| 	setArmy(s2, true); | ||||
| 	pos.x += x; | ||||
| 	pos.y += y; | ||||
| 	createSlots(); | ||||
| } | ||||
|  | ||||
| const CGarrisonSlot * CGarrisonInt::getSelection() | ||||
| { | ||||
| 	return highlighted; | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::selectSlot(CGarrisonSlot *slot) | ||||
| { | ||||
| 	if (slot != highlighted) | ||||
| 	{ | ||||
| 		if (highlighted) | ||||
| 			highlighted->setHighlight(false); | ||||
|  | ||||
| 		highlighted = slot; | ||||
| 		for (auto button : splitButtons) | ||||
| 			button->block(highlighted == nullptr); | ||||
|  | ||||
| 		if (highlighted) | ||||
| 			highlighted->setHighlight(true); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::setSplittingMode(bool on) | ||||
| { | ||||
| 	assert(on == false || highlighted != nullptr); //can't be in splitting mode without selection | ||||
|  | ||||
| 	if (inSplittingMode || on) | ||||
| 	{ | ||||
| 		for(CGarrisonSlot * slot : slotsUp) | ||||
| 			slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature))); | ||||
|  | ||||
| 		for(CGarrisonSlot * slot : slotsDown) | ||||
| 			slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature))); | ||||
| 		inSplittingMode = on; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CGarrisonInt::getSplittingMode() | ||||
| { | ||||
| 	return inSplittingMode; | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::setArmy(const CArmedInstance *army, bool bottomGarrison) | ||||
| { | ||||
| 	owned[bottomGarrison] =  army ? (army->tempOwner == LOCPLINT->playerID || army->tempOwner == PlayerColor::UNFLAGGABLE) : false; | ||||
| 	armedObjs[bottomGarrison] = army; | ||||
| } | ||||
|  | ||||
| CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps, const TButtonsInfo &Buttons, bool delComps) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| @@ -3668,48 +3220,6 @@ CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDi | ||||
| 	#endif | ||||
| } | ||||
|  | ||||
| CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits ): | ||||
|     CWindowObject(PLAYER_COLORED, "GARRISON") | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
|  | ||||
| 	garr = new CGarrisonInt(92, 127, 4, Point(0,96), background->bg, Point(93,127), up, down, removableUnits); | ||||
| 	{ | ||||
| 		CAdventureMapButton *split = new CAdventureMapButton(CGI->generaltexth->tcommands[3],"",boost::bind(&CGarrisonInt::splitClick,garr),88,314,"IDV6432.DEF"); | ||||
| 		removeChild(split); | ||||
| 		garr->addSplitBtn(split); | ||||
| 	} | ||||
| 	quit = new CAdventureMapButton(CGI->generaltexth->tcommands[8],"",boost::bind(&CGarrisonWindow::close,this),399,314,"IOK6432.DEF",SDLK_RETURN); | ||||
|  | ||||
| 	std::string titleText; | ||||
| 	if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner) | ||||
| 		titleText = CGI->generaltexth->allTexts[709]; | ||||
| 	else | ||||
| 	{ | ||||
| 		titleText = CGI->generaltexth->allTexts[35]; | ||||
| 		boost::algorithm::replace_first(titleText, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl); | ||||
| 	} | ||||
| 	new CLabel(275, 30, FONT_BIG, CENTER, Colors::YELLOW, titleText); | ||||
|  | ||||
| 	new CAnimImage("CREST58", garr->armedObjs[0]->getOwner().getNum(), 0, 28, 124); | ||||
| 	new CAnimImage("PortraitsLarge", dynamic_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait, 0, 29, 222); | ||||
| } | ||||
|  | ||||
|  | ||||
| IShowActivatable::IShowActivatable() | ||||
| { | ||||
| 	type = 0; | ||||
| } | ||||
|  | ||||
| CGarrisonHolder::CGarrisonHolder() | ||||
| { | ||||
| } | ||||
|  | ||||
| void CWindowWithGarrison::updateGarrisons() | ||||
| { | ||||
| 	garr->recreateSlots(); | ||||
| } | ||||
|  | ||||
| void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState) | ||||
| { | ||||
| 	if((!down) && previousState) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include "../lib/GameConstants.h" | ||||
| #include "gui/CArtifactHolder.h" | ||||
| #include "gui/CComponent.h" | ||||
| #include "gui/CGarrisonInt.h" | ||||
|  | ||||
| #ifdef max | ||||
| #undef max | ||||
| @@ -215,87 +216,6 @@ public: | ||||
| 	CTownTooltip(Point pos, const CGTownInstance * town); | ||||
| }; | ||||
|  | ||||
| /////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| class CGarrisonInt; | ||||
|  | ||||
| /// A single garrison slot which holds one creature of a specific amount | ||||
| class CGarrisonSlot : public CIntObject | ||||
| { | ||||
| 	SlotID ID; //for identification | ||||
| 	CGarrisonInt *owner; | ||||
| 	const CStackInstance *myStack; //nullptr if slot is empty | ||||
| 	const CCreature *creature; | ||||
| 	int upg; //0 - up garrison, 1 - down garrison | ||||
|  | ||||
| 	CAnimImage * creatureImage; | ||||
| 	CAnimImage * selectionImage; // image for selection, not always visible | ||||
| 	CLabel * stackCount; | ||||
|  | ||||
| 	void setHighlight(bool on); | ||||
| public: | ||||
| 	virtual void hover (bool on); //call-in | ||||
| 	const CArmedInstance * getObj() const; | ||||
| 	bool our() const; | ||||
| 	void clickRight(tribool down, bool previousState); | ||||
| 	void clickLeft(tribool down, bool previousState); | ||||
| 	void update(); | ||||
| 	CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg=0, const CStackInstance * Creature=nullptr); | ||||
|  | ||||
| 	friend class CGarrisonInt; | ||||
| }; | ||||
|  | ||||
| /// Class which manages slots of upper and lower garrison, splitting of units | ||||
| class CGarrisonInt :public CIntObject | ||||
| { | ||||
| 	CGarrisonSlot *highlighted; //chosen slot. Should be changed only via selectSlot | ||||
| 	bool inSplittingMode; | ||||
|  | ||||
| public: | ||||
| 	void selectSlot(CGarrisonSlot * slot); //null = deselect | ||||
| 	const CGarrisonSlot * getSelection(); | ||||
|  | ||||
| 	void setSplittingMode(bool on); | ||||
| 	bool getSplittingMode(); | ||||
|  | ||||
| 	int interx; //space between slots | ||||
| 	Point garOffset; //offset between garrisons (not used if only one hero) | ||||
| 	std::vector<CAdventureMapButton *> splitButtons; //may be empty if no buttons | ||||
|  | ||||
| 	SlotID p2; //TODO: comment me | ||||
| 	int	shiftPos;//1st slot of the second row, set shiftPoint for effect | ||||
| 	bool pb, | ||||
| 	     smallIcons, //true - 32x32 imgs, false - 58x64 | ||||
| 	     removableUnits,//player can remove units from up | ||||
| 	     twoRows,//slots will be placed in 2 rows | ||||
| 		 owned[2];//player owns up or down army [0] upper, [1] lower | ||||
|  | ||||
| // 	const CCreatureSet *set1; //top set of creatures | ||||
| // 	const CCreatureSet *set2; //bottom set of creatures | ||||
|  | ||||
| 	std::vector<CGarrisonSlot*> slotsUp, slotsDown; //slots of upper and lower garrison | ||||
| 	const CArmedInstance *armedObjs[2]; //[0] is upper, [1] is down | ||||
| 	//const CArmedInstance *oup, *odown; //upper and lower garrisons (heroes or towns) | ||||
|  | ||||
| 	void setArmy(const CArmedInstance *army, bool bottomGarrison); | ||||
| 	void addSplitBtn(CAdventureMapButton * button); | ||||
| 	void createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int distance, int posY, int Upg ); | ||||
|  | ||||
| 	void createSlots(); | ||||
| 	void recreateSlots(); | ||||
|  | ||||
| 	void splitClick(); //handles click on split button | ||||
| 	void splitStacks(int amountLeft, int amountRight); //TODO: comment me | ||||
| 	//x, y - position; | ||||
| 	//inx - distance between slots; | ||||
| 	//pomsur, SurOffset - UNUSED | ||||
| 	//s1, s2 - top and bottom armies; | ||||
| 	//removableUnits - you can take units from top; | ||||
| 	//smallImgs - units images size 64x58 or 32x32; | ||||
| 	//twoRows - display slots in 2 row (1st row = 4 slots, 2nd = 3 slots) | ||||
| 	CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=nullptr, bool _removableUnits = true, bool smallImgs = false, bool _twoRows=false); //c-tor | ||||
| }; | ||||
|  | ||||
| /// draws picture with creature on background, use Animated=true to get animation | ||||
| class CCreaturePic : public CIntObject | ||||
| { | ||||
| @@ -766,29 +686,6 @@ public: | ||||
| 	LRClickableAreaOpenTown(); | ||||
| }; | ||||
|  | ||||
| class CGarrisonHolder | ||||
| { | ||||
| public: | ||||
| 	CGarrisonHolder(); | ||||
| 	virtual void updateGarrisons()=0; | ||||
| }; | ||||
|  | ||||
| class CWindowWithGarrison : public virtual CGarrisonHolder | ||||
| { | ||||
| public: | ||||
| 	CGarrisonInt *garr; | ||||
| 	virtual void updateGarrisons(); | ||||
| }; | ||||
|  | ||||
| /// Garrison window where you can take creatures out of the hero to place it on the garrison | ||||
| class CGarrisonWindow : public CWindowObject, public CWindowWithGarrison | ||||
| { | ||||
| public: | ||||
| 	CAdventureMapButton * quit; | ||||
|  | ||||
| 	CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor | ||||
| }; | ||||
|  | ||||
| class CExchangeWindow : public CWindowObject, public CWindowWithGarrison, public CWindowWithArtifacts | ||||
| { | ||||
| 	CGStatusBar * ourBar; //internal statusbar | ||||
|   | ||||
							
								
								
									
										501
									
								
								client/gui/CGarrisonInt.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										501
									
								
								client/gui/CGarrisonInt.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,501 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CGarrisonInt.h" | ||||
|  | ||||
| #include "CGuiHandler.h" | ||||
|  | ||||
| #include "../CAnimation.h" | ||||
| #include "../CCreatureWindow.h" | ||||
| #include "../CGameInfo.h" | ||||
| #include "../CPlayerInterface.h" | ||||
|  | ||||
| #include "../../CCallback.h" | ||||
|  | ||||
| #include "../../lib/CGeneralTextHandler.h" | ||||
| #include "../../lib/CCreatureHandler.h" | ||||
| #include "../../lib/mapObjects/CGHeroInstance.h" | ||||
|  | ||||
| #include "../../lib/CGameState.h" | ||||
|  | ||||
| void CGarrisonSlot::setHighlight(bool on) | ||||
| { | ||||
| 	if (on) | ||||
| 		selectionImage->enable(); //show | ||||
| 	else | ||||
| 		selectionImage->disable(); //hide | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::hover (bool on) | ||||
| { | ||||
| 	////Hoverable::hover(on); | ||||
| 	if(on) | ||||
| 	{ | ||||
| 		std::string temp; | ||||
| 		if(creature) | ||||
| 		{ | ||||
| 			if(owner->getSelection()) | ||||
| 			{ | ||||
| 				if(owner->getSelection() == this) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[4]; //View %s | ||||
| 					boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 				} | ||||
| 				else if (owner->getSelection()->creature == creature) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[2]; //Combine %s armies | ||||
| 					boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 				} | ||||
| 				else if (owner->getSelection()->creature) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[7]; //Exchange %s with %s | ||||
| 					boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing); | ||||
| 					boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
|                     logGlobal->warnStream() << "Warning - shouldn't be - highlighted void slot "<<owner->getSelection(); | ||||
|                     logGlobal->warnStream() << "Highlighted set to nullptr"; | ||||
| 					owner->selectSlot(nullptr); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if(upg) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting) | ||||
| 				} | ||||
| 				else if(owner->armedObjs[0] && owner->armedObjs[0]->ID == Obj::TOWN) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison) | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->allTexts[481]; //Select %s | ||||
| 				} | ||||
| 				boost::algorithm::replace_first(temp,"%s",creature->nameSing); | ||||
| 			}; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if(owner->getSelection()) | ||||
| 			{ | ||||
| 				const CArmedInstance *highl = owner->getSelection()->getObj(); | ||||
| 				if(  highl->needsLastStack()		//we are moving stack from hero's | ||||
| 				  && highl->stacksCount() == 1	//it's only stack | ||||
| 				  && owner->getSelection()->upg != upg	//we're moving it to the other garrison | ||||
| 				  ) | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[5]; //Cannot move last army to garrison | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					temp = CGI->generaltexth->tcommands[6]; //Move %s | ||||
| 					boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				temp = CGI->generaltexth->tcommands[11]; //Empty | ||||
| 			} | ||||
| 		} | ||||
| 		GH.statusbar->setText(temp); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		GH.statusbar->clear(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const CArmedInstance * CGarrisonSlot::getObj() const | ||||
| { | ||||
| 	return 	(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]); | ||||
| } | ||||
|  | ||||
| bool CGarrisonSlot::our() const | ||||
| { | ||||
| 	return 	upg?(owner->owned[1]):(owner->owned[0]); | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::clickRight(tribool down, bool previousState) | ||||
| { | ||||
| 	if(down && creature) | ||||
| 	{ | ||||
| 		GH.pushInt(createCreWindow(myStack, CCreatureWindow::ARMY)); | ||||
| 	} | ||||
| } | ||||
| void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
| { | ||||
| 	if(down) | ||||
| 	{ | ||||
| 		bool refr = false; | ||||
| 		if(owner->getSelection()) | ||||
| 		{ | ||||
| 			if(owner->getSelection() == this) //view info | ||||
| 			{ | ||||
| 				UpgradeInfo pom; | ||||
| 				LOCPLINT->cb->getUpgradeInfo(getObj(), ID, pom); | ||||
|  | ||||
| 				bool canUpgrade = getObj()->tempOwner == LOCPLINT->playerID && pom.oldID>=0; //upgrade is possible | ||||
| 				bool canDismiss = getObj()->tempOwner == LOCPLINT->playerID && (getObj()->stacksCount()>1  || !getObj()->needsLastStack()); | ||||
| 				std::function<void()> upgr = nullptr; | ||||
| 				std::function<void()> dism = nullptr; | ||||
| 				if(canUpgrade) upgr = [=] { LOCPLINT->cb->upgradeCreature(getObj(), ID, pom.newID[0]); }; | ||||
| 				if(canDismiss) dism = [=] { LOCPLINT->cb->dismissCreature(getObj(), ID); }; | ||||
|  | ||||
| 				owner->selectSlot(nullptr); | ||||
| 				owner->setSplittingMode(false); | ||||
|  | ||||
| 				for(auto & elem : owner->splitButtons) | ||||
| 					elem->block(true); | ||||
|  | ||||
| 				redraw(); | ||||
| 				refr = true; | ||||
| 				CIntObject *creWindow = createCreWindow(myStack, CCreatureWindow::HERO, upgr, dism, &pom); | ||||
| 				GH.pushInt(creWindow); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				// Only allow certain moves if troops aren't removable or not ours. | ||||
| 				if (  ( owner->getSelection()->our()//our creature is selected | ||||
| 				     || owner->getSelection()->creature == creature )//or we are rebalancing army | ||||
| 				   && ( owner->removableUnits | ||||
| 				     || (upg == 0 &&  ( owner->getSelection()->upg == 1 && !creature ) ) | ||||
| 					 || (upg == 1 &&    owner->getSelection()->upg == 1 ) ) ) | ||||
| 				{ | ||||
| 					//we want to split | ||||
| 					if((owner->getSplittingMode() || LOCPLINT->shiftPressed()) | ||||
| 						&& (!creature | ||||
| 							|| (creature == owner->getSelection()->creature))) | ||||
| 					{ | ||||
| 						owner->p2 = ID; //store the second stack pos | ||||
| 						owner->pb = upg;//store the second stack owner (up or down army) | ||||
| 						owner->setSplittingMode(false); | ||||
|  | ||||
| 						int minLeft=0, minRight=0; | ||||
|  | ||||
| 						if(upg != owner->getSelection()->upg) //not splitting within same army | ||||
| 						{ | ||||
| 							if(owner->getSelection()->getObj()->stacksCount() == 1 //we're splitting away the last stack | ||||
| 								&& owner->getSelection()->getObj()->needsLastStack() ) | ||||
| 							{ | ||||
| 								minLeft = 1; | ||||
| 							} | ||||
| 							if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature | ||||
| 								&& owner->getSelection()->creature == creature | ||||
| 								&& getObj()->needsLastStack() ) | ||||
| 							{ | ||||
| 								minRight = 1; | ||||
| 							} | ||||
| 						} | ||||
|  | ||||
| 						int countLeft = owner->getSelection()->myStack ? owner->getSelection()->myStack->count : 0; | ||||
| 						int countRight = myStack ? myStack->count : 0; | ||||
|  | ||||
| 						GH.pushInt(new CSplitWindow(owner->getSelection()->creature, boost::bind(&CGarrisonInt::splitStacks, owner, _1, _2), | ||||
| 						                            minLeft, minRight, countLeft, countRight)); | ||||
| 						refr = true; | ||||
| 					} | ||||
| 					else if(creature != owner->getSelection()->creature) //swap | ||||
| 					{ | ||||
| 						LOCPLINT->cb->swapCreatures( | ||||
| 							(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							ID,owner->getSelection()->ID); | ||||
| 					} | ||||
| 					else //merge | ||||
| 					{ | ||||
| 						LOCPLINT->cb->mergeStacks( | ||||
| 							(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]), | ||||
| 							owner->getSelection()->ID,ID); | ||||
| 					} | ||||
| 				} | ||||
| 				else // Highlight | ||||
| 				{ | ||||
| 					if(creature) | ||||
| 						owner->selectSlot(this); | ||||
| 					redraw(); | ||||
| 					refr = true; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else //highlight or drop artifact | ||||
| 		{ | ||||
| 			bool artSelected = false; | ||||
| 			if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt())) //dirty solution | ||||
| 			{ | ||||
| 				const CArtifactsOfHero::SCommonPart *commonInfo = chw->artSets.front()->commonInfo; | ||||
| 				if (const CArtifactInstance *art = commonInfo->src.art) | ||||
| 				{ | ||||
| 					const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero(); | ||||
| 					artSelected = true; | ||||
| 					ArtifactLocation src(srcHero, commonInfo->src.slotID); | ||||
| 					ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT); | ||||
| 					if (art->canBePutAt(dst, true)) | ||||
| 					{	//equip clicked stack | ||||
| 						if(dst.getArt()) | ||||
| 						{ | ||||
| 							//creature can wear only one active artifact | ||||
| 							//if we are placing a new one, the old one will be returned to the hero's backpack | ||||
| 							LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero))); | ||||
| 						} | ||||
| 						LOCPLINT->cb->swapArtifacts(src, dst); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (!artSelected && creature) | ||||
| 			{ | ||||
| 				owner->selectSlot(this); | ||||
| 				if(creature) | ||||
| 				{ | ||||
| 					for(auto & elem : owner->splitButtons) | ||||
| 						elem->block(false); | ||||
| 				} | ||||
| 			} | ||||
| 			redraw(); | ||||
| 			refr = true; | ||||
| 		} | ||||
| 		if(refr) {hover(false);	hover(true); } //to refresh statusbar | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGarrisonSlot::update() | ||||
| { | ||||
| 	if (getObj() != nullptr) | ||||
| 	{ | ||||
| 		addUsedEvents(LCLICK | RCLICK | HOVER); | ||||
| 		myStack = getObj()->getStackPtr(ID); | ||||
| 		creature = myStack ? myStack->type : nullptr; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		removeUsedEvents(LCLICK | RCLICK | HOVER); | ||||
| 		myStack = nullptr; | ||||
| 		creature = nullptr; | ||||
| 	} | ||||
|  | ||||
| 	if (creature) | ||||
| 	{ | ||||
| 		creatureImage->enable(); | ||||
| 		creatureImage->setFrame(creature->iconIndex); | ||||
|  | ||||
| 		stackCount->enable(); | ||||
| 		stackCount->setText(boost::lexical_cast<std::string>(myStack->count)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		creatureImage->disable(); | ||||
| 		stackCount->disable(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg, const CStackInstance * Creature): | ||||
|     ID(IID), | ||||
|     owner(Owner), | ||||
|     myStack(Creature), | ||||
|     creature(Creature ? Creature->type : nullptr), | ||||
|     upg(Upg) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| 	if (getObj()) | ||||
| 		addUsedEvents(LCLICK | RCLICK | HOVER); | ||||
| 	pos.x += x; | ||||
| 	pos.y += y; | ||||
|  | ||||
| 	std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT"; | ||||
|  | ||||
| 	creatureImage = new CAnimImage(imgName, creature ? creature->iconIndex : 0); | ||||
| 	if (!creature) | ||||
| 		creatureImage->disable(); | ||||
|  | ||||
| 	selectionImage = new CAnimImage(imgName, 1); | ||||
| 	selectionImage->disable(); | ||||
|  | ||||
| 	if(Owner->smallIcons) | ||||
| 	{ | ||||
| 		pos.w = 32; | ||||
| 		pos.h = 32; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		pos.w = 58; | ||||
| 		pos.h = 64; | ||||
| 	} | ||||
|  | ||||
| 	stackCount = new CLabel(pos.w, pos.h, owner->smallIcons ? FONT_TINY : FONT_MEDIUM, BOTTOMRIGHT, Colors::WHITE); | ||||
| 	if (!creature) | ||||
| 		stackCount->disable(); | ||||
| 	else | ||||
| 		stackCount->setText(boost::lexical_cast<std::string>(myStack->count)); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::addSplitBtn(CAdventureMapButton * button) | ||||
| { | ||||
| 	addChild(button); | ||||
| 	button->recActions = defActions; | ||||
| 	splitButtons.push_back(button); | ||||
| 	button->block(getSelection() == nullptr); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int posY, int distance, int Upg ) | ||||
| { | ||||
| 	ret.resize(7); | ||||
|  | ||||
| 	if (set) | ||||
| 	{ | ||||
| 		for(auto & elem : set->Slots()) | ||||
| 		{ | ||||
| 			ret[elem.first.getNum()] = new CGarrisonSlot(this, posX + (elem.first.getNum()*distance), posY, elem.first, Upg, elem.second); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for(int i=0; i<ret.size(); i++) | ||||
| 		if(!ret[i]) | ||||
| 			ret[i] = new CGarrisonSlot(this, posX + (i*distance), posY, SlotID(i), Upg, nullptr); | ||||
|  | ||||
| 	if (twoRows) | ||||
| 		for (int i=4; i<ret.size(); i++) | ||||
| 		{ | ||||
| 			ret[i]->pos.x -= 126; | ||||
| 			ret[i]->pos.y += 37; | ||||
| 		}; | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::createSlots() | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
|  | ||||
| 	int width = smallIcons? 32 : 58; | ||||
|  | ||||
| 	createSet(slotsUp, armedObjs[0], 0, 0, width+interx, 0); | ||||
| 	createSet(slotsDown, armedObjs[1], garOffset.x, garOffset.y, width+interx, 1); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::recreateSlots() | ||||
| { | ||||
| 	selectSlot(nullptr); | ||||
| 	setSplittingMode(false); | ||||
|  | ||||
| 	for(auto & elem : splitButtons) | ||||
| 		elem->block(true); | ||||
|  | ||||
|  | ||||
| 	for(CGarrisonSlot * slot : slotsUp) | ||||
| 		slot->update(); | ||||
|  | ||||
| 	for(CGarrisonSlot * slot : slotsDown) | ||||
| 		slot->update(); | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::splitClick() | ||||
| { | ||||
| 	if(!getSelection()) | ||||
| 		return; | ||||
| 	setSplittingMode(!getSplittingMode()); | ||||
| 	redraw(); | ||||
| } | ||||
| void CGarrisonInt::splitStacks(int, int amountRight) | ||||
| { | ||||
| 	LOCPLINT->cb->splitStack(armedObjs[getSelection()->upg], armedObjs[pb], getSelection()->ID, p2, amountRight); | ||||
| } | ||||
|  | ||||
| CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset, | ||||
|                            SDL_Surface *pomsur, const Point& SurOffset, | ||||
|                            const CArmedInstance *s1, const CArmedInstance *s2, | ||||
|                            bool _removableUnits, bool smallImgs, bool _twoRows ) : | ||||
|     highlighted(nullptr), | ||||
|     inSplittingMode(false), | ||||
|     interx(inx), | ||||
|     garOffset(garsOffset), | ||||
|     smallIcons(smallImgs), | ||||
|     removableUnits(_removableUnits), | ||||
|     twoRows(_twoRows) | ||||
| { | ||||
| 	setArmy(s1, false); | ||||
| 	setArmy(s2, true); | ||||
| 	pos.x += x; | ||||
| 	pos.y += y; | ||||
| 	createSlots(); | ||||
| } | ||||
|  | ||||
| const CGarrisonSlot * CGarrisonInt::getSelection() | ||||
| { | ||||
| 	return highlighted; | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::selectSlot(CGarrisonSlot *slot) | ||||
| { | ||||
| 	if (slot != highlighted) | ||||
| 	{ | ||||
| 		if (highlighted) | ||||
| 			highlighted->setHighlight(false); | ||||
|  | ||||
| 		highlighted = slot; | ||||
| 		for (auto button : splitButtons) | ||||
| 			button->block(highlighted == nullptr); | ||||
|  | ||||
| 		if (highlighted) | ||||
| 			highlighted->setHighlight(true); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::setSplittingMode(bool on) | ||||
| { | ||||
| 	assert(on == false || highlighted != nullptr); //can't be in splitting mode without selection | ||||
|  | ||||
| 	if (inSplittingMode || on) | ||||
| 	{ | ||||
| 		for(CGarrisonSlot * slot : slotsUp) | ||||
| 			slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature))); | ||||
|  | ||||
| 		for(CGarrisonSlot * slot : slotsDown) | ||||
| 			slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature))); | ||||
| 		inSplittingMode = on; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CGarrisonInt::getSplittingMode() | ||||
| { | ||||
| 	return inSplittingMode; | ||||
| } | ||||
|  | ||||
| void CGarrisonInt::setArmy(const CArmedInstance *army, bool bottomGarrison) | ||||
| { | ||||
| 	owned[bottomGarrison] =  army ? (army->tempOwner == LOCPLINT->playerID || army->tempOwner == PlayerColor::UNFLAGGABLE) : false; | ||||
| 	armedObjs[bottomGarrison] = army; | ||||
| } | ||||
|  | ||||
| CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits ): | ||||
| 	CWindowObject(PLAYER_COLORED, "GARRISON") | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
|  | ||||
| 	garr = new CGarrisonInt(92, 127, 4, Point(0,96), background->bg, Point(93,127), up, down, removableUnits); | ||||
| 	{ | ||||
| 		CAdventureMapButton *split = new CAdventureMapButton(CGI->generaltexth->tcommands[3],"",boost::bind(&CGarrisonInt::splitClick,garr),88,314,"IDV6432.DEF"); | ||||
| 		removeChild(split); | ||||
| 		garr->addSplitBtn(split); | ||||
| 	} | ||||
| 	quit = new CAdventureMapButton(CGI->generaltexth->tcommands[8],"",boost::bind(&CGarrisonWindow::close,this),399,314,"IOK6432.DEF",SDLK_RETURN); | ||||
|  | ||||
| 	std::string titleText; | ||||
| 	if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner) | ||||
| 		titleText = CGI->generaltexth->allTexts[709]; | ||||
| 	else | ||||
| 	{ | ||||
| 		titleText = CGI->generaltexth->allTexts[35]; | ||||
| 		boost::algorithm::replace_first(titleText, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl); | ||||
| 	} | ||||
| 	new CLabel(275, 30, FONT_BIG, CENTER, Colors::YELLOW, titleText); | ||||
|  | ||||
| 	new CAnimImage("CREST58", garr->armedObjs[0]->getOwner().getNum(), 0, 28, 124); | ||||
| 	new CAnimImage("PortraitsLarge", dynamic_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait, 0, 29, 222); | ||||
| } | ||||
|  | ||||
| CGarrisonHolder::CGarrisonHolder() | ||||
| { | ||||
| } | ||||
|  | ||||
| void CWindowWithGarrison::updateGarrisons() | ||||
| { | ||||
| 	garr->recreateSlots(); | ||||
| } | ||||
							
								
								
									
										123
									
								
								client/gui/CGarrisonInt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								client/gui/CGarrisonInt.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CIntObject.h" | ||||
| #include "CIntObjectClasses.h" | ||||
|  | ||||
| /* | ||||
|  * CGarrisonInt.h, part of VCMI engine | ||||
|  * | ||||
|  * Authors: listed in file AUTHORS in main folder | ||||
|  * | ||||
|  * License: GNU General Public License v2.0 or later | ||||
|  * Full text of license available in license.txt file, in main folder | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class CGarrisonInt; | ||||
| class CAdventureMapButton; | ||||
| class CArmedInstance; | ||||
| class CAnimImage; | ||||
| class CCreatureSet; | ||||
| class CGarrisonSlot; | ||||
| class CStackInstance; | ||||
| class CLabel; | ||||
|  | ||||
| /// A single garrison slot which holds one creature of a specific amount | ||||
| class CGarrisonSlot : public CIntObject | ||||
| { | ||||
| 	SlotID ID; //for identification | ||||
| 	CGarrisonInt *owner; | ||||
| 	const CStackInstance *myStack; //nullptr if slot is empty | ||||
| 	const CCreature *creature; | ||||
| 	int upg; //0 - up garrison, 1 - down garrison | ||||
|  | ||||
| 	CAnimImage * creatureImage; | ||||
| 	CAnimImage * selectionImage; // image for selection, not always visible | ||||
| 	CLabel * stackCount; | ||||
|  | ||||
| 	void setHighlight(bool on); | ||||
| public: | ||||
| 	virtual void hover (bool on); //call-in | ||||
| 	const CArmedInstance * getObj() const; | ||||
| 	bool our() const; | ||||
| 	void clickRight(tribool down, bool previousState); | ||||
| 	void clickLeft(tribool down, bool previousState); | ||||
| 	void update(); | ||||
| 	CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg=0, const CStackInstance * Creature=nullptr); | ||||
|  | ||||
| 	friend class CGarrisonInt; | ||||
| }; | ||||
|  | ||||
| /// Class which manages slots of upper and lower garrison, splitting of units | ||||
| class CGarrisonInt :public CIntObject | ||||
| { | ||||
| 	CGarrisonSlot *highlighted; //chosen slot. Should be changed only via selectSlot | ||||
| 	bool inSplittingMode; | ||||
|  | ||||
| public: | ||||
| 	void selectSlot(CGarrisonSlot * slot); //null = deselect | ||||
| 	const CGarrisonSlot * getSelection(); | ||||
|  | ||||
| 	void setSplittingMode(bool on); | ||||
| 	bool getSplittingMode(); | ||||
|  | ||||
| 	int interx; //space between slots | ||||
| 	Point garOffset; //offset between garrisons (not used if only one hero) | ||||
| 	std::vector<CAdventureMapButton *> splitButtons; //may be empty if no buttons | ||||
|  | ||||
| 	SlotID p2; //TODO: comment me | ||||
| 	int	shiftPos;//1st slot of the second row, set shiftPoint for effect | ||||
| 	bool pb, | ||||
| 		 smallIcons, //true - 32x32 imgs, false - 58x64 | ||||
| 		 removableUnits,//player can remove units from up | ||||
| 		 twoRows,//slots will be placed in 2 rows | ||||
| 		 owned[2];//player owns up or down army [0] upper, [1] lower | ||||
|  | ||||
| // 	const CCreatureSet *set1; //top set of creatures | ||||
| // 	const CCreatureSet *set2; //bottom set of creatures | ||||
|  | ||||
| 	std::vector<CGarrisonSlot*> slotsUp, slotsDown; //slots of upper and lower garrison | ||||
| 	const CArmedInstance *armedObjs[2]; //[0] is upper, [1] is down | ||||
| 	//const CArmedInstance *oup, *odown; //upper and lower garrisons (heroes or towns) | ||||
|  | ||||
| 	void setArmy(const CArmedInstance *army, bool bottomGarrison); | ||||
| 	void addSplitBtn(CAdventureMapButton * button); | ||||
| 	void createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int distance, int posY, int Upg ); | ||||
|  | ||||
| 	void createSlots(); | ||||
| 	void recreateSlots(); | ||||
|  | ||||
| 	void splitClick(); //handles click on split button | ||||
| 	void splitStacks(int amountLeft, int amountRight); //TODO: comment me | ||||
| 	//x, y - position; | ||||
| 	//inx - distance between slots; | ||||
| 	//pomsur, SurOffset - UNUSED | ||||
| 	//s1, s2 - top and bottom armies; | ||||
| 	//removableUnits - you can take units from top; | ||||
| 	//smallImgs - units images size 64x58 or 32x32; | ||||
| 	//twoRows - display slots in 2 row (1st row = 4 slots, 2nd = 3 slots) | ||||
| 	CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=nullptr, bool _removableUnits = true, bool smallImgs = false, bool _twoRows=false); //c-tor | ||||
| }; | ||||
|  | ||||
| class CGarrisonHolder | ||||
| { | ||||
| public: | ||||
| 	CGarrisonHolder(); | ||||
| 	virtual void updateGarrisons()=0; | ||||
| }; | ||||
|  | ||||
| class CWindowWithGarrison : public virtual CGarrisonHolder | ||||
| { | ||||
| public: | ||||
| 	CGarrisonInt *garr; | ||||
| 	virtual void updateGarrisons(); | ||||
| }; | ||||
|  | ||||
| /// Garrison window where you can take creatures out of the hero to place it on the garrison | ||||
| class CGarrisonWindow : public CWindowObject, public CWindowWithGarrison | ||||
| { | ||||
| public: | ||||
| 	CAdventureMapButton * quit; | ||||
|  | ||||
| 	CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor | ||||
| }; | ||||
| @@ -4,6 +4,11 @@ | ||||
| #include "SDL_Extensions.h" | ||||
| #include "../CMessage.h" | ||||
|  | ||||
| IShowActivatable::IShowActivatable() | ||||
| { | ||||
| 	type = 0; | ||||
| } | ||||
|  | ||||
| void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb) | ||||
| { | ||||
| 	boost::unique_lock<boost::recursive_mutex> lock(updateGuard);	 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user