mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Stacks #3 -> towards new system of stack operations.
This commit is contained in:
		| @@ -113,10 +113,14 @@ public: | ||||
| 	void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove) {}; | ||||
| 	void takeCreatures (int objid, TSlots creatures){}; | ||||
| 	void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures){}; | ||||
| 	void changeStackType(const StackLocation &sl, CCreature *c){}; | ||||
| 	void changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false){}; | ||||
| 	void insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count){}; | ||||
| 	void eraseStack(const StackLocation &sl){}; | ||||
| 	bool changeStackType(const StackLocation &sl, CCreature *c){return false;}; | ||||
| 	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false){return false;}; | ||||
| 	bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count){return false;}; | ||||
| 	bool eraseStack(const StackLocation &sl){return false;}; | ||||
| 	bool swapStacks(const StackLocation &sl1, const StackLocation &sl2){return false;} | ||||
| 	bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count){return false;} | ||||
| 	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished){} | ||||
| 	bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1){return false;} | ||||
| 	void showCompInfo(ShowInInfobox * comp){}; | ||||
| 	void heroVisitCastle(int obj, int heroID){}; | ||||
| 	void stopHeroVisitCastle(int obj, int heroID){}; | ||||
|   | ||||
| @@ -122,6 +122,40 @@ void SetAvailableHeroes::applyCl( CClient *cl ) | ||||
| 	//TODO: inform interface? | ||||
| } | ||||
|  | ||||
| void ChangeStackCount::applyCl( CClient *cl ) | ||||
| { | ||||
| 	INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army); | ||||
| } | ||||
|  | ||||
| void SetStackType::applyCl( CClient *cl ) | ||||
| { | ||||
| 	INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army); | ||||
| } | ||||
|  | ||||
| void EraseStack::applyCl( CClient *cl ) | ||||
| { | ||||
| 	INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army); | ||||
| } | ||||
|  | ||||
| void SwapStacks::applyCl( CClient *cl ) | ||||
| { | ||||
| 	INTERFACE_CALL_IF_PRESENT(sl1.army->tempOwner,garrisonChanged,sl1.army); | ||||
| 	if(sl1.army != sl2.army) | ||||
| 		INTERFACE_CALL_IF_PRESENT(sl2.army->tempOwner,garrisonChanged,sl2.army); | ||||
| } | ||||
|  | ||||
| void InsertNewStack::applyCl( CClient *cl ) | ||||
| { | ||||
| 	INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,garrisonChanged,sl.army); | ||||
| } | ||||
|  | ||||
| void RebalanceStacks::applyCl( CClient *cl ) | ||||
| { | ||||
| 	INTERFACE_CALL_IF_PRESENT(src.army->tempOwner,garrisonChanged,src.army); | ||||
| 	if(src.army != dst.army) | ||||
| 		INTERFACE_CALL_IF_PRESENT(dst.army->tempOwner,garrisonChanged,dst.army); | ||||
| } | ||||
|  | ||||
| void GiveBonus::applyCl( CClient *cl ) | ||||
| { | ||||
| 	switch(who) | ||||
|   | ||||
| @@ -139,6 +139,11 @@ bool CCreature::isMyUpgrade(const CCreature *anotherCre) const | ||||
| 	return vstd::contains(upgrades, anotherCre->idNumber); | ||||
| } | ||||
|  | ||||
| bool CCreature::valid() const | ||||
| { | ||||
| 	return this == VLC->creh->creatures[idNumber]; | ||||
| } | ||||
|  | ||||
| int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo() | ||||
| { | ||||
| 	befi=i; | ||||
|   | ||||
| @@ -61,6 +61,8 @@ public: | ||||
| 	static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion | ||||
| 	bool isMyUpgrade(const CCreature *anotherCre) const; | ||||
|  | ||||
| 	bool valid() const; | ||||
|  | ||||
| 	void addBonus(int val, int type, int subtype = -1); | ||||
| 	//void getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const; | ||||
|  | ||||
|   | ||||
| @@ -1766,10 +1766,11 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) co | ||||
|  | ||||
| 	int crid = creatures[0].second[0]; | ||||
| 	CCreature *crs = VLC->creh->creatures[crid]; | ||||
| 	TQuantity count = creatures[0].first; | ||||
|  | ||||
| 	if(crs->level == 1  &&  ID != 78) //first level - creatures are for free | ||||
| 	{ | ||||
| 		if(creatures[0].first) //there are available creatures | ||||
| 		if(count) //there are available creatures | ||||
| 		{ | ||||
| 			int slot = h->getSlotFor(crid); | ||||
| 			if(slot < 0) //no available slot | ||||
| @@ -1787,19 +1788,16 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) co | ||||
| 				sac.creatures = creatures; | ||||
| 				sac.creatures[0].first = 0; | ||||
|  | ||||
| 				SetGarrisons sg; | ||||
| 				sg.garrs[h->id] = *h; | ||||
| 				sg.garrs[h->id].addToSlot(slot, crid, creatures[0].first); | ||||
|  | ||||
| 				InfoWindow iw; | ||||
| 				iw.player = h->tempOwner; | ||||
| 				iw.text.addTxt(MetaString::GENERAL_TXT, 423); //%d %s join your army. | ||||
| 				iw.text.addReplacement(creatures[0].first); | ||||
| 				iw.text.addReplacement(count); | ||||
| 				iw.text.addReplacement(MetaString::CRE_PL_NAMES, crid); | ||||
|  | ||||
| 				cb->showInfoDialog(&iw); | ||||
| 				cb->sendAndApply(&sac); | ||||
| 				cb->sendAndApply(&sg); | ||||
| 				cb->addToSlot(StackLocation(h, slot), crs, count); | ||||
| 			} | ||||
| 		} | ||||
| 		else //there no creatures | ||||
| @@ -3102,20 +3100,21 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co | ||||
| 		if(cost) | ||||
| 			cb->giveResource(h->tempOwner,6,-cost); | ||||
|  | ||||
| 		int slot = h->getSlotFor(subID); | ||||
| 		if(slot >= 0) //there is place | ||||
| 		{ | ||||
| 			//add creatures | ||||
| 			SetGarrisons sg; | ||||
| 			sg.garrs[h->id] = h->getArmy(); | ||||
| 			sg.garrs[h->id].addToSlot(slot, subID, getStackCount(0)); | ||||
| 			cb->sendAndApply(&sg); | ||||
| 			cb->removeObject(id); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends | ||||
| 		} | ||||
| 		cb->tryJoiningArmy(this, h, true); | ||||
| // 		int slot = h->getSlotFor(subID); | ||||
| // 		if(slot >= 0) //there is place | ||||
| // 		{ | ||||
| // 			//add creatures | ||||
| // 			SetGarrisons sg; | ||||
| // 			sg.garrs[h->id] = h->getArmy(); | ||||
| // 			sg.garrs[h->id].addToSlot(slot, subID, getStackCount(0)); | ||||
| // 			cb->sendAndApply(&sg); | ||||
| // 			cb->removeObject(id); | ||||
| // 		} | ||||
| // 		else | ||||
| // 		{ | ||||
| // 			cb->showGarrisonDialog(id,h->id,true,boost::bind(&IGameCallback::removeObject,cb,id)); //show garrison window and remove ourselves from map when player ends | ||||
| // 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -6158,14 +6157,13 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 	{ | ||||
| 		giveDummyBonus(h->id, Bonus::ONE_BATTLE); | ||||
| 		int xp = 0; | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[h->id] = h->getArmy(); | ||||
|  | ||||
| 		for (TSlots::const_iterator i = h->Slots().begin(); i != h->Slots().end(); i++) | ||||
| 		{ | ||||
| 			int drown = (int)(i->second->count * 0.3); | ||||
| 			TQuantity drown = i->second->count * 0.3; | ||||
| 			if(drown) | ||||
| 			{ | ||||
| 				sg.garrs[h->id].setStackCount(i->first, i->second->count - drown); | ||||
| 				cb->changeStackCount(StackLocation(h, i->first), -drown); | ||||
| 				xp += drown * i->second->type->valOfBonuses(Bonus::STACK_HEALTH); | ||||
| 			} | ||||
| 		} | ||||
| @@ -6174,7 +6172,6 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 		{ | ||||
| 			iw.text.addTxt(11,132); | ||||
| 			iw.text.addReplacement(xp); | ||||
| 			cb->sendAndApply(&sg); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| @@ -6182,6 +6179,8 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 		} | ||||
| 	} | ||||
| 	cb->showInfoDialog(&iw); | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| 	///TODO: WHAT WITH EXP?  | ||||
| } | ||||
|  | ||||
| //bool IShipyard::validLocation() const | ||||
|   | ||||
| @@ -49,9 +49,16 @@ bool CCreatureSet::setCreature(TSlot slot, TCreature type, TQuantity quantity) / | ||||
|  | ||||
| TSlot CCreatureSet::getSlotFor(TCreature creature, ui32 slotsAmount/*=7*/) const /*returns -1 if no slot available */ | ||||
| { | ||||
| 	return getSlotFor(VLC->creh->creatures[creature], slotsAmount); | ||||
| } | ||||
|  | ||||
| TSlot CCreatureSet::getSlotFor(const CCreature *c, ui32 slotsAmount/*=ARMY_SIZE*/) const | ||||
| { | ||||
| 	assert(c->valid()); | ||||
| 	for(TSlots::const_iterator i=slots.begin(); i!=slots.end(); ++i) | ||||
| 	{ | ||||
| 		if(i->second->type->idNumber == creature) | ||||
| 		assert(i->second->type->valid()); | ||||
| 		if(i->second->type == c) | ||||
| 		{ | ||||
| 			return i->first; //if there is already such creature we return its slot id | ||||
| 		} | ||||
| @@ -317,6 +324,7 @@ CStackInstance * CCreatureSet::detachStack(TSlot slot) | ||||
| 	if(CArmedInstance *armedObj = castToArmyObj()) | ||||
| 		ret->detachFrom(armedObj); | ||||
|  | ||||
| 	slots.erase(slot); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @@ -327,6 +335,24 @@ void CCreatureSet::setStackType(TSlot slot, const CCreature *type) | ||||
| 	s->setType(type->idNumber); | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs) const | ||||
| { | ||||
| 	std::set<const CCreature*> cres; | ||||
|  | ||||
| 	//get types of creatures that need their own slot | ||||
| 	for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++) | ||||
| 		cres.insert(i->second->type); | ||||
| 	for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++) | ||||
| 		cres.insert(i->second->type); | ||||
|  | ||||
| 	return cres.size() <= ARMY_SIZE; | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::hasStackAtSlot(TSlot slot) const | ||||
| { | ||||
| 	return vstd::contains(slots, slot); | ||||
| } | ||||
|  | ||||
| CStackInstance::CStackInstance() | ||||
| 	: armyObj(_armyObj) | ||||
| { | ||||
|   | ||||
| @@ -106,6 +106,7 @@ public: | ||||
| 	int getStackCount (TSlot slot) const; | ||||
| 	TSlot findStack(const CStackInstance *stack) const; //-1 if none | ||||
| 	TSlot getSlotFor(TCreature creature, ui32 slotsAmount=ARMY_SIZE) const; //returns -1 if no slot available | ||||
| 	TSlot getSlotFor(const CCreature *c, ui32 slotsAmount=ARMY_SIZE) const; //returns -1 if no slot available | ||||
| 	bool mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable = -1) const; //looks for two same stacks, returns slot positions; | ||||
| 	bool validTypes(bool allowUnrandomized = false) const; //checks if all types of creatures are set properly | ||||
| 	bool slotEmpty(TSlot slot) const; | ||||
| @@ -114,9 +115,10 @@ public: | ||||
| 	int getArmyStrength() const; //sum of AI values of creatures | ||||
| 	ui64 getPower (TSlot slot) const; //value of specific stack | ||||
| 	std::string getRoughAmount (TSlot slot) const; //rough size of specific stack | ||||
| 	bool hasStackAtSlot(TSlot slot) const; | ||||
| 	 | ||||
| 	bool contains(const CStackInstance *stack) const; | ||||
|  | ||||
| 	bool canBeMergedWith(const CCreatureSet &cs) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -90,10 +90,14 @@ public: | ||||
| 	virtual void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove) =0; | ||||
| 	virtual void takeCreatures (int objid, TSlots creatures) =0; | ||||
| 	virtual void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) =0; | ||||
| 	virtual void changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0; | ||||
| 	virtual void changeStackType(const StackLocation &sl, CCreature *c) =0; | ||||
| 	virtual void insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count) =0; | ||||
| 	virtual void eraseStack(const StackLocation &sl) =0; | ||||
| 	virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0; | ||||
| 	virtual bool changeStackType(const StackLocation &sl, CCreature *c) =0; | ||||
| 	virtual bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) =0; //count -1 => moves whole stack | ||||
| 	virtual bool eraseStack(const StackLocation &sl) =0; | ||||
| 	virtual bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) =0; | ||||
| 	virtual bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) =0; //makes new stack or increases count of already existing | ||||
| 	virtual void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished) =0; //merges army from src do dst or opens a garrison window | ||||
| 	virtual bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count) = 0; | ||||
| 	virtual void showCompInfo(ShowInInfobox * comp)=0; | ||||
| 	virtual void heroVisitCastle(int obj, int heroID)=0; | ||||
| 	virtual void stopHeroVisitCastle(int obj, int heroID)=0; | ||||
|   | ||||
| @@ -736,12 +736,17 @@ struct StackLocation | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct ChangeStackCount : CPackForClient  //521 | ||||
| struct CGarrisonOperationPack : CPackForClient | ||||
| { | ||||
| }; | ||||
|  | ||||
| struct ChangeStackCount : CGarrisonOperationPack  //521 | ||||
| { | ||||
| 	StackLocation sl; | ||||
| 	TQuantity count; | ||||
| 	ui8 absoluteValue; //if not -> count will be added (or subtracted if negative) | ||||
|  | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -750,11 +755,12 @@ struct ChangeStackCount : CPackForClient  //521 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct SetStackType : CPackForClient  //522 | ||||
| struct SetStackType : CGarrisonOperationPack  //522 | ||||
| { | ||||
| 	StackLocation sl; | ||||
| 	CCreature *type; | ||||
|  | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -763,10 +769,11 @@ struct SetStackType : CPackForClient  //522 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct EraseStack : CPackForClient  //523 | ||||
| struct EraseStack : CGarrisonOperationPack  //523 | ||||
| { | ||||
| 	StackLocation sl; | ||||
|  | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -775,10 +782,11 @@ struct EraseStack : CPackForClient  //523 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct SwapStacks : CPackForClient  //524 | ||||
| struct SwapStacks : CGarrisonOperationPack  //524 | ||||
| { | ||||
| 	StackLocation sl1, sl2; | ||||
|  | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -787,11 +795,12 @@ struct SwapStacks : CPackForClient  //524 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct InsertNewStack : CPackForClient  //525 | ||||
| struct InsertNewStack : CGarrisonOperationPack //525 | ||||
| { | ||||
| 	StackLocation sl; | ||||
| 	CStackInstance *stack; | ||||
|  | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -801,11 +810,12 @@ struct InsertNewStack : CPackForClient  //525 | ||||
| }; | ||||
|  | ||||
| //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks | ||||
| struct RebalanceStacks : CPackForClient  //525 | ||||
| struct RebalanceStacks : CGarrisonOperationPack  //525 | ||||
| { | ||||
| 	StackLocation src, dst; | ||||
| 	TQuantity count; | ||||
|  | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
|   | ||||
| @@ -625,7 +625,11 @@ DLL_EXPORT void EraseStack::applyGs( CGameState *gs ) | ||||
|  | ||||
| DLL_EXPORT void SwapStacks::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	CStackInstance *s1 = sl1.army->detachStack(sl1.slot), | ||||
| 		*s2 = sl2.army->detachStack(sl2.slot); | ||||
|  | ||||
| 	sl2.army->putStack(sl2.slot, s1); | ||||
| 	sl1.army->putStack(sl1.slot, s2); | ||||
| } | ||||
|  | ||||
| DLL_EXPORT void InsertNewStack::applyGs( CGameState *gs ) | ||||
|   | ||||
| @@ -640,20 +640,13 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer | ||||
| 		// Give raised units to winner and show dialog, if any were raised. | ||||
| 		if (raisedStack.type)  | ||||
| 		{ | ||||
| 			int slot = winnerHero->getSlotFor(raisedStack.type->idNumber); | ||||
| 			TSlot slot = winnerHero->getSlotFor(raisedStack.type); | ||||
|  | ||||
| 			if (slot != -1)  | ||||
| 			{ | ||||
| 				SetGarrisons sg; | ||||
| 				sg.garrs[winnerHero->id] = winnerHero->getArmy(); | ||||
| 				sg.garrs[winnerHero->id].addToSlot(slot, raisedStack.type->idNumber, raisedStack.count); | ||||
|  | ||||
| // 				if (vstd::contains(winnerHero->slots, slot)) // Add to existing stack. | ||||
| // 					sg.garrs[winnerHero->id].slots[slot]->count += raisedStack.count; | ||||
| // 				else // Create a new stack. | ||||
| // 					sg.garrs[winnerHero->id].slots[slot]->= raisedStack; | ||||
| 				winnerHero->showNecromancyDialog(raisedStack); | ||||
| 				sendAndApply(&sg); | ||||
| 				addToSlot(StackLocation(winnerHero, slot), raisedStack.type, raisedStack.count); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -926,6 +919,7 @@ int CGameHandler::moveStack(int stack, int dest) | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| CGameHandler::CGameHandler(void) | ||||
| { | ||||
| 	QID = 1; | ||||
| @@ -2624,8 +2618,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| { | ||||
| 	CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id1]), | ||||
| 		*s2 = static_cast<CArmedInstance*>(gs->map->objects[id2]); | ||||
| 	CCreatureSet temp1 = s1->getArmy(), temp2 = s2->getArmy(), | ||||
| 		&S1 = temp1, &S2 = (s1!=s2)?(temp2):(temp1); | ||||
| 	CCreatureSet &S1 = *s1, &S2 = *s2; | ||||
| 	StackLocation sl1(s1, p1), sl2(s2, p2); | ||||
|  | ||||
| 	if(!isAllowedExchange(id1,id2)) | ||||
| 	{ | ||||
| @@ -2641,14 +2635,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| 			complain("Can't take troops from another player!"); | ||||
| 			return false; | ||||
| 		} | ||||
| 		 | ||||
| 		std::swap(S1.slots[p1], S2.slots[p2]); //swap slots | ||||
|  | ||||
| 		//if one of them is empty, remove entry | ||||
| 		if(!S1.slots[p1]->count) | ||||
| 			S1.slots.erase(p1); | ||||
| 		if(!S2.slots[p2]->count) | ||||
| 			S2.slots.erase(p2); | ||||
| 		swapStacks(sl1, sl2); | ||||
| 	} | ||||
| 	else if(what==2)//merge | ||||
| 	{ | ||||
| @@ -2656,11 +2644,17 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| 		|| ((s1->tempOwner != player && s1->tempOwner != 254) && S2.slots[p2]->count) && complain("Can't take troops from another player!")) | ||||
| 			return false;  | ||||
|  | ||||
| 		S2.slots[p2]->count += S1.slots[p1]->count; | ||||
| 		S1.slots.erase(p1); | ||||
| 		moveStack(sl1, sl2); | ||||
| 	} | ||||
| 	else if(what==3) //split | ||||
| 	{ | ||||
| 		if ( (s1->tempOwner != player && S1.slots[p1]->count < s1->getArmy().getStackCount(p1) ) | ||||
| 			|| (s2->tempOwner != player && S2.slots[p2]->count < s2->getArmy().getStackCount(p2) ) ) | ||||
| 		{ | ||||
| 			complain("Can't move troops of another player!"); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		//general conditions checking | ||||
| 		if((!vstd::contains(S1.slots,p1) && complain("no creatures to split")) | ||||
| 			|| (val<1  && complain("no creatures to split"))  ) | ||||
| @@ -2679,8 +2673,9 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| 				return false;  | ||||
| 			} | ||||
| 			 | ||||
| 			S2.slots[p2]->count = val; | ||||
| 			S1.slots[p1]->count = total - val; | ||||
| 			moveStack(sl1, sl2, val - S2.slots[p2]->count); | ||||
| 			//S2.slots[p2]->count = val; | ||||
| 			//S1.slots[p1]->count = total - val; | ||||
| 		} | ||||
| 		else //split one stack to the two | ||||
| 		{ | ||||
| @@ -2689,35 +2684,12 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| 				complain("Cannot split that stack, not enough creatures!"); | ||||
| 				return false;  | ||||
| 			} | ||||
| 			S2.slots[p2]->type = S1.slots[p1]->type; | ||||
| 			S2.slots[p2]->count = val; | ||||
| 			S1.slots[p1]->count -= val; | ||||
|  | ||||
|  | ||||
| 			moveStack(sl1, sl2, val); | ||||
| 		} | ||||
|  | ||||
| 		if ( (s1->tempOwner != player && S1.slots[p1]->count < s1->getArmy().getStackCount(p1) ) | ||||
| 		  || (s2->tempOwner != player && S2.slots[p2]->count < s2->getArmy().getStackCount(p2) ) ) | ||||
| 		{ | ||||
| 			complain("Can't move troops of another player!"); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		if(!S1.slots[p1]->count) //if we've moved all creatures | ||||
| 			S1.slots.erase(p1); | ||||
| 	} | ||||
| 	if((s1->needsLastStack() && !S1.stacksCount()) //it's not allowed to take last stack from hero army! | ||||
| 		|| (s2->needsLastStack() && !S2.stacksCount()) | ||||
| 	) | ||||
| 	{ | ||||
| 		complain("Cannot take the last stack!"); | ||||
| 		return false; //leave without applying changes to garrison | ||||
| 	} | ||||
|  | ||||
| 	//apply changes | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[id1] = S1; | ||||
| 	if(s1 != s2) | ||||
| 		sg.garrs[id2] = S2; | ||||
| 	sendAndApply(&sg); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -2753,10 +2725,8 @@ bool CGameHandler::disbandCreature( si32 id, ui8 pos ) | ||||
| 		complain("Illegal call to disbandCreature - no such stack in army!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	s1->slots.erase(pos); | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[id] = s1->getArmy(); | ||||
| 	sendAndApply(&sg); | ||||
|  | ||||
| 	eraseStack(StackLocation(s1, pos)); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -2983,10 +2953,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram, si32 from | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[dst->id] = dst->getArmy(); | ||||
| 		sg.garrs[dst->id] .addToSlot(slot, crid, cram); | ||||
| 		sendAndApply(&sg); | ||||
| 		addToSlot(StackLocation(dst, slot), c, cram); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
| @@ -2994,6 +2961,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram, si32 from | ||||
| bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) | ||||
| { | ||||
| 	CArmedInstance *obj = static_cast<CArmedInstance*>(gs->map->objects[objid]); | ||||
| 	assert(obj->hasStackAtSlot(pos)); | ||||
| 	UpgradeInfo ui = gs->getUpgradeInfo(obj->getStack(pos)); | ||||
| 	int player = obj->tempOwner; | ||||
| 	int crQuantity = obj->slots[pos]->count; | ||||
| @@ -3027,21 +2995,20 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) | ||||
| 	} | ||||
| 	 | ||||
| 	//upgrade creature | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[objid] = obj->getArmy(); | ||||
| 	sg.garrs[objid].slots[pos]->setType(upgID); | ||||
| 	sendAndApply(&sg);	 | ||||
| 	changeStackType(StackLocation(obj, pos), VLC->creh->creatures[upgID]); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::changeStackType(const StackLocation &sl, CCreature *c) | ||||
| bool CGameHandler::changeStackType(const StackLocation &sl, CCreature *c) | ||||
| { | ||||
| 	assert(sl.army->getCreature(sl.slot)); | ||||
| 	if(!sl.army->hasStackAtSlot(sl.slot)) | ||||
| 		COMPLAIN_RET("Cannot find a stack to change type"); | ||||
|  | ||||
| 	SetStackType sst; | ||||
| 	sst.sl = sl; | ||||
| 	sst.type = c; | ||||
| 	sendAndApply(&sst);	 | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| @@ -3049,42 +3016,43 @@ bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| 	CGTownInstance *town = gs->getTown(tid); | ||||
| 	if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies: town army => hero army | ||||
| 	{ | ||||
| 		CCreatureSet csn = town->visitingHero->getArmy(), cso = town->getArmy(); | ||||
|  | ||||
| 		if(!town->visitingHero->canBeMergedWith(*town)) | ||||
| 		{ | ||||
| 			complain("Cannot make garrison swap, not enough free slots!"); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		const CCreatureSet &cso = *town; | ||||
| 		const CCreatureSet &csn = *town->visitingHero; | ||||
|  | ||||
| 		while(!cso.slots.empty())//while there are unmoved creatures | ||||
| 		{ | ||||
| 			int pos = csn.getSlotFor(cso.slots.begin()->second->type->idNumber); | ||||
| 			if(pos<0) | ||||
| 			TSlots::const_iterator i = cso.slots.begin(); //iterator to stack to move | ||||
| 			StackLocation sl(town, i->first); //location of stack to move | ||||
|  | ||||
| 			TSlot pos = csn.getSlotFor(i->second->type); | ||||
| 			if(pos < 0) | ||||
| 			{ | ||||
| 				//try to merge two other stacks to make place | ||||
| 				std::pair<TSlot, TSlot> toMerge; | ||||
| 				if(csn.mergableStacks(toMerge, cso.slots.begin()->first)) | ||||
| 				if(csn.mergableStacks(toMerge, i->first)) | ||||
| 				{ | ||||
| 					//merge | ||||
| 					csn.slots[toMerge.second]->count += csn.slots[toMerge.first]->count; | ||||
| 					csn.slots[toMerge.first] = cso.slots.begin()->second; | ||||
| 					moveStack(StackLocation(town->visitingHero, toMerge.first), StackLocation(town->visitingHero, toMerge.second)); //merge toMerge.first into toMerge.second | ||||
| 					moveStack(sl, StackLocation(town->visitingHero, toMerge.first)); //move stack to freed slot | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					complain("Cannot make garrison swap, not enough free slots!"); | ||||
| 					complain("Unexpected failure during an attempt to merge town and visiting hero armies!"); | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			else if(csn.slots.find(pos) != csn.slots.end()) //add creatures to the existing stack | ||||
| 			else | ||||
| 			{ | ||||
| 				csn.slots[pos]->count += cso.slots.begin()->second->count; | ||||
| 				moveStack(sl, StackLocation(town->visitingHero, pos)); | ||||
| 			} | ||||
| 			else //move stack on the free pos | ||||
| 			{ | ||||
| 				csn.slots[pos]->type = cso.slots.begin()->second->type; | ||||
| 				csn.slots[pos]->count = cso.slots.begin()->second->count; | ||||
| 			} | ||||
| 			cso.slots.erase(cso.slots.begin()); | ||||
| 		} | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[town->visitingHero->id] = csn; | ||||
| 		sg.garrs[town->id] = csn; | ||||
| 		sendAndApply(&sg); | ||||
|  | ||||
| 		 | ||||
| 		SetHeroesInTown intown; | ||||
| 		intown.tid = tid; | ||||
| 		intown.visiting = -1; | ||||
| @@ -3106,25 +3074,14 @@ bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| 		intown.garrison = -1; | ||||
| 		intown.visiting =  town->garrisonHero->id; | ||||
| 		sendAndApply(&intown); | ||||
|  | ||||
| 		//town will be empty | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[tid] = CCreatureSet(); | ||||
| 		sendAndApply(&sg); | ||||
| 		return true; | ||||
| 	} | ||||
| 	else if (town->garrisonHero && town->visitingHero) //swap visiting and garrison hero | ||||
| 	{ | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[town->id] = town->visitingHero->getArmy();; | ||||
| 		sg.garrs[town->garrisonHero->id] = town->garrisonHero->getArmy(); | ||||
|  | ||||
| 		SetHeroesInTown intown; | ||||
| 		intown.tid = tid; | ||||
| 		intown.garrison = town->visitingHero->id; | ||||
| 		intown.visiting =  town->garrisonHero->id; | ||||
| 		sendAndApply(&intown); | ||||
| 		sendAndApply(&sg); | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| @@ -3537,14 +3494,7 @@ bool CGameHandler::sellCreatures(ui32 count, const IMarket *market, const CGHero | ||||
|  		assert(0); | ||||
|  	} | ||||
|   | ||||
|  | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[hero->id] = hero->getArmy(); | ||||
| 	if(s.count > count) | ||||
| 		sg.garrs[hero->id].setStackCount(slot, s.count - count); | ||||
| 	else | ||||
| 		sg.garrs[hero->id].eraseStack(slot); | ||||
| 	sendAndApply(&sg); | ||||
| 	changeStackCount(StackLocation(hero, slot), -count); | ||||
|  | ||||
|  	SetResource sr; | ||||
|  	sr.player = hero->tempOwner; | ||||
| @@ -3561,13 +3511,14 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance | ||||
| 	if (hero) | ||||
| 		army = hero; | ||||
| 	else | ||||
| 	{ | ||||
| 		army = dynamic_cast<const CGTownInstance *>(market->o); | ||||
| 	} | ||||
|  | ||||
| 	if (!army) | ||||
| 		COMPLAIN_RET("Incorrect call to transform in undead!"); | ||||
| 	if(!vstd::contains(army->Slots(), slot)) | ||||
| 	if(!army->hasStackAtSlot(slot)) | ||||
| 		COMPLAIN_RET("Army doesn't have any creature in that slot!"); | ||||
|  | ||||
|  | ||||
| 	const CStackInstance &s = army->getStack(slot); | ||||
| 	int resCreature;//resulting creature - bone dragons or skeletons | ||||
| 	 | ||||
| @@ -3575,10 +3526,8 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance | ||||
| 		resCreature = 68; | ||||
| 	else | ||||
| 		resCreature = 56; | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[army->id] = army->getArmy(); | ||||
| 	sg.garrs[army->id].setCreature(slot, resCreature, s.count); | ||||
| 	sendAndApply(&sg); | ||||
|  | ||||
| 	changeStackType(StackLocation(army, slot), VLC->creh->creatures[resCreature]); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -4054,30 +4003,22 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message ) | ||||
| 	else if(message == "vcmiainur") //gives 5 archangels into each slot | ||||
| 	{ | ||||
| 		CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection); | ||||
| 		const CCreature *archangel = VLC->creh->creatures[13]; | ||||
| 		if(!hero) return; | ||||
|  | ||||
| 		SetGarrisons sg; | ||||
| 		CCreatureSet &newArmy = sg.garrs[hero->id]; | ||||
|  | ||||
| 		newArmy = hero->getArmy(); | ||||
| 		for(int i=0; i<ARMY_SIZE; i++) | ||||
| 			if(newArmy.slotEmpty(i)) | ||||
| 				newArmy.addToSlot(i, 13, 5); | ||||
| 		sendAndApply(&sg); | ||||
| 		for(int i = 0; i < ARMY_SIZE; i++) | ||||
| 			if(!hero->hasStackAtSlot(i)) | ||||
| 				insertNewStack(StackLocation(hero, i), archangel, 10); | ||||
| 	} | ||||
| 	else if(message == "vcmiangband") //gives 10 black knight into each slot | ||||
| 	{ | ||||
| 		CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection); | ||||
| 		const CCreature *blackKnight = VLC->creh->creatures[66]; | ||||
| 		if(!hero) return; | ||||
|  | ||||
| 		SetGarrisons sg; | ||||
| 		CCreatureSet &newArmy = sg.garrs[hero->id]; | ||||
|  | ||||
| 		newArmy = hero->getArmy(); | ||||
| 		for(int i=0; i<ARMY_SIZE; i++) | ||||
| 			if(newArmy.slotEmpty(i)) | ||||
| 				newArmy.addToSlot(i, 66, 10); | ||||
| 		sendAndApply(&sg); | ||||
| 		for(int i = 0; i < ARMY_SIZE; i++) | ||||
| 			if(!hero->hasStackAtSlot(i)) | ||||
| 				insertNewStack(StackLocation(hero, i), blackKnight, 10); | ||||
| 	} | ||||
| 	else if(message == "vcminoldor") //all war machines | ||||
| 	{ | ||||
| @@ -5244,7 +5185,6 @@ bool CGameHandler::tryAttackingGuard(const int3 &guardPos, const CGHeroInstance | ||||
| bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstance *hero, TSlot slot, ui32 count) | ||||
| { | ||||
| 	int oldCount = hero->getStackCount(slot); | ||||
| 	int newCount = oldCount - count; | ||||
|  | ||||
| 	if(oldCount < count) | ||||
| 		COMPLAIN_RET("Not enough creatures to sacrifice!") | ||||
| @@ -5253,18 +5193,12 @@ bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstanc | ||||
|  | ||||
| 	int crid = hero->getStack(slot).type->idNumber; | ||||
| 	 | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[hero->id] = hero->getArmy(); | ||||
| 	if(newCount) | ||||
| 		sg.garrs[hero->id].setStackCount(slot, newCount); | ||||
| 	else | ||||
| 		sg.garrs[hero->id].eraseStack(slot); | ||||
| 	sendAndApply(&sg); | ||||
| 	changeStackCount(StackLocation(hero, slot), -count); | ||||
|  | ||||
| 	int dump, exp; | ||||
| 	market->getOffer(crid, 0, dump, exp, CREATURE_EXP); | ||||
| 	exp *= count; | ||||
| 	changePrimSkill	(hero->id, 4, exp*(100+hero->getSecSkillLevel(21)*5)/100.0f); | ||||
| 	changePrimSkill(hero->id, 4, exp*(100+hero->getSecSkillLevel(21)*5)/100.0f); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
| @@ -5280,26 +5214,149 @@ bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * h | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count) | ||||
| bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count) | ||||
| { | ||||
| 	if(sl.army->hasStackAtSlot(sl.slot)) | ||||
| 		COMPLAIN_RET("Slot is already taken!"); | ||||
|  | ||||
| 	InsertNewStack ins; | ||||
| 	ins.sl = sl; | ||||
| 	ins.stack = new CStackInstance(c, count); | ||||
| 	sendAndApply(&ins); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::eraseStack(const StackLocation &sl) | ||||
| bool CGameHandler::eraseStack(const StackLocation &sl) | ||||
| { | ||||
| 	if(!sl.army->hasStackAtSlot(sl.slot)) | ||||
| 		COMPLAIN_RET("Cannot find a stack to erase"); | ||||
|  | ||||
| 	if(sl.army->Slots().size() == 1 //from the last stack | ||||
| 		&& sl.army->needsLastStack()) //that must be left | ||||
| 	{ | ||||
| 		COMPLAIN_RET("Cannot erase the last stack!"); | ||||
| 	} | ||||
|  | ||||
| 	EraseStack es; | ||||
| 	es.sl = sl; | ||||
| 	sendAndApply(&es); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue /*= false*/) | ||||
| bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue /*= false*/) | ||||
| { | ||||
| 	ChangeStackCount csc; | ||||
| 	csc.sl = sl; | ||||
| 	csc.count = count; | ||||
| 	csc.absoluteValue = absoluteValue; | ||||
| 	sendAndApply(&csc); | ||||
| 	TQuantity currentCount = sl.army->getStackCount(sl.slot); | ||||
| 	if(absoluteValue && count < 0 | ||||
| 		|| !absoluteValue && -count > currentCount) | ||||
| 	{ | ||||
| 		COMPLAIN_RET("Cannot take more stacks than present!"); | ||||
| 	} | ||||
|  | ||||
| 	if(currentCount == -count  &&  !absoluteValue | ||||
| 		|| !count && absoluteValue) | ||||
| 	{ | ||||
| 		eraseStack(sl); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ChangeStackCount csc; | ||||
| 		csc.sl = sl; | ||||
| 		csc.count = count; | ||||
| 		csc.absoluteValue = absoluteValue; | ||||
| 		sendAndApply(&csc); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) | ||||
| { | ||||
| 	const CCreature *slotC = sl.army->getCreature(sl.slot); | ||||
| 	if(!slotC) //slot is empty | ||||
| 		insertNewStack(sl, c, count); | ||||
| 	else if(c == slotC) | ||||
| 		changeStackCount(sl, count); | ||||
| 	else | ||||
| 	{ | ||||
| 		tlog1 << "Cannot add " << c->namePl << " to slot " << sl.slot << std::endl; | ||||
| 		COMPLAIN_RET("Cannot add stack to slot!"); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished) | ||||
| { | ||||
| 	if(!dst->canBeMergedWith(*src)) | ||||
| 	{ | ||||
| 		boost::function<void()> removeOrNot = 0; | ||||
| 		if(removeObjWhenFinished)  | ||||
| 			removeOrNot = boost::bind(&IGameCallback::removeObject,this,src->id); | ||||
| 		showGarrisonDialog(src->id, dst->id, true, removeOrNot); //show garrison window and optionally remove ourselves from map when player ends | ||||
| 	} | ||||
| 	else //merge | ||||
| 	{ | ||||
| 		while(src->slots.size()) //there are not moved cres | ||||
| 		{ | ||||
| 			TSlots::const_iterator i = src->slots.begin(); | ||||
|  | ||||
| 			TSlot dstSlot = dst->getSlotFor(i->second->type); | ||||
| 			if(dstSlot >= 0) //there is place | ||||
| 			{ | ||||
| 				moveStack(StackLocation(src, i->first), StackLocation(dst, dstSlot), i->second->count); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				tlog1 << "Unexpected Failure on merging armies!\n"; | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if(removeObjWhenFinished) | ||||
| 			removeObject(src->id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count) | ||||
| { | ||||
| 	if(!src.army->hasStackAtSlot(src.slot)) | ||||
| 		COMPLAIN_RET("No stack to move!"); | ||||
|  | ||||
| 	if(dst.army->hasStackAtSlot(dst.slot) && dst.army->getCreature(dst.slot) != src.army->getCreature(src.slot)) | ||||
| 		COMPLAIN_RET("Cannot move: stack of different type at destination pos!"); | ||||
|  | ||||
| 	if(count == -1) | ||||
| 	{ | ||||
| 		count = src.army->getStackCount(src.slot); | ||||
| 	} | ||||
|  | ||||
| 	if(src.army != dst.army  //moving away | ||||
| 		&&  count == src.army->getStackCount(src.slot) //all creatures | ||||
| 		&& src.army->Slots().size() == 1 //from the last stack | ||||
| 		&& src.army->needsLastStack()) //that must be left | ||||
| 	{ | ||||
| 		COMPLAIN_RET("Cannot move away the alst creature!"); | ||||
| 	} | ||||
|  | ||||
| 	RebalanceStacks rs; | ||||
| 	rs.src = src; | ||||
| 	rs.dst = dst; | ||||
| 	rs.count = count; | ||||
| 	sendAndApply(&rs); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2) | ||||
| { | ||||
|  | ||||
| 	if(!sl1.army->hasStackAtSlot(sl1.slot)) | ||||
| 		return moveStack(sl2, sl1); | ||||
| 	else if(!sl2.army->hasStackAtSlot(sl2.slot)) | ||||
| 		return moveStack(sl1, sl2); | ||||
| 	else | ||||
| 	{ | ||||
| 		SwapStacks ss; | ||||
| 		ss.sl1 = sl1; | ||||
| 		ss.sl2 = sl2; | ||||
| 		sendAndApply(&ss); | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| @@ -138,10 +138,14 @@ public: | ||||
| 	void giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures, bool remove); | ||||
| 	void takeCreatures (int objid, TSlots creatures); | ||||
| 	void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures); | ||||
| 	void changeStackType(const StackLocation &sl, CCreature *c); | ||||
| 	void changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false); | ||||
| 	void insertNewStack(const StackLocation &sl, CCreature *c, TQuantity count); | ||||
| 	void eraseStack(const StackLocation &sl); | ||||
| 	bool changeStackType(const StackLocation &sl, CCreature *c); | ||||
| 	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false); | ||||
| 	bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count); | ||||
| 	bool eraseStack(const StackLocation &sl); | ||||
| 	bool swapStacks(const StackLocation &sl1, const StackLocation &sl2); | ||||
| 	bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count); | ||||
| 	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished); | ||||
| 	bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1); | ||||
| 	void showCompInfo(ShowInInfobox * comp); | ||||
| 	void heroVisitCastle(int obj, int heroID); | ||||
| 	void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h); | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
|  | ||||
| CGameState* CPackForServer::GS(CGameHandler *gh) | ||||
| { | ||||
| 	return gh->gs; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user