1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

* correct handling of flying creatures in battles

* minor changes
This commit is contained in:
mateuszb 2009-03-07 16:05:53 +00:00
parent 329eab2f6a
commit 9eb6128b27
10 changed files with 144 additions and 83 deletions

View File

@ -466,7 +466,7 @@ void CBattleInterface::show(SDL_Surface * to)
for(size_t v=0; v<stackAliveByHex[b].size(); ++v)
{
int animType = creAnims[stackAliveByHex[b][v]]->getType();
bool incrementFrame = (animCount%(4/animSpeed)==0) && animType!=0 && animType!=5 && animType!=20 && animType!=21 && animType!=3 && animType!=2;
bool incrementFrame = (animCount%(4/animSpeed)==0) && animType!=5 && animType!=20 && animType!=3 && animType!=2;
if(animType == 2)
{
if(standingFrame.find(stackAliveByHex[b][v])!=standingFrame.end())
@ -854,8 +854,9 @@ bool CBattleInterface::reverseCreature(int number, int hex, bool wideTrick)
if(creAnims[number]==NULL)
return false; //there is no such creature
creAnims[number]->setType(8);
int firstFrame = creAnims[number]->getFrame();
for(int g=0; creAnims[number]->getFrame() != creAnims[number]->framesInGroup(8) + firstFrame - 1; ++g)
//int firstFrame = creAnims[number]->getFrame();
//for(int g=0; creAnims[number]->getFrame() != creAnims[number]->framesInGroup(8) + firstFrame - 1; ++g)
while(!creAnims[number]->onLastFrameInGroup())
{
show();
CSDL_Ext::update();
@ -883,8 +884,9 @@ bool CBattleInterface::reverseCreature(int number, int hex, bool wideTrick)
}
creAnims[number]->setType(7);
firstFrame = creAnims[number]->getFrame();
for(int g=0; creAnims[number]->getFrame() != creAnims[number]->framesInGroup(7) + firstFrame - 1; ++g)
//firstFrame = creAnims[number]->getFrame();
//for(int g=0; creAnims[number]->getFrame() != creAnims[number]->framesInGroup(7) + firstFrame - 1; ++g)
while(!creAnims[number]->onLastFrameInGroup())
{
show();
CSDL_Ext::update();
@ -1006,7 +1008,7 @@ void CBattleInterface::stackActivated(int number)
}
}
void CBattleInterface::stackMoved(int number, int destHex, bool endMoving)
void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int distance)
{
bool startMoving = creAnims[number]->getType()==20;
//a few useful variables
@ -1014,6 +1016,10 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving)
int steps = creAnims[number]->framesInGroup(0)*getAnimSpeedMultiplier()-1;
int hexWbase = 44, hexHbase = 42;
bool twoTiles = LOCPLINT->cb->battleGetCreature(number).isDoubleWide();
CStack * movedStack = LOCPLINT->cb->battleGetStackByID(number);
std::pair<int, int> begPosition = CBattleHex::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack->creature);
std::pair<int, int> endPosition = CBattleHex::getXYUnitAnim(destHex, movedStack->attackerOwned, movedStack->creature);
if(startMoving) //animation of starting move; some units don't have this animation (ie. halberdier)
{
@ -1027,78 +1033,102 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving)
}
int mutPos = BattleInfo::mutualPosition(curStackPos, destHex);
float stepX=0.0, stepY=0.0; //how far stack is moved in one frame; calculated later
//reverse unit if necessary
if((begPosition.first > endPosition.first) && creDir[number] == true)
{
switch(mutPos) //reverse unit if necessary
reverseCreature(number, curStackPos, twoTiles);
}
else if ((begPosition.first < endPosition.first) && creDir[number] == false)
{
reverseCreature(number, curStackPos, twoTiles);
}
if(creAnims[number]->getType() != 0)
{
creAnims[number]->setType(0);
}
//unit reversed
//step shift calculation
float posX = creAnims[number]->pos.x, posY = creAnims[number]->pos.y; // for precise calculations ;]
if(mutPos == -1 && movedStack->creature->isFlying())
{
steps *= distance;
stepX = (endPosition.first - (float)begPosition.first)/steps;
stepY = (endPosition.second - (float)begPosition.second)/steps;
}
else
{
switch(mutPos)
{
case 0: case 4: case 5:
if(creDir[number] == true)
reverseCreature(number, curStackPos, twoTiles);
case 0:
stepX = (-1.0)*((float)hexWbase)/(2.0f*steps);
stepY = (-1.0)*((float)hexHbase)/((float)steps);
break;
case 1: case 2: case 3:
if(creDir[number] == false)
reverseCreature(number, curStackPos, twoTiles);
case 1:
stepX = ((float)hexWbase)/(2.0f*steps);
stepY = (-1.0)*((float)hexHbase)/((float)steps);
break;
case 2:
stepX = ((float)hexWbase)/((float)steps);
stepY = 0.0;
break;
case 3:
stepX = ((float)hexWbase)/(2.0f*steps);
stepY = ((float)hexHbase)/((float)steps);
break;
case 4:
stepX = (-1.0)*((float)hexWbase)/(2.0f*steps);
stepY = ((float)hexHbase)/((float)steps);
break;
case 5:
stepX = (-1.0)*((float)hexWbase)/((float)steps);
stepY = 0.0;
break;
}
//moving instructions
float posX = creAnims[number]->pos.x, posY = creAnims[number]->pos.y; // for precise calculations ;]
for(int i=0; i<steps; ++i)
{
switch(mutPos)
{
case 0:
posX -= ((float)hexWbase)/(2.0f*steps);
creAnims[number]->pos.x = posX;
posY -= ((float)hexHbase)/((float)steps);
creAnims[number]->pos.y = posY;
break;
case 1:
posX += ((float)hexWbase)/(2.0f*steps);
creAnims[number]->pos.x = posX;
posY -= ((float)hexHbase)/((float)steps);
creAnims[number]->pos.y = posY;
break;
case 2:
posX += ((float)hexWbase)/((float)steps);
creAnims[number]->pos.x = posX;
break;
case 3:
posX += ((float)hexWbase)/(2.0f*steps);
creAnims[number]->pos.x = posX;
posY += ((float)hexHbase)/((float)steps);
creAnims[number]->pos.y = posY;
break;
case 4:
posX -= ((float)hexWbase)/(2.0f*steps);
creAnims[number]->pos.x = posX;
posY += ((float)hexHbase)/((float)steps);
creAnims[number]->pos.y = posY;
break;
case 5:
posX -= ((float)hexWbase)/((float)steps);
creAnims[number]->pos.x = posX;
break;
}
show();
CSDL_Ext::update();
SDL_framerateDelay(LOCPLINT->mainFPSmng);
if((animCount+1)%(4/animSpeed)==0)
creAnims[number]->incrementFrame();
}
}
//step shifts calculated
//switch(mutPos) //reverse unit if necessary
//{
//case 0: case 4: case 5:
// if(creDir[number] == true)
// reverseCreature(number, curStackPos, twoTiles);
// break;
//case 1: case 2: case 3:
// if(creDir[number] == false)
// reverseCreature(number, curStackPos, twoTiles);
// break;
//}
//moving instructions
for(int i=0; i<steps; ++i)
{
posX += stepX;
creAnims[number]->pos.x = posX;
posY += stepY;
creAnims[number]->pos.y = posY;
show();
CSDL_Ext::update();
SDL_framerateDelay(LOCPLINT->mainFPSmng);
}
//unit moved
if(endMoving) //animation of ending move
{
if(creAnims[number]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier)
{
creAnims[number]->setType(21);
for(int i=0; i<creAnims[number]->framesInGroup(21)*getAnimSpeedMultiplier()-1; ++i)
//for(int i=0; i<creAnims[number]->framesInGroup(21)*getAnimSpeedMultiplier()-1; ++i)
while(!creAnims[number]->onLastFrameInGroup())
{
show();
CSDL_Ext::update();
SDL_framerateDelay(LOCPLINT->mainFPSmng);
if((animCount+1)%(4/animSpeed)==0)
creAnims[number]->incrementFrame();
}
}
creAnims[number]->setType(2); //resetting to default

View File

@ -249,7 +249,7 @@ public:
void stackRemoved(CStack stack); //stack disappeared from batlefiled
//void stackKilled(int ID, int dmg, int killed, int IDby, bool byShooting); //stack has been killed (but corpses remain)
void stackActivated(int number); //active stack has been changed
void stackMoved(int number, int destHex, bool endMoving); //stack with id number moved to destHex
void stackMoved(int number, int destHex, bool endMoving, int distance); //stack with id number moved to destHex
void stacksAreAttacked(std::vector<SStackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(int ID, int dest); //called when stack with id ID is attacking something on hex dest
void newRound(int number); //caled when round is ended; number is the number of round

View File

@ -78,7 +78,7 @@ public:
virtual void battleStackAttacked(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){};
virtual void battleStackMoved(int ID, int dest, int distance){};
virtual void battleSpellCasted(SpellCasted *sc){};
virtual 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
virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
@ -95,7 +95,7 @@ public:
virtual void yourTurn(){};
virtual void heroKilled(const CGHeroInstance*){};
virtual void heroCreated(const CGHeroInstance*){};
virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving){};
virtual void battleStackMoved(int ID, int dest, int distance){};
virtual void battleStackAttacking(int ID, int dest){};
virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting){};
virtual BattleAction activeStack(int stackID) {BattleAction ba; ba.actionType = 3; ba.stackNumber = stackID; return ba;};

