From 9eb6128b27ac816e6e26901e44f7f70ba818a66b Mon Sep 17 00:00:00 2001 From: mateuszb Date: Sat, 7 Mar 2009 16:05:53 +0000 Subject: [PATCH] * correct handling of flying creatures in battles * minor changes --- CBattleInterface.cpp | 152 ++++++++++++++++++++++++---------------- CBattleInterface.h | 2 +- CGameInterface.h | 4 +- CGameState.cpp | 21 +++++- CGameState.h | 2 +- CPlayerInterface.cpp | 4 +- CPlayerInterface.h | 2 +- client/Client.cpp | 4 +- lib/NetPacks.h | 4 +- server/CGameHandler.cpp | 32 ++++++--- 10 files changed, 144 insertions(+), 83 deletions(-) diff --git a/CBattleInterface.cpp b/CBattleInterface.cpp index b6d1841cf..71cd8e1b7 100644 --- a/CBattleInterface.cpp +++ b/CBattleInterface.cpp @@ -466,7 +466,7 @@ void CBattleInterface::show(SDL_Surface * to) for(size_t v=0; vgetType(); - 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 begPosition = CBattleHex::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack->creature); + std::pair 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; ipos.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; ipos.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; iframesInGroup(21)*getAnimSpeedMultiplier()-1; ++i) + + //for(int i=0; iframesInGroup(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 diff --git a/CBattleInterface.h b/CBattleInterface.h index ea1a3af74..fcf6dde57 100644 --- a/CBattleInterface.h +++ b/CBattleInterface.h @@ -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 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 diff --git a/CGameInterface.h b/CGameInterface.h index 3d87d5c69..366788c46 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -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 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;}; diff --git a/CGameState.cpp b/CGameState.cpp index 6241d801e..567cf5c35 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -333,6 +333,7 @@ signed char BattleInfo::mutualPosition(int hex1, int hex2) return 3; return -1; } + std::vector BattleInfo::neighbouringTiles(int hex) { #define CHECK_AND_PUSH(tile) {int hlp = (tile); if(hlp>=0 && hlp BattleInfo::neighbouringTiles(int hex) #undef CHECK_AND_PUSH return ret; } -std::vector BattleInfo::getPath(int start, int dest, bool*accessibility) +std::pair< std::vector, 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 path; @@ -361,7 +375,8 @@ std::vector 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) diff --git a/CGameState.h b/CGameState.h index 79a6639f3..14732dbce 100644 --- a/CGameState.h +++ b/CGameState.h @@ -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 getPath(int start, int dest, bool*accessibility); + std::pair< std::vector, int > getPath(int start, int dest, bool*accessibility, bool flyingCreature); //returned value: pair; length may be different than number of elements in path since flying vreatures jump between distant hexes std::vector 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 diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index cf09006bf..db3f9f7cd 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -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 un(*pim); - battleInt->stackMoved(ID, dest, dest==curAction->destinationTile); + battleInt->stackMoved(ID, dest, dest==curAction->destinationTile, distance); } void CPlayerInterface::battleSpellCasted(SpellCasted *sc) { diff --git a/CPlayerInterface.h b/CPlayerInterface.h index 3bdcea05e..7fcadb84b 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -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 diff --git a/client/Client.cpp b/client/Client.cpp index 78b44098d..ffb2a68c9 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -520,9 +520,9 @@ void CClient::process(int what) *serv >> br; tlog5 << "Stack "<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; } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index d23c8dcd3..f7d5408c6 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -520,11 +520,11 @@ struct BattleResult : public CPack//3003 struct BattleStackMoved : public CPack//3004 { - ui32 stack, tile; + ui32 stack, tile, distance; BattleStackMoved(){type = 3004;}; template void serialize(Handler &h, const int version) { - h & stack & tile; + h & stack & tile & distance; } }; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index bfd4aeaec..d2b9597a2 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -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 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 > 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)