Преглед на файлове

Fixed fighting guardians of Dwellings (and other objs as well).
Most of creature generators should work fine.

Michał W. Urbańczyk преди 16 години
родител
ревизия
9206a13390
променени са 8 файла, в които са добавени 78 реда и са изтрити 58 реда
  1. 11 12
      client/CPlayerInterface.cpp
  2. 1 0
      client/CPlayerInterface.h
  3. 3 2
      client/Client.h
  4. 13 18
      hch/CObjectHandler.cpp
  5. 5 2
      lib/IGameCallback.h
  6. 1 1
      lib/NetPacksLib.cpp
  7. 38 19
      server/CGameHandler.cpp
  8. 6 4
      server/CGameHandler.h

+ 11 - 12
client/CPlayerInterface.cpp

@@ -1025,12 +1025,7 @@ void CPlayerInterface::receivedResource(int type, int val)
 
 void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16>& skills, boost::function<void(ui32)> &callback)
 {
-	{
-		boost::unique_lock<boost::mutex> un(showingDialog->mx);
-		while(showingDialog->data)
-			showingDialog->cond.wait(un);
-	}
-
+	waitWhileDialog();
 	CGI->soundh->playSound(soundBase::heroNewLevel);
 
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
@@ -1378,12 +1373,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 
 void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, int soundID)
 {
-	{
-		boost::unique_lock<boost::mutex> un(showingDialog->mx);
-		while(showingDialog->data)
-			showingDialog->cond.wait(un);
-	}
-
+	waitWhileDialog();
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	
 	if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement
@@ -1424,6 +1414,7 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto
 
 void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel )
 {
+	waitWhileDialog();
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 
 	CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
@@ -1734,6 +1725,7 @@ const CGHeroInstance * CPlayerInterface::getWHero( int pos )
 
 void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, int level)
 {
+	waitWhileDialog();
 	std::vector<std::pair<int,int> > cres;
 	for(int i = 0; i < dwelling->creatures.size(); i++)
 	{
@@ -1745,6 +1737,13 @@ void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, int lev
 	pushInt(cr);
 }
 
+void CPlayerInterface::waitWhileDialog()
+{
+	boost::unique_lock<boost::mutex> un(showingDialog->mx);
+	while(showingDialog->data)
+		showingDialog->cond.wait(un);
+}
+
 void SystemOptions::setMusicVolume( int newVolume )
 {
 	musicVolume = newVolume;

+ 1 - 0
client/CPlayerInterface.h

@@ -192,6 +192,7 @@ public:
 
 
 	//-------------//
+	void waitWhileDialog();
 	bool shiftPressed() const; //determines if shift key is pressed (left or right or both)
 	void redrawHeroWin(const CGHeroInstance * hero);
 	void updateWater();

+ 3 - 2
client/Client.h

@@ -96,8 +96,9 @@ public:
 	void heroVisitCastle(int obj, int heroID){};
 	void stopHeroVisitCastle(int obj, int heroID){};
 	void giveHeroArtifact(int artid, int hid, int position){}; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
-	void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb){}; //use hero=NULL for no hero
-	void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb){}; //for hero<=>neutral army
+	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb = 0){}; //use hero=NULL for no hero
+	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0){}; //if any of armies is hero, hero will be used
+	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
 	void setAmount(int objid, ui32 val){};
 	bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255){return false;};
 	void giveHeroBonus(GiveBonus * bonus){};

+ 13 - 18
hch/CObjectHandler.cpp

@@ -652,13 +652,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
 		else
 		{
 			//battle
-			cb->startBattleI(
-				&h->army,
-				&army,
-				h->pos,
-				h,
-				this,
-				0);
+			cb->startBattleI(h,	this);
 		}
 	}
 	else if(ID == 62) //prison
@@ -1113,7 +1107,7 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) co
 void CGDwelling::wantsFight( const CGHeroInstance *h, ui32 answer ) const
 {
 	if(answer)
-		cb->startBattleI(h->id,army,pos,boost::bind(&CGDwelling::fightOver, this, h, _1));
+		cb->startBattleI(h, this, boost::bind(&CGDwelling::fightOver, this, h, _1));
 }
 
 void CGDwelling::fightOver(const CGHeroInstance *h, BattleResult *result) const
@@ -1667,12 +1661,12 @@ void CGCreature::endBattle( BattleResult *result ) const
 	}
 	else
 	{
-		int killedAmount=0;
-		for(std::set<std::pair<ui32,si32> >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++)
-			if(i->first == subID)
-				killedAmount += i->second;
-		cb->setAmount(id, army.slots.find(0)->second.second - killedAmount);	
-		
+		//int killedAmount=0;
+		//for(std::set<std::pair<ui32,si32> >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++)
+		//	if(i->first == subID)
+		//		killedAmount += i->second;
+		//cb->setAmount(id, army.slots.find(0)->second.second - killedAmount);	
+
 		MetaString ms;
 		int pom = CCreature::getQuantityID(army.slots.find(0)->second.second);
 		pom = 174 + 3*pom + 1;
@@ -1861,7 +1855,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
 
 void CGCreature::fight( const CGHeroInstance *h ) const
 {
-	cb->startBattleI(h->id,army,pos,boost::bind(&CGCreature::endBattle,this,_1));
+	cb->startBattleI(h, this, boost::bind(&CGCreature::endBattle,this,_1));
 }
 
 void CGCreature::flee( const CGHeroInstance * h ) const
@@ -1997,7 +1991,7 @@ void CGResource::collectRes( int player ) const
 void CGResource::fightForRes(ui32 agreed, const CGHeroInstance *h) const
 {
 	if(agreed)
-		cb->startBattleI(h->id,army,pos,boost::bind(&CGResource::endBattle,this,_1,h));
+		cb->startBattleI(h, this, boost::bind(&CGResource::endBattle,this,_1,h));
 }
 
 void CGResource::endBattle( BattleResult *result, const CGHeroInstance *h ) const
@@ -2164,6 +2158,7 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 		if(ID == 5)
 		{
 			InfoWindow iw;
+			iw.soundID = soundBase::treasure;
 			iw.player = h->tempOwner;
 			iw.components.push_back(Component(4,subID,0,0));
 			if(message.length())
@@ -2206,7 +2201,7 @@ void CGArtifact::pick(const CGHeroInstance * h) const
 void CGArtifact::fightForArt( ui32 agreed, const CGHeroInstance *h ) const
 {
 	if(agreed)
-		cb->startBattleI(h->id,army,pos,boost::bind(&CGArtifact::endBattle,this,_1,h));
+		cb->startBattleI(h, this, boost::bind(&CGArtifact::endBattle,this,_1,h));
 }
 
 void CGArtifact::endBattle( BattleResult *result, const CGHeroInstance *h ) const
@@ -2695,7 +2690,7 @@ void CGEvent::activated( const CGHeroInstance * h ) const
 		else
 			iw.text.addTxt(MetaString::ADVOB_TXT, 16);
 		cb->showInfoDialog(&iw);
-		cb->startBattleI(h->id,army,pos,boost::bind(&CGEvent::endBattle,this,h,_1));
+		cb->startBattleI(h, this, boost::bind(&CGEvent::endBattle,this,h,_1));
 	}
 	else
 	{

+ 5 - 2
lib/IGameCallback.h

@@ -31,6 +31,7 @@ struct PlayerSettings;
 struct CPackForClient;
 class CArtHandler;
 class CArtifact;
+class CArmedInstance;
 
 class DLL_EXPORT IGameCallback
 {
@@ -73,8 +74,10 @@ public:
 	virtual void heroVisitCastle(int obj, int heroID)=0;
 	virtual void stopHeroVisitCastle(int obj, int heroID)=0;
 	virtual void giveHeroArtifact(int artid, int hid, int position)=0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack
-	virtual void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb)=0; //use hero=NULL for no hero
-	virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb)=0; //for hero<=>neutral army
+	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb = 0)=0; //use hero=NULL for no hero
+	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0)=0; //if any of armies is hero, hero will be used
+	virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
+	//virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb)=0; //for hero<=>neutral army
 	virtual void setAmount(int objid, ui32 val)=0;
 	virtual bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255)=0;
 	virtual void giveHeroBonus(GiveBonus * bonus)=0;

+ 1 - 1
lib/NetPacksLib.cpp

@@ -288,7 +288,7 @@ void TryMoveHero::applyGs( CGameState *gs )
 	CGHeroInstance *h = gs->getHero(id);
 	h->movement = movePoints;
 
-	if(result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK)
+	if((result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK) && start != end)
 		h->moveDir = getDir(start,end);
 
 	if(result == EMBARK) //hero enters boat at dest tile

+ 38 - 19
server/CGameHandler.cpp

@@ -294,6 +294,8 @@ void CGameHandler::changePrimSkill(int ID, int which, int val, bool abs)
 
 static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInfo *bat)
 {
+	if(color == 254)
+		color = 255;
 	CCreatureSet ret(set);
 	for(int i=0; i<bat->stacks.size();i++)
 	{
@@ -309,10 +311,10 @@ static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInf
 	return ret;
 }
 
-void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb)
+void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb)
 {
 	BattleInfo *curB = new BattleInfo;
-	setupBattle(curB, tile, army1, army2, hero1, hero2); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
+	setupBattle(curB, tile, army1->army, army2->army, hero1, hero2); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
 	NEW_ROUND;
 	//TODO: pre-tactic stuff, call scripts etc.
 
@@ -401,10 +403,8 @@ askInterfaceForMove:
 
 	//casualties among heroes armies
 	SetGarrisons sg;
-	if(hero1)
-		sg.garrs[hero1->id] = takeCasualties(hero1->tempOwner,hero1->army,gs->curB);
-	if(hero2)
-		sg.garrs[hero2->id] = takeCasualties(hero2->tempOwner,hero2->army,gs->curB);
+	sg.garrs[army1->id] = takeCasualties(army1->tempOwner,army1->army,gs->curB);
+	sg.garrs[army2->id] = takeCasualties(army2->tempOwner,army2->army,gs->curB);
 	sendAndApply(&sg);
 
 	//end battle, remove all info, free memory
@@ -822,7 +822,7 @@ namespace CGH
 	}
 }
 
-void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 )
+void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2 )
 {
 	battleResult.set(NULL);
 	std::vector<CStack*> & stacks = (curB->stacks);
@@ -837,7 +837,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army
 	curB->side2=(hero2)?(hero2->tempOwner):(-1);
 	curB->round = -2;
 	curB->activeStack = -1;
-	for(std::map<si32,std::pair<ui32,si32> >::iterator i = army1.slots.begin(); i!=army1.slots.end(); i++)
+	for(std::map<si32,std::pair<ui32,si32> >::const_iterator i = army1.slots.begin(); i!=army1.slots.end(); i++)
 	{
 		stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero1->tempOwner, stacks.size(), true,i->first));
 		if(hero1)
@@ -890,7 +890,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army
 		{
 			stacks[b]->position = attackerLoose[army1.slots.size()-1][b];
 		}
-	for(std::map<si32,std::pair<ui32,si32> >::iterator i = army2.slots.begin(); i!=army2.slots.end(); i++)
+	for(std::map<si32,std::pair<ui32,si32> >::const_iterator i = army2.slots.begin(); i!=army2.slots.end(); i++)
 	{
 		stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero2 ? hero2->tempOwner : 255, stacks.size(), false, i->first));
 		//base luck/morale calculations
@@ -1170,7 +1170,8 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
 			&& complain("Cannot move hero, destination tile is on water!")
 		|| (h->boat && t.tertype != TerrainTile::water && t.blocked)
 			&& complain("Cannot disembark hero, tile is blocked!")
-		|| !h->movement && complain("Hero don't have any movement points left!"))
+		|| (!h->movement && dst != h->pos)
+			&& complain("Hero don't have any movement points left!"))
 	{
 		//send info about movement failure
 		sendAndApply(&tmh);
@@ -1266,11 +1267,15 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
 		{
 			if(obj->ID==HEROI_TYPE)
 			{
+				CGHeroInstance *dh = static_cast<CGHeroInstance *>(obj);
+
 				if(obj->tempOwner==h->tempOwner) 
-					return true;//TODO: exchange
+				{
+					heroExchange(h->id, dh->id);
+					return true;
+				}
 				//TODO: check for ally
-				CGHeroInstance *dh = static_cast<CGHeroInstance *>(obj);
-				startBattleI(&h->army,&dh->army,dst,h,dh,0);
+				startBattleI(h, dh);
 				return true;
 			}
 		}
@@ -1397,17 +1402,31 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
 	sendAndApply(&sha);
 }
 
-void CGameHandler::startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb) //use hero=NULL for no hero
+void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb) //use hero=NULL for no hero
+{
+	boost::thread(boost::bind(&CGameHandler::startBattle,this,army1,army2,tile,hero1,hero2,cb));
+}
+
+void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb )
 {
-	boost::thread(boost::bind(&CGameHandler::startBattle,this,*const_cast<CCreatureSet *>(army1),*const_cast<CCreatureSet *>(army2),tile,const_cast<CGHeroInstance *>(hero1), const_cast<CGHeroInstance *>(hero2),cb));
+	startBattleI(army1, army2, tile,
+		army1->ID == 34 ? static_cast<const CGHeroInstance*>(army1) : NULL, 
+		army2->ID == 34 ? static_cast<const CGHeroInstance*>(army2) : NULL, 
+		cb);
 }
-void CGameHandler::startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) //for hero<=>neutral army
+
+void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb)
 {
-	CGHeroInstance* h = const_cast<CGHeroInstance*>(getHero(heroID));
-	startBattleI(&h->army,&army,tile,h,NULL,cb);
-	//battle(&h->army,army,tile,h,NULL);
+	startBattleI(army1, army2, army2->pos - army2->getVisitableOffset(), cb);
 }
 
+//void CGameHandler::startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) //for hero<=>neutral army
+//{
+//	CGHeroInstance* h = const_cast<CGHeroInstance*>(getHero(heroID));
+//	startBattleI(&h->army,&army,tile,h,NULL,cb);
+//	//battle(&h->army,army,tile,h,NULL);
+//}
+
 void CGameHandler::changeSpells( int hid, bool give, const std::set<ui32> &spells )
 {
 	ChangeSpells cs;

+ 6 - 4
server/CGameHandler.h

@@ -84,11 +84,11 @@ public:
 	bool isAllowedExchange(int id1, int id2);
 	void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
 	void moveStack(int stack, int dest);
-	void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
+	void startBattle(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
 	void prepareAttack(BattleAttack &bat, CStack *att, CStack *def); //if last parameter is true, attack is by shooting, if false it's a melee attack
 	void prepareAttacked(BattleStackAttacked &bsa, CStack *def);
 	void checkForBattleEnd( std::vector<CStack*> &stacks );
-	void setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 );
+	void setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2 );
 
 
 	CGameHandler(void);
@@ -121,8 +121,10 @@ public:
 	void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack
 	void moveArtifact(int hid, int oldPosition, int destPos);
 	void removeArtifact(int hid, int pos);
-	void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
-	void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
+	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
+	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb);
+	void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
+	//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
 	void setAmount(int objid, ui32 val);
 	bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255);
 	void giveHeroBonus(GiveBonus * bonus);