View File

@ -333,6 +333,7 @@ signed char BattleInfo::mutualPosition(int hex1, int hex2)
return 3;
return -1;
}
std::vector<int> BattleInfo::neighbouringTiles(int hex)
{
#define CHECK_AND_PUSH(tile) {int hlp = (tile); if(hlp>=0 && hlp<BFIELD_SIZE && (hlp%BFIELD_WIDTH!=16) && hlp%BFIELD_WIDTH) ret.push_back(hlp);}
@ -346,12 +347,25 @@ std::vector<int> BattleInfo::neighbouringTiles(int hex)
#undef CHECK_AND_PUSH
return ret;
}
std::vector<int> BattleInfo::getPath(int start, int dest, bool*accessibility)
std::pair< std::vector<int>, int > BattleInfo::getPath(int start, int dest, bool*accessibility, bool flyingCreature)
{
int predecessor[BFIELD_SIZE]; //for getting the Path
int dist[BFIELD_SIZE]; //calculated distances
makeBFS(start,accessibility,predecessor,dist);
if(flyingCreature)
{
bool acc[BFIELD_SIZE]; //full accessibility table
for(int b=0; b<BFIELD_SIZE; ++b) //initialization of acc
{
acc[b] = true;
}
makeBFS(start, acc, predecessor, dist);
}
else
{
makeBFS(start, accessibility, predecessor, dist);
}
//making the Path
std::vector<int> path;
@ -361,7 +375,8 @@ std::vector<int> BattleInfo::getPath(int start, int dest, bool*accessibility)
path.push_back(curElem);
curElem = predecessor[curElem];
}
return path;
return std::make_pair(path, dist[dest]);
}
CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S)

View File

@ -118,7 +118,7 @@ struct DLL_EXPORT BattleInfo
void getAccessibilityMap(bool *accessibility, int stackToOmmit=-1); //send pointer to at least 187 allocated bytes
void getAccessibilityMapForTwoHex(bool *accessibility, bool atackerSide, int stackToOmmit=-1, bool addOccupiable = false); //send pointer to at least 187 allocated bytes
void makeBFS(int start, bool*accessibility, int *predecessor, int *dists); //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result
std::vector<int> getPath(int start, int dest, bool*accessibility);
std::pair< std::vector<int>, int > getPath(int start, int dest, bool*accessibility, bool flyingCreature); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes
std::vector<int> getAccessibility(int stackID, bool addOccupiable); //returns vector of accessible tiles (taking into account the creature range)
bool isStackBlocked(int ID); //returns true if there is neighbouring enemy stack

View File

@ -2215,10 +2215,10 @@ void CPlayerInterface::battleResultQuited()
LOCPLINT->showingDialog->setn(false);
}
void CPlayerInterface::battleStackMoved(int ID, int dest)
void CPlayerInterface::battleStackMoved(int ID, int dest, int distance)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->stackMoved(ID, dest, dest==curAction->destinationTile);
battleInt->stackMoved(ID, dest, dest==curAction->destinationTile, distance);
}
void CPlayerInterface::battleSpellCasted(SpellCasted *sc)
{

View File

@ -490,7 +490,7 @@ public:
void battleEnd(BattleResult *br);
void battleResultQuited();
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);
void battleStackMoved(int ID, int dest, int distance);
void battleSpellCasted(SpellCasted *sc);
void battleStackAttacked(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

View File

@ -520,9 +520,9 @@ void CClient::process(int what)
*serv >> br;
tlog5 << "Stack "<<br.stack <<" moves to the tile "<<br.tile<<std::endl;
if(playerint.find(gs->curB->side1) != playerint.end())
playerint[gs->curB->side1]->battleStackMoved(br.stack,br.tile);
playerint[gs->curB->side1]->battleStackMoved(br.stack, br.tile, br.distance);
if(playerint.find(gs->curB->side2) != playerint.end())
playerint[gs->curB->side2]->battleStackMoved(br.stack,br.tile);
playerint[gs->curB->side2]->battleStackMoved(br.stack, br.tile, br.distance);
gs->apply(&br);
break;
}

View File

@ -520,11 +520,11 @@ struct BattleResult : public CPack<BattleResult>//3003
struct BattleStackMoved : public CPack<BattleStackMoved>//3004
{
ui32 stack, tile;
ui32 stack, tile, distance;
BattleStackMoved(){type = 3004;};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stack & tile;
h & stack & tile & distance;
}
};

View File

@ -1574,15 +1574,31 @@ void CGameHandler::moveStack(int stack, int dest)
//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
// return false;
std::vector<int> path = gs->curB->getPath(curStack->position,dest,accessibility);
int tilesToMove = std::max((int)(path.size() - curStack->speed()), 0);
for(int v=path.size()-1; v>=tilesToMove; --v)
std::pair< std::vector<int>, int > path = gs->curB->getPath(curStack->position, dest, accessibility, curStack->creature->isFlying());
if(curStack->creature->isFlying())
{
//inform clients about move
BattleStackMoved sm;
sm.stack = curStack->ID;
sm.tile = path[v];
sendAndApply(&sm);
if(path.second <= curStack->speed() && path.first.size() > 0)
{
//inform clients about move
BattleStackMoved sm;
sm.stack = curStack->ID;
sm.tile = path.first[0];
sm.distance = path.second;
sendAndApply(&sm);
}
}
else //for non-flying creatures
{
int tilesToMove = std::max((int)(path.first.size() - curStack->speed()), 0);
for(int v=path.first.size()-1; v>=tilesToMove; --v)
{
//inform clients about move
BattleStackMoved sm;
sm.stack = curStack->ID;
sm.tile = path.first[v];
sm.distance = path.second;
sendAndApply(&sm);
}
}
}
CGameHandler::CGameHandler(void)