mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Stacks #5: giving creatures, practically finished (many fixes needed).
This commit is contained in:
		| @@ -3589,7 +3589,7 @@ void CBattleHex::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
|  | ||||
| 	if(hovered && strictHovered) //print attacked creature to console | ||||
| 	{ | ||||
| 		if(myInterface->console->alterTxt.size() == 0 && myInterface->curInt->cb->battleGetStackByID(myNumber) != NULL && | ||||
| 		if(myInterface->console->alterTxt.size() == 0 && myInterface->curInt->cb->battleGetStackByPos(myNumber) != NULL && | ||||
| 			myInterface->curInt->cb->battleGetStackByPos(myNumber)->owner != myInterface->curInt->playerID && | ||||
| 			myInterface->curInt->cb->battleGetStackByPos(myNumber)->alive()) | ||||
| 		{ | ||||
|   | ||||
| @@ -110,7 +110,7 @@ public: | ||||
| 	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb){}; | ||||
| 	void showThievesGuildWindow(int requestingObjId){}; | ||||
| 	void giveResource(int player, int which, int val){}; | ||||
| 	void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) {}; | ||||
| 	void giveCreatures (const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) {}; | ||||
| 	void takeCreatures (int objid, TSlots creatures){}; | ||||
| 	void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures){}; | ||||
| 	bool changeStackType(const StackLocation &sl, CCreature *c){return false;}; | ||||
| @@ -119,7 +119,7 @@ public: | ||||
| 	bool eraseStack(const StackLocation &sl, bool forceRemoval = false){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){} | ||||
| 	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging){} | ||||
| 	bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1){return false;} | ||||
| 	void showCompInfo(ShowInInfobox * comp){}; | ||||
| 	void heroVisitCastle(int obj, int heroID){}; | ||||
|   | ||||
| @@ -3106,7 +3106,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co | ||||
| 		if(cost) | ||||
| 			cb->giveResource(h->tempOwner,6,-cost); | ||||
|  | ||||
| 		cb->tryJoiningArmy(this, h, true); | ||||
| 		cb->tryJoiningArmy(this, h, true, false); | ||||
| // 		int slot = h->getSlotFor(subID); | ||||
| // 		if(slot >= 0) //there is place | ||||
| // 		{ | ||||
| @@ -4461,7 +4461,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward | ||||
| 			{ | ||||
| 				CCreatureSet creatures; | ||||
| 				creatures.setCreature(0, rID, rVal); | ||||
| 				cb->giveCreatures(id, h, creatures, false); | ||||
| 				cb->giveCreatures(this, h, creatures, false); | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| @@ -5029,7 +5029,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con | ||||
| 		iw.text.addReplacement(h->name); | ||||
|  | ||||
| 		cb->showInfoDialog(&iw); | ||||
| 		cb->giveCreatures (id, h, creatures, true); | ||||
| 		cb->giveCreatures(this, h, creatures, true); | ||||
| 		//boost::bind(&CGPandoraBox::endBattle, this, h, _1) | ||||
| 	} | ||||
| 	if(!afterBattle && message.size()) | ||||
| @@ -5909,7 +5909,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons | ||||
| 			iw.text.addReplacement(loot.buildList()); | ||||
| 			iw.text.addReplacement(h->name); | ||||
| 			cb->showInfoDialog(&iw); | ||||
| 			cb->giveCreatures (id, h, ourArmy, false); | ||||
| 			cb->giveCreatures(this, h, ourArmy, false); | ||||
| 		} | ||||
| 		cb->setObjProperty (id, 15, 0); //bc = NULL | ||||
| 	} | ||||
|   | ||||
| @@ -675,7 +675,7 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT CGSeerHut : public CGObjectInstance, public CQuest | ||||
| class DLL_EXPORT CGSeerHut : public CArmedInstance, public CQuest //army is used when giving reward | ||||
| { | ||||
| public: | ||||
| 	ui8 rewardType; //type of reward: 0 - no reward; 1 - experience; 2 - mana points; 3 - morale bonus; 4 - luck bonus; 5 - resources; 6 - main ability bonus (attak, defence etd.); 7 - secondary ability gain; 8 - artifact; 9 - spell; 10 - creature | ||||
|   | ||||
| @@ -345,17 +345,32 @@ void CCreatureSet::setStackType(TSlot slot, const CCreature *type) | ||||
| 	s->setType(type->idNumber); | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs) const | ||||
| bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks) const | ||||
| { | ||||
| 	std::set<const CCreature*> cres; | ||||
| 	if(!allowMergingStacks) | ||||
| 	{ | ||||
| 		int freeSlots = stacksCount() - ARMY_SIZE; | ||||
| 		std::set<const CCreature*> cresToAdd; | ||||
| 		for(TSlots::const_iterator i = cs.slots.begin(); i != cs.slots.end(); i++) | ||||
| 		{ | ||||
| 			TSlot dest = getSlotFor(i->second->type); | ||||
| 			if(dest < 0 || hasStackAtSlot(dest)) | ||||
| 				cresToAdd.insert(i->second->type); | ||||
| 		} | ||||
| 		return cresToAdd.size() <= freeSlots; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		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); | ||||
| 		//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; | ||||
| 		return cres.size() <= ARMY_SIZE; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::hasStackAtSlot(TSlot slot) const | ||||
|   | ||||
| @@ -124,7 +124,7 @@ public: | ||||
| 	bool hasStackAtSlot(TSlot slot) const; | ||||
| 	 | ||||
| 	bool contains(const CStackInstance *stack) const; | ||||
| 	bool canBeMergedWith(const CCreatureSet &cs) const; | ||||
| 	bool canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks = true) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -87,7 +87,7 @@ public: | ||||
| 	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 showThievesGuildWindow(int requestingObjId) =0; | ||||
| 	virtual void giveResource(int player, int which, int val)=0; | ||||
| 	virtual void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0; | ||||
| 	virtual void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0; | ||||
| 	//virtual void takeCreatures (int objid, TSlots creatures) =0; | ||||
| 	virtual void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) =0; | ||||
| 	virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0; | ||||
| @@ -96,7 +96,7 @@ public: | ||||
| 	virtual bool eraseStack(const StackLocation &sl, bool forceRemoval = false) =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 void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) =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; | ||||
|   | ||||
| @@ -1439,7 +1439,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 				CStackInstance *hlp = new CStackInstance(); | ||||
| 				hlp->count =  readNormalNr(bufor,i, 2); i+=2; | ||||
| 				//type will be set during initialization | ||||
| 				cre->slots[0] = hlp; | ||||
| 				cre->putStack(0, hlp); | ||||
|  | ||||
| 				cre->character = bufor[i]; ++i; | ||||
| 				bool isMesTre = bufor[i]; ++i; //true if there is message or treasury | ||||
|   | ||||
| @@ -24,6 +24,7 @@ | ||||
| #include <boost/assign/list_of.hpp> | ||||
| #include <boost/random/linear_congruential.hpp> | ||||
| #include <fstream> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/system/system_error.hpp> | ||||
|  | ||||
| /* | ||||
| @@ -50,6 +51,7 @@ extern bool end2; | ||||
| #undef max | ||||
| #endif | ||||
|  | ||||
| #define COMPLAIN_RET_IF(cond, txt) do {if(cond){complain(txt); return;}} while(0) | ||||
| #define COMPLAIN_RET(txt) {complain(txt); return false;} | ||||
| #define NEW_ROUND 		BattleNextRound bnr;\ | ||||
| 		bnr.round = gs->curB->round + 1;\ | ||||
| @@ -2062,41 +2064,25 @@ void CGameHandler::giveResource(int player, int which, int val) | ||||
| 	sr.val = gs->players.find(player)->second.resources[which]+val; | ||||
| 	sendAndApply(&sr); | ||||
| } | ||||
| void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) | ||||
|  | ||||
| void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) | ||||
| { | ||||
| 	assert(0); | ||||
| // 	if (creatures.stacksCount() <= 0) | ||||
| // 		return; | ||||
| // 	CCreatureSet heroArmy = h->getArmy(); | ||||
| // 	std::set<int> takenSlots; | ||||
| // 	for (TSlots::const_iterator it = creatures.Slots().begin(); it != creatures.Slots().end(); it++) | ||||
| // 	{ | ||||
| // 		int slot = heroArmy.getSlotFor(it->second->type->idNumber); | ||||
| // 		if (slot >= 0) | ||||
| // 		{ | ||||
| // 			heroArmy.addToSlot(slot, it->second); 	//move all matching creatures to hero's army | ||||
| // 			takenSlots.insert(it->first); //slot id | ||||
| // 		} | ||||
| // 	} | ||||
| // 	for (std::set<int>::iterator it = takenSlots.begin(); it != takenSlots.end(); it++) | ||||
| // 		creatures.eraseStack(*it); //delete them from used army | ||||
| //  | ||||
| // 	SetGarrisons sg; | ||||
| // 	sg.garrs[h->id] = heroArmy; | ||||
| // 	sg.garrs[objid] = creatures; | ||||
| // 	sendAndApply (&sg); | ||||
| //  | ||||
| // 	if (remove) //show garrison window and let player pick remaining creatures | ||||
| // 	{ | ||||
| // 		if (creatures.stacksCount()) //Pandora needs to exist until we close garrison window | ||||
| // 		{ | ||||
| // 			showGarrisonDialog (objid, h->id, true, boost::bind(&CGameHandler::removeObject, this, objid)); | ||||
| // 		} | ||||
| // 		else | ||||
| // 			removeObject(objid); | ||||
| // 	} | ||||
| // 	else if (creatures.stacksCount()) | ||||
| // 		showGarrisonDialog (objid, h->id, true, 0); | ||||
| 	boost::function<void()> removeOrNot = 0; | ||||
| 	if(remove) | ||||
| 		removeOrNot = boost::bind(&CGameHandler::removeObject, this, obj->id); | ||||
|  | ||||
| 	COMPLAIN_RET_IF(!creatures.stacksCount(), "Strange, giveCreatures called without args!"); | ||||
| 	COMPLAIN_RET_IF(obj->stacksCount(), "Cannot give creatures from not-cleared object!"); | ||||
| 	COMPLAIN_RET_IF(creatures.stacksCount() > ARMY_SIZE, "Too many stacks to give!"); | ||||
|  | ||||
| 	//first we move creatures to give to make them army of object-source | ||||
| 	for(int i = 0; creatures.stacksCount(); i++) | ||||
| 	{ | ||||
| 		TSlots::const_iterator stack = creatures.Slots().begin(); | ||||
| 		addToSlot(StackLocation(obj, i), stack->second->type, stack->second->count); | ||||
| 	} | ||||
|  | ||||
| 	tryJoiningArmy(obj, h, remove, false); | ||||
| } | ||||
|  | ||||
| void CGameHandler::takeCreatures(int objid, std::vector<CStackBasicDescriptor> creatures) | ||||
| @@ -2994,6 +2980,38 @@ bool CGameHandler::changeStackType(const StackLocation &sl, CCreature *c) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging)  | ||||
| { | ||||
| 	assert(src->canBeMergedWith(*dst, allowMerging)); | ||||
| 	while(!src->stacksCount())//while there are unmoved creatures | ||||
| 	{ | ||||
| 		TSlots::const_iterator i = src->Slots().begin(); //iterator to stack to move | ||||
| 		StackLocation sl(src, i->first); //location of stack to move | ||||
|  | ||||
| 		TSlot pos = dst->getSlotFor(i->second->type); | ||||
| 		if(pos < 0) | ||||
| 		{ | ||||
| 			//try to merge two other stacks to make place | ||||
| 			std::pair<TSlot, TSlot> toMerge; | ||||
| 			if(dst->mergableStacks(toMerge, i->first) && allowMerging) | ||||
| 			{ | ||||
| 				moveStack(StackLocation(dst, toMerge.first), StackLocation(dst, toMerge.second)); //merge toMerge.first into toMerge.second | ||||
| 				assert(!dst->hasStackAtSlot(toMerge.first)); //we have now a new free slot | ||||
| 				moveStack(sl, StackLocation(dst, toMerge.first)); //move stack to freed slot | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				complain("Unexpected failure during an attempt to move army from " + src->nodeName() + " to " + dst->nodeName() + "!"); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			moveStack(sl, StackLocation(dst, pos)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| { | ||||
| 	CGTownInstance *town = gs->getTown(tid); | ||||
| @@ -3005,36 +3023,8 @@ bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| 			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 | ||||
| 		{ | ||||
| 			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, i->first)) | ||||
| 				{ | ||||
| 					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("Unexpected failure during an attempt to merge town and visiting hero armies!"); | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				moveStack(sl, StackLocation(town->visitingHero, pos)); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		moveArmy(town, town->visitingHero, true); | ||||
| 		 | ||||
| 		SetHeroesInTown intown; | ||||
| 		intown.tid = tid; | ||||
| @@ -5274,15 +5264,14 @@ bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuant | ||||
| 		changeStackCount(sl, count); | ||||
| 	else | ||||
| 	{ | ||||
| 		tlog1 << "Cannot add " << c->namePl << " to slot " << sl.slot << std::endl; | ||||
| 		COMPLAIN_RET("Cannot add stack to slot!"); | ||||
| 		COMPLAIN_RET("Cannot add " + c->namePl + " to slot " + boost::lexical_cast<std::string>(sl.slot) + "!"); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished) | ||||
| void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) | ||||
| { | ||||
| 	if(!dst->canBeMergedWith(*src)) | ||||
| 	if(!dst->canBeMergedWith(*src, allowMerging)) | ||||
| 	{ | ||||
| 		boost::function<void()> removeOrNot = 0; | ||||
| 		if(removeObjWhenFinished)  | ||||
| @@ -5291,22 +5280,7 @@ void CGameHandler::tryJoiningArmy(const CArmedInstance *src, const CArmedInstanc | ||||
| 	} | ||||
| 	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; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		moveArmy(src, dst, allowMerging); | ||||
| 		if(removeObjWhenFinished) | ||||
| 			removeObject(src->id); | ||||
| 	} | ||||
|   | ||||
| @@ -148,7 +148,7 @@ public: | ||||
| 	void showGarrisonDialog(int upobj, int hid, bool removableUnits, const boost::function<void()> &cb); | ||||
| 	void showThievesGuildWindow(int requestingObjId); //TODO: make something more general? | ||||
| 	void giveResource(int player, int which, int val); | ||||
| 	void giveCreatures (int objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove); | ||||
| 	void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove); | ||||
| 	void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures); | ||||
| 	bool changeStackType(const StackLocation &sl, CCreature *c); | ||||
| 	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false); | ||||
| @@ -156,7 +156,7 @@ public: | ||||
| 	bool eraseStack(const StackLocation &sl, bool forceRemoval = false); | ||||
| 	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); | ||||
| 	void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging); | ||||
| 	bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1); | ||||
| 	void showCompInfo(ShowInInfobox * comp); | ||||
| 	void heroVisitCastle(int obj, int heroID); | ||||
| @@ -221,6 +221,7 @@ public: | ||||
| 	void engageIntoBattle( ui8 player ); | ||||
| 	bool dig(const CGHeroInstance *h); | ||||
| 	bool castSpell(const CGHeroInstance *h, int spellID, const int3 &pos); | ||||
| 	void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user