2
0
Эх сурвалжийг харах

* fixed crash on saving when some objects havebeen removed
* support for multi-target attacks/spells in the protocol
* version bumped to 0.7d

Michał W. Urbańczyk 16 жил өмнө
parent
commit
b2c4f3e0fd

+ 2 - 2
AI/GeniusAI/CGeniusAI.cpp

@@ -97,9 +97,9 @@ void CGeniusAI::battleAttack(BattleAttack *ba)
 /**
  * called when stack receives damage (after battleAttack())
  */
-void CGeniusAI::battleStackAttacked(BattleStackAttacked * bsa)
+void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked> & bsa)
 {
-	MsgBox("\t\t\tCGeniusAI::battleStackAttacked");
+	MsgBox("\t\t\tCGeniusAI::battleStacksAttacked");
 }
 /**
  * called by engine when battle starts; side=0 - left, side=1 - right

+ 1 - 1
AI/GeniusAI/CGeniusAI.h

@@ -197,7 +197,7 @@ public:
 	virtual void actionFinished(const BattleAction *action);//occurs AFTER every action taken by any stack or by the hero
 	virtual void actionStarted(const BattleAction *action);//occurs BEFORE every action taken by any stack or by the hero
 	virtual void battleAttack(BattleAttack *ba); //called when stack is performing attack
-	virtual void battleStackAttacked(BattleStackAttacked * bsa); //called when stack receives damage (after battleAttack())
+	virtual void battleStacksAttacked(std::set<BattleStackAttacked> & bsa); //called when stack receives damage (after battleAttack())
 	virtual void battleEnd(BattleResult *br);
 	virtual void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest);

+ 1 - 1
CGameInterface.h

@@ -75,7 +75,7 @@ public:
 	virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
 	virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
 	virtual void battleAttack(BattleAttack *ba){}; //called when stack is performing attack
-	virtual void battleStackAttacked(BattleStackAttacked * bsa){}; //called when stack receives damage (after battleAttack())
+	virtual void battleStacksAttacked(std::set<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
 	virtual void battleEnd(BattleResult *br){};
 	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest, int distance){};

+ 19 - 8
CPlayerInterface.cpp

@@ -2288,18 +2288,24 @@ void CPlayerInterface::battleSpellCasted(SpellCasted *sc)
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	battleInt->spellCasted(sc);
 }
-void CPlayerInterface::battleStackAttacked(BattleStackAttacked * bsa)
+void CPlayerInterface::battleStacksAttacked(std::set<BattleStackAttacked> & bsa)
 {
 	tlog5 << "CPlayerInterface::battleStackAttacked - locking...";
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	tlog5 << "done!\n";
-	if(bsa->isEffect())
+
+
+	std::vector<CBattleInterface::SStackAttackedInfo> arg;
+	for(std::set<BattleStackAttacked>::iterator i = bsa.begin(); i != bsa.end(); i++)
 	{
-		battleInt->displayEffect(bsa->effect, cb->battleGetStackByID(bsa->stackAttacked)->position);
+		if(i->isEffect())
+		{
+			battleInt->displayEffect(i->effect, cb->battleGetStackByID(i->stackAttacked)->position);
+		}
+		CBattleInterface::SStackAttackedInfo to_put = {i->stackAttacked, i->damageAmount, i->killedAmount, LOCPLINT->curAction->stackNumber, LOCPLINT->curAction->actionType==7, i->killed()};
+		arg.push_back(to_put);
 	}
-	std::vector<CBattleInterface::SStackAttackedInfo> arg;
-	CBattleInterface::SStackAttackedInfo to_put = {bsa->stackAttacked, bsa->damageAmount, bsa->killedAmount, LOCPLINT->curAction->stackNumber, LOCPLINT->curAction->actionType==7, bsa->killed()};
-	arg.push_back(to_put);
+
 	battleInt->stacksAreAttacked(arg);
 }
 void CPlayerInterface::battleAttack(BattleAttack *ba)
@@ -2307,7 +2313,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
 	tlog5 << "CPlayerInterface::battleAttack - locking...";
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	tlog5 << "done!\n";
-	if(ba->bsa.lucky()) //lucky hit
+	if(ba->lucky()) //lucky hit
 	{
 		CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
 		std::string hlp = CGI->generaltexth->allTexts[45];
@@ -2315,8 +2321,13 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
 		battleInt->console->addText(hlp);
 		battleInt->displayEffect(18,stack->position);
 	}
+	//TODO: bad luck?
+
 	if(ba->shot())
-		battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
+	{
+		for(std::set<BattleStackAttacked>::iterator i = ba->bsa.begin(); i != ba->bsa.end(); i++)
+			battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(i->stackAttacked));
+	}
 	else
 	{
 		CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);

+ 1 - 1
CPlayerInterface.h

@@ -495,7 +495,7 @@ public:
 	void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	void battleStackMoved(int ID, int dest, int distance);
 	void battleSpellCasted(SpellCasted *sc);
-	void battleStackAttacked(BattleStackAttacked * bsa);
+	void battleStacksAttacked(std::set<BattleStackAttacked> & bsa);
 	void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
 	void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 

+ 14 - 13
client/NetPacksClient.cpp

@@ -335,11 +335,11 @@ void BattleStackMoved::applyFirstCl( CClient *cl )
 
 void BattleStackAttacked::applyCl( CClient *cl )
 {
+	std::set<BattleStackAttacked> bsa;
+	bsa.insert(*this);
 
-	if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
-		cl->playerint[GS(cl)->curB->side1]->battleStackAttacked(this);
-	if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
-		cl->playerint[GS(cl)->curB->side2]->battleStackAttacked(this);
+	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1,battleStacksAttacked,bsa);
+	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2,battleStacksAttacked,bsa);
 }
 
 void BattleAttack::applyFirstCl( CClient *cl )
@@ -352,10 +352,8 @@ void BattleAttack::applyFirstCl( CClient *cl )
 
 void BattleAttack::applyCl( CClient *cl )
 {
-	if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
-		cl->playerint[GS(cl)->curB->side1]->battleStackAttacked(&bsa);
-	if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
-		cl->playerint[GS(cl)->curB->side2]->battleStackAttacked(&bsa);
+	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1,battleStacksAttacked,bsa);
+	INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2,battleStacksAttacked,bsa);
 }
 
 void StartAction::applyFirstCl( CClient *cl )
@@ -381,11 +379,14 @@ void SetStackEffect::applyCl( CClient *cl )
 	sc.id = effect.id;
 	sc.side = 3; //doesn't matter
 	sc.skill = effect.level;
-	sc.tile = GS(cl)->curB->getStack(stack)->position;
-	if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
-		cl->playerint[GS(cl)->curB->side1]->battleSpellCasted(&sc);
-	if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
-		cl->playerint[GS(cl)->curB->side2]->battleSpellCasted(&sc);
+	BOOST_FOREACH(ui32 stack, stacks)
+	{
+		sc.tile = GS(cl)->curB->getStack(stack)->position;
+		if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
+			cl->playerint[GS(cl)->curB->side1]->battleSpellCasted(&sc);
+		if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
+			cl->playerint[GS(cl)->curB->side2]->battleSpellCasted(&sc);
+	}
 }
 
 CGameState* CPackForClient::GS( CClient *cl )

+ 1 - 1
global.h

@@ -19,7 +19,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
 #define THC
 #endif
 
-#define NAME_VER ("VCMI 0.7c")
+#define NAME_VER ("VCMI 0.7d")
 #define CONSOLE_LOGGING_LEVEL 5
 #define FILE_LOGGING_LEVEL 6
 

+ 19 - 10
lib/NetPacks.h

@@ -665,7 +665,7 @@ struct BattleStackAttacked : public CPackForClient//3005
 
 	ui32 stackAttacked;
 	ui32 newAmount, newHP, killedAmount, damageAmount;
-	ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown; 4 - lucky hit
+	ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown;
 	ui32 effect; //set only if flag 2 is present
 
 	bool killed() //if target stack was killed
@@ -676,14 +676,14 @@ struct BattleStackAttacked : public CPackForClient//3005
 	{
 		return flags & 2;
 	}
-	bool lucky()
-	{
-		return flags & 4;
-	}
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount & effect;
 	}
+	bool operator<(const BattleStackAttacked &b) const
+	{
+		return stackAttacked < b.stackAttacked;
+	}
 };
 
 struct BattleAttack : public CPackForClient//3006
@@ -693,7 +693,7 @@ struct BattleAttack : public CPackForClient//3006
 	DLL_EXPORT void applyGs(CGameState *gs);
 	void applyCl(CClient *cl);
 
-	BattleStackAttacked bsa;
+	std::set<BattleStackAttacked> bsa;
 	ui32 stackAttacking;
 	ui8 flags;
 
@@ -705,10 +705,19 @@ struct BattleAttack : public CPackForClient//3006
 	{
 		return flags & 2;
 	}
-	bool killed() //if target stack was killed
+	bool lucky()
+	{
+		return flags & 4;
+	}
+	bool unlucky()
 	{
-		return bsa.killed();
+		//TODO: support?
+		return flags & 8;
 	}
+	//bool killed() //if target stack was killed
+	//{
+	//	return bsa.killed();
+	//}
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & bsa & stackAttacking & flags;
@@ -761,11 +770,11 @@ struct SetStackEffect : public CPackForClient //3010
 	DLL_EXPORT void applyGs(CGameState *gs);
 	void applyCl(CClient *cl);
 
-	ui32 stack;
+	std::set<ui32> stacks;
 	CStack::StackEffect effect;
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & stack & effect;
+		h & stacks & effect;
 	}
 };
 

+ 10 - 3
lib/NetPacksLib.cpp

@@ -428,7 +428,8 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
 		attacker->counterAttacks--;
 	if(shot())
 		attacker->shots--;
-	bsa.applyGs(gs);
+	BOOST_FOREACH(BattleStackAttacked &stackAttacked, bsa)
+		stackAttacked.applyGs(gs);
 }
 
 DLL_EXPORT void StartAction::applyGs( CGameState *gs )
@@ -464,8 +465,14 @@ DLL_EXPORT void SpellCasted::applyGs( CGameState *gs )
 
 DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
 {
-	CStack *s = gs->curB->getStack(stack);
-	s->effects.push_back(effect);
+	BOOST_FOREACH(ui32 id, stacks)
+	{
+		CStack *s = gs->curB->getStack(id);
+		if(s)
+			s->effects.push_back(effect);
+		else
+			tlog1 << "Cannot find stack " << id << std::endl;
+	}
 }
 
 DLL_EXPORT void YourTurn::applyGs( CGameState *gs )

+ 8 - 5
map.h

@@ -389,11 +389,14 @@ struct DLL_EXPORT Mapa : public CMapHeader
 			CGObjectInstance *&obj = objects[i];
 			h & obj;
 
-			si32 shlp;
-			//definfo
-			h & (h.saving ? (shlp=obj->defInfo->serial) : shlp); //read / write pos of definfo in defs vector
-			if(!h.saving)
-				obj->defInfo = defy[shlp];
+			if (obj)
+			{
+				si32 shlp;
+				//definfo
+				h & (h.saving ? (shlp=obj->defInfo->serial) : shlp); //read / write pos of definfo in defs vector
+				if(!h.saving)
+					obj->defInfo = defy[shlp];
+			}
 		}
 
 		if(!h.saving)

+ 9 - 7
server/CGameHandler.cpp

@@ -485,14 +485,16 @@ void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def)
 void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
 {
 	bat.stackAttacking = att->ID;
-	bat.bsa.stackAttacked = def->ID;
-	bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot());//counting dealt damage
+	std::set<BattleStackAttacked>::iterator bsa = bat.bsa.insert(BattleStackAttacked()).first;
+
+	bsa->stackAttacked = def->ID;
+	bsa->damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot());//counting dealt damage
 	if(att->Luck() > 0  &&  rand()%24 < att->Luck())
 	{
-		bat.bsa.damageAmount *= 2;
-		bat.bsa.flags |= 4;
+		bsa->damageAmount *= 2;
+		bsa->flags |= 4;
 	}
-	prepareAttacked(bat.bsa,def);
+	prepareAttacked(*bsa,def);
 }
 void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 {
@@ -2226,7 +2228,7 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
 #define SPELL_CAST_TEMPLATE_1(NUMBER, DURATION) SetStackEffect sse; \
 if(getSchoolLevel(h,s) < 3)  /*not expert */ \
 			{ \
-			sse.stack = gs->curB->getStackT(ba.destinationTile)->ID; \
+			sse.stacks.insert(gs->curB->getStackT(ba.destinationTile)->ID); \
 			sse.effect.id = (NUMBER); \
 			sse.effect.level = getSchoolLevel(h,s); \
 			sse.effect.turnsRemain = (DURATION); /*! - any duration */ \
@@ -2241,7 +2243,7 @@ if(getSchoolLevel(h,s) < 3)  /*not expert */ \
 			||(VLC->spellh->spells[ba.additionalInfo].positiveness <= 0 && gs->curB->stacks[it]->owner != h->tempOwner ) \
 			) \
 			{ \
-			sse.stack = gs->curB->stacks[it]->ID; \
+			sse.stacks.insert(gs->curB->stacks[it]->ID); \
 			sse.effect.id = (NUMBER); \
 			sse.effect.level = getSchoolLevel(h,s); \
 			sse.effect.turnsRemain = (DURATION); \