| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 | #include "CGameState.h"#include "CGameInterface.h"#include "CPlayerInterface.h"#include <algorithm>#include "SDL_Thread.h"#include "SDL_Extensions.h"#include <queue>class CMP_stack{public:	bool operator ()(const CStack* a, const CStack* b)	{		return (a->creature->speed)>(b->creature->speed);	}} cmpst ;void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CArmedInstance *hero1, CArmedInstance *hero2){	curB = new BattleInfo();	std::vector<CStack*> & stacks = (curB->stacks);	curB->army1=army1;	curB->army2=army2;	curB->hero1=dynamic_cast<CGHeroInstance*>(hero1);	curB->hero2=dynamic_cast<CGHeroInstance*>(hero2);	curB->side1=(hero1)?(hero1->tempOwner):(-1);	curB->side2=(hero2)?(hero2->tempOwner):(-1);	curB->round = -2;	curB->stackActionPerformed = false;	for(std::map<int,std::pair<CCreature*,int> >::iterator i = army1->slots.begin(); i!=army1->slots.end(); i++)	{		stacks.push_back(new CStack(i->second.first,i->second.second,0, stacks.size(), true));		stacks[stacks.size()-1]->ID = stacks.size()-1;	}	//initialization of positions	switch(army1->slots.size()) //for attacker	{	case 0:		break;	case 1:		stacks[0]->position = 86; //6		break;	case 2:		stacks[0]->position = 35; //3		stacks[1]->position = 137; //9		break;	case 3:		stacks[0]->position = 35; //3		stacks[1]->position = 86; //6		stacks[2]->position = 137; //9		break;	case 4:		stacks[0]->position = 1; //1		stacks[1]->position = 69; //5		stacks[2]->position = 103; //7		stacks[3]->position = 171; //11		break;	case 5:		stacks[0]->position = 1; //1		stacks[1]->position = 35; //3		stacks[2]->position = 86; //6		stacks[3]->position = 137; //9		stacks[4]->position = 171; //11		break;	case 6:		stacks[0]->position = 1; //1		stacks[1]->position = 35; //3		stacks[2]->position = 69; //5		stacks[3]->position = 103; //7		stacks[4]->position = 137; //9		stacks[5]->position = 171; //11		break;	case 7:		stacks[0]->position = 1; //1		stacks[1]->position = 35; //3		stacks[2]->position = 69; //5		stacks[3]->position = 86; //6		stacks[4]->position = 103; //7		stacks[5]->position = 137; //9		stacks[6]->position = 171; //11		break;	default: //fault		break;	}	for(std::map<int,std::pair<CCreature*,int> >::iterator i = army2->slots.begin(); i!=army2->slots.end(); i++)		stacks.push_back(new CStack(i->second.first,i->second.second,1, stacks.size(), false));	switch(army2->slots.size()) //for defender	{	case 0:		break;	case 1:		stacks[0+army1->slots.size()]->position = 100; //6		break;	case 2:		stacks[0+army1->slots.size()]->position = 49; //3		stacks[1+army1->slots.size()]->position = 151; //9		break;	case 3:		stacks[0+army1->slots.size()]->position = 49; //3		stacks[1+army1->slots.size()]->position = 100; //6		stacks[2+army1->slots.size()]->position = 151; //9		break;	case 4:		stacks[0+army1->slots.size()]->position = 15; //1		stacks[1+army1->slots.size()]->position = 83; //5		stacks[2+army1->slots.size()]->position = 117; //7		stacks[3+army1->slots.size()]->position = 185; //11		break;	case 5:		stacks[0+army1->slots.size()]->position = 15; //1		stacks[1+army1->slots.size()]->position = 49; //3		stacks[2+army1->slots.size()]->position = 100; //6		stacks[3+army1->slots.size()]->position = 151; //9		stacks[4+army1->slots.size()]->position = 185; //11		break;	case 6:		stacks[0+army1->slots.size()]->position = 15; //1		stacks[1+army1->slots.size()]->position = 49; //3		stacks[2+army1->slots.size()]->position = 83; //5		stacks[3+army1->slots.size()]->position = 117; //7		stacks[4+army1->slots.size()]->position = 151; //9		stacks[5+army1->slots.size()]->position = 185; //11		break;	case 7:		stacks[0+army1->slots.size()]->position = 15; //1		stacks[1+army1->slots.size()]->position = 49; //3		stacks[2+army1->slots.size()]->position = 83; //5		stacks[3+army1->slots.size()]->position = 100; //6		stacks[4+army1->slots.size()]->position = 117; //7		stacks[5+army1->slots.size()]->position = 151; //9		stacks[6+army1->slots.size()]->position = 185; //11		break;	default: //fault		break;	}	for(int g=0; g<stacks.size(); ++g) //shifting positions of two-hex creatures	{		if((stacks[g]->position%17)==1 && stacks[g]->creature->isDoubleWide())		{			stacks[g]->position += 1;		}		else if((stacks[g]->position%17)==15 && stacks[g]->creature->isDoubleWide())		{			stacks[g]->position -= 1;		}	}	std::stable_sort(stacks.begin(),stacks.end(),cmpst);	//for start inform players about battle	for(std::map<int, PlayerState>::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing	{		if (j->first > PLAYER_LIMIT)			break;		if(j->second.fogOfWarMap[tile.x][tile.y][tile.z])		{ //player should be notified			tribool side = tribool::indeterminate_value;			if(j->first == curB->side1) //player is attacker				side = false;			else if(j->first == curB->side2) //player is defender				side = true;			else 				return; //no witnesses			if(CGI->playerint[j->second.serial]->human)			{				((CPlayerInterface*)( CGI->playerint[j->second.serial] ))->battleStart(army1, army2, tile, curB->hero1, curB->hero2, side);			}			else			{				//CGI->playerint[j->second.serial]->battleStart(army1, army2, tile, curB->hero1, curB->hero2, side);			}		}	}	curB->round++;	if( (curB->hero1 && curB->hero1->getSecSkillLevel(19)>=0) || ( curB->hero2 && curB->hero2->getSecSkillLevel(19)>=0)  )//someone has tactics	{		//TODO: wywolania dla rundy -1, ograniczenie pola ruchu, etc	}	curB->round++;	//SDL_Thread * eventh = SDL_CreateThread(battleEventThread, NULL);	while(true) //do zwyciestwa jednej ze stron	{		for(int i=0;i<stacks.size();i++)		{			curB->activeStack = i;			curB->stackActionPerformed = false;			if(stacks[i]->alive) //indicate posiibility of making action for this unit			{				unsigned char owner = (stacks[i]->owner)?(hero2 ? hero2->tempOwner : 255):(hero1->tempOwner);				unsigned char serialOwner = -1;				for(int g=0; g<CGI->playerint.size(); ++g)				{					if(CGI->playerint[g]->playerID == owner)					{						serialOwner = g;						break;					}				}				if(serialOwner==255) //neutral unit				{				}				else if(CGI->playerint[serialOwner]->human)				{					BattleAction ba = ((CPlayerInterface*)CGI->playerint[serialOwner])->activeStack(stacks[i]->ID);					switch(ba.actionType)					{					case 3: //defend						{							break;						}					case 4: //retreat/flee						{							for(int v=0; v<CGI->playerint.size(); ++v) //tell about the end of this battle to interfaces								CGI->playerint[v]->battleEnd(army1, army2, hero1, hero2, std::vector<int>(), 0, false);							return; //return from this function, I hope it'll work							break;						}					case 6: //walk or attack						{							battleMoveCreatureStack(ba.stackNumber, ba.destinationTile);							break;						}					}				}				else				{					//CGI->playerint[serialOwner]->activeStack(stacks[i]->ID);				}			}			//sprawdzic czy po tej akcji ktoras strona nie wygrala bitwy		}		SDL_Delay(50);	}	for(int i=0;i<stacks.size();i++)		delete stacks[i];	delete curB;	curB = NULL;}bool CGameState::battleMoveCreatureStack(int ID, int dest){	//first checks	if(curB->stackActionPerformed) //because unit cannot be moved more than once		return false;	bool stackAtEnd = false; //true if there is a stack at the end of the path (we should attack it)	unsigned char owner = -1; //owner moved of unit	for(int g=0; g<curB->stacks.size(); ++g)	{		if(curB->stacks[g]->position == dest)		{			stackAtEnd = true;			break;		}	}	for(int g=0; g<curB->stacks.size(); ++g)	{		if(curB->stacks[g]->ID == ID)		{			owner = curB->stacks[g]->owner;			break;		}	}	//selecting moved stack	CStack * curStack = NULL;	for(int y=0; y<curB->stacks.size(); ++y)	{		if(curB->stacks[y]->ID == ID)		{			curStack = curB->stacks[y];			break;		}	}	if(!curStack)		return false;	//initing necessary tables	bool accessibility[187]; //accesibility of hexes	for(int k=0; k<187; k++)		accessibility[k] = true;	for(int g=0; g<curB->stacks.size(); ++g)	{		//if(curB->stacks[g]->owner == owner) //we don't want to lock enemy's positions		{			accessibility[curB->stacks[g]->position] = false;			if(curB->stacks[g]->creature->isDoubleWide()) //if it's a double hex creature			{				if(curB->stacks[g]->attackerOwned)					accessibility[curB->stacks[g]->position-1] = false;				else					accessibility[curB->stacks[g]->position+1] = false;			}		}	}	int predecessor[187]; //for getting the Path	for(int b=0; b<187; ++b)		predecessor[b] = -1;	//bfsing	int dists[187]; //calculated distances	std::queue<int> hexq; //bfs queue	hexq.push(curStack->position);	for(int g=0; g<187; ++g)		dists[g] = 100000000;	dists[hexq.front()] = 0;	int curNext = -1; //for bfs loop only (helper var)	while(!hexq.empty()) //bfs loop	{		int curHex = hexq.front();		hexq.pop();		curNext = curHex - ( (curHex/17)%2 ? 18 : 17 );		if((curNext > 0) && (accessibility[curNext] || curNext==dest) && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //top left		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;			predecessor[curNext] = curHex;		}		curNext = curHex - ( (curHex/17)%2 ? 17 : 16 );		if((curNext > 0) && (accessibility[curNext] || curNext==dest)  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //top right		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;			predecessor[curNext] = curHex;		}		curNext = curHex - 1;		if((curNext > 0) && (accessibility[curNext] || curNext==dest)  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //left		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;			predecessor[curNext] = curHex;		}		curNext = curHex + 1;		if((curNext < 187) && (accessibility[curNext] || curNext==dest)  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //right		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;			predecessor[curNext] = curHex;		}		curNext = curHex + ( (curHex/17)%2 ? 16 : 17 );		if((curNext < 187) && (accessibility[curNext] || curNext==dest)  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //bottom left		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;			predecessor[curNext] = curHex;		}		curNext = curHex + ( (curHex/17)%2 ? 17 : 18 );		if((curNext < 187) && (accessibility[curNext] || curNext==dest)  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //bottom right		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;			predecessor[curNext] = curHex;		}	}	//following the Path	if(dists[dest] > curStack->creature->speed)		return false;	std::vector<int> path;	int curElem = dest;	while(curElem!=curStack->position)	{		path.push_back(curElem);		curElem = predecessor[curElem];	}	for(int v=path.size()-1; v>=0; --v)	{		if(v!=0 || !stackAtEnd) //it's not the last step		{			LOCPLINT->battleStackMoved(ID, path[v], v==path.size()-1, v==0);			curStack->position = path[v];		}		else //if it's last step and we should attack unit at the end		{			LOCPLINT->battleStackAttacking(ID, path[v]);		}	}	curB->stackActionPerformed = true;	LOCPLINT->actionFinished(BattleAction());	return true;}std::vector<int> CGameState::battleGetRange(int ID){	int initialPlace=-1; //position of unit	int radius=-1; //range of unit	unsigned char owner = -1; //owner of unit	for(int g=0; g<curB->stacks.size(); ++g)	{		if(curB->stacks[g]->ID == ID)		{			initialPlace = curB->stacks[g]->position;			radius = curB->stacks[g]->creature->speed;			owner = curB->stacks[g]->owner;			break;		}	}	bool accessibility[187]; //accesibility of hexes	for(int k=0; k<187; k++)		accessibility[k] = true;	for(int g=0; g<curB->stacks.size(); ++g)	{		if(curB->stacks[g]->owner == owner) //we don't want to lock enemy's positions		{			accessibility[curB->stacks[g]->position] = false;			if(curB->stacks[g]->creature->isDoubleWide()) //if it's a double hex creature			{				if(curB->stacks[g]->attackerOwned)					accessibility[curB->stacks[g]->position-1] = false;				else					accessibility[curB->stacks[g]->position+1] = false;			}		}	}	int dists[187]; //calculated distances	std::queue<int> hexq; //bfs queue	hexq.push(initialPlace);	for(int g=0; g<187; ++g)		dists[g] = 100000000;	dists[initialPlace] = 0;	int curNext = -1; //for bfs loop only (helper var)	while(!hexq.empty()) //bfs loop	{		int curHex = hexq.front();		hexq.pop();		curNext = curHex - ( (curHex/17)%2 ? 18 : 17 );		if((curNext > 0) && accessibility[curNext]  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //top left		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;		}		curNext = curHex - ( (curHex/17)%2 ? 17 : 16 );		if((curNext > 0) && accessibility[curNext]  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //top right		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;		}		curNext = curHex - 1;		if((curNext > 0) && accessibility[curNext]  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //left		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;		}		curNext = curHex + 1;		if((curNext < 187) && accessibility[curNext]  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //right		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;		}		curNext = curHex + ( (curHex/17)%2 ? 16 : 17 );		if((curNext < 187) && accessibility[curNext]  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //bottom left		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;		}		curNext = curHex + ( (curHex/17)%2 ? 17 : 18 );		if((curNext < 187) && accessibility[curNext]  && (dists[curHex] + 1 < dists[curNext]) && (curNext)%17!=0 && (curNext)%17!=16) //bottom right		{			hexq.push(curNext);			dists[curNext] = dists[curHex] + 1;		}	}	std::vector<int> ret;	for(int i=0; i<187; ++i)	{		if(dists[i]<=radius)		{			ret.push_back(i);		}	}	return ret;}
 |