diff --git a/CBattleInterface.cpp b/CBattleInterface.cpp index 57c045367..c25a969e5 100644 --- a/CBattleInterface.cpp +++ b/CBattleInterface.cpp @@ -9,8 +9,11 @@ #include "CCallback.h" #include "CGameState.h" #include +#include extern SDL_Surface * screen; +extern TTF_Font * GEOR13; +extern SDL_Color zwykly; SDL_Surface * CBattleInterface::cellBorder, * CBattleInterface::cellShade; CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2) @@ -22,10 +25,11 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C std::map stacks = LOCPLINT->cb->battleGetStacks(); for(std::map::iterator b=stacks.begin(); b!=stacks.end(); ++b) { - std::pair coords = CBattleHex::getXYUnitAnim(b->second.position, b->second.owner == attackingHeroInstance->tempOwner); + std::pair coords = CBattleHex::getXYUnitAnim(b->second.position, b->second.owner == attackingHeroInstance->tempOwner, b->second.creature); creAnims[b->second.ID] = (new CCreatureAnimation(b->second.creature->animDefName)); creAnims[b->second.ID]->setType(2); creAnims[b->second.ID]->pos = genRect(creAnims[b->second.ID]->fullHeight, creAnims[b->second.ID]->fullWidth, coords.first, coords.second); + creDir[b->second.ID] = b->second.owner==attackingHeroInstance->tempOwner; } //preparing menu background and terrain std::vector< std::string > & backref = CGI->mh->battleBacks[ LOCPLINT->cb->battleGetBattlefieldType() ]; @@ -33,6 +37,22 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C menu = CGI->bitmaph->loadBitmap("CBAR.BMP"); CSDL_Ext::blueToPlayersAdv(menu, hero1->tempOwner); + //preparing graphics for displaying amounts of creatures + amountBasic = CGI->bitmaph->loadBitmap("CMNUMWIN.BMP"); + amountNormal = CGI->bitmaph->loadBitmap("CMNUMWIN.BMP"); + CSDL_Ext::alphaTransform(amountNormal); + for(int g=0; gformat->palette->ncolors; ++g) + { + if((amountNormal->format->palette->colors+g)->b != 132 && + (amountNormal->format->palette->colors+g)->g != 231 && + (amountNormal->format->palette->colors+g)->r != 255) //it's not yellow border + { + (amountNormal->format->palette->colors+g)->r = (float)((amountNormal->format->palette->colors+g)->r) * 0.54f; + (amountNormal->format->palette->colors+g)->g = (float)((amountNormal->format->palette->colors+g)->g) * 0.19f; + (amountNormal->format->palette->colors+g)->b = (float)((amountNormal->format->palette->colors+g)->b) * 0.93f; + } + } + //blitting menu background and terrain blitAt(background, 0, 0); blitAt(menu, 0, 556); @@ -206,15 +226,68 @@ void CBattleInterface::show(SDL_Surface * to) defendingHero->show(to); //showing units //a lot of work... - for(std::map::iterator j=creAnims.begin(); j!=creAnims.end(); ++j) + int stackByHex[187]; + for(int b=0; b<187; ++b) + stackByHex[b] = -1; + for(std::map::iterator j=stacks.begin(); j!=stacks.end(); ++j) { - j->second->nextFrame(to, j->second->pos.x, j->second->pos.y, stacks[j->first].owner == attackingHeroInstance->tempOwner, animCount%2==0 || j->second->getType()==0, j->first==activeStack); //increment always when moving + stackByHex[j->second.position] = j->second.ID; + } + for(int b=0; b<187; ++b) + { + if(stackByHex[b]!=-1) + { + creAnims[stackByHex[b]]->nextFrame(to, creAnims[stackByHex[b]]->pos.x, creAnims[stackByHex[b]]->pos.y, creDir[stackByHex[b]], animCount%2==0 || creAnims[stackByHex[b]]->getType()==0, stackByHex[b]==activeStack); //increment always when moving + //printing amount + if(stacks[stackByHex[b]].attackerOwned) + { + CSDL_Ext::blit8bppAlphaTo24bpp(amountNormal, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[stackByHex[b]]->pos.x + 220, creAnims[stackByHex[b]]->pos.y + 260)); + std::stringstream ss; + ss<pos.x + 220 + 14, creAnims[stackByHex[b]]->pos.y + 260 + 4, GEOR13, 20, zwykly, to); + } + else + { + CSDL_Ext::blit8bppAlphaTo24bpp(amountNormal, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[stackByHex[b]]->pos.x + 202, creAnims[stackByHex[b]]->pos.y + 260)); + std::stringstream ss; + ss<pos.x + 202 + 14, creAnims[stackByHex[b]]->pos.y + 260 + 4, GEOR13, 20, zwykly, to); + } + } } //units shown CSDL_Ext::update(); } +bool CBattleInterface::reverseCreature(int number, int hex) +{ + if(creAnims[number]==NULL) + return false; //there is no such creature + creAnims[number]->setType(8); + for(int g=0; gframesInGroup(8); ++g) + { + show(); + SDL_framerateDelay(LOCPLINT->mainFPSmng); + } + creDir[number] = !creDir[number]; + + CStack curs = LOCPLINT->cb->battleGetStackByID(number); + std::pair coords = CBattleHex::getXYUnitAnim(hex, creDir[number], curs.creature); + creAnims[number]->pos.x = coords.first; + creAnims[number]->pos.y = coords.second; + + creAnims[number]->setType(7); + for(int g=0; gframesInGroup(7); ++g) + { + show(); + SDL_framerateDelay(LOCPLINT->mainFPSmng); + } + creAnims[number]->setType(2); + + return true; +} + void CBattleInterface::bOptionsf() { } @@ -270,6 +343,7 @@ void CBattleInterface::newStack(CStack stack) { creAnims[stack.ID] = new CCreatureAnimation(stack.creature->animDefName); creAnims[stack.ID]->setType(2); + creDir[stack.ID] = stack.owner==attackingHeroInstance->tempOwner; } void CBattleInterface::stackRemoved(CStack stack) @@ -284,11 +358,49 @@ void CBattleInterface::stackActivated(int number) activeStack = number; } -void CBattleInterface::stackMoved(int number, int destHex) +void CBattleInterface::stackMoved(int number, int destHex, bool startMoving, bool endMoving) { int curStackPos = LOCPLINT->cb->battleGetPos(number); - int steps = 6; + int steps = creAnims[number]->framesInGroup(0); int hexWbase = 44, hexHbase = 42; + + if(startMoving) //animation of starting move + { + for(int i=0; iframesInGroup(20); ++i) + { + show(); + SDL_framerateDelay(LOCPLINT->mainFPSmng); + } + } + + switch(CBattleHex::mutualPosition(curStackPos, destHex)) //reverse unit if necessary + { + case 0: + if(creDir[number] == true) + reverseCreature(number, curStackPos); + break; + case 1: + if(creDir[number] == false) + reverseCreature(number, curStackPos); + break; + case 2: + if(creDir[number] == false) + reverseCreature(number, curStackPos); + break; + case 3: + if(creDir[number] == false) + reverseCreature(number, curStackPos); + break; + case 4: + if(creDir[number] == true) + reverseCreature(number, curStackPos); + break; + case 5: + if(creDir[number] == true) + reverseCreature(number, curStackPos); + break; + } + //moving instructions creAnims[number]->setType(0); for(int i=0; imainFPSmng); } + + if(endMoving) //animation of starting move + { + for(int i=0; iframesInGroup(21); ++i) + { + show(); + SDL_framerateDelay(LOCPLINT->mainFPSmng); + } + } - creAnims[number]->setType(2); //resetting to delault + creAnims[number]->setType(2); //resetting to default CStack curs = LOCPLINT->cb->battleGetStackByID(number); + if(endMoving) //resetting to default + { + if(creDir[number] != (curs.owner == attackingHeroInstance->tempOwner)) + reverseCreature(number, destHex); + //creDir[number] = (curs.owner == attackingHeroInstance->tempOwner); + } - std::pair coords = CBattleHex::getXYUnitAnim(destHex, curs.owner == attackingHeroInstance->tempOwner); + std::pair coords = CBattleHex::getXYUnitAnim(destHex, creDir[number], curs.creature); creAnims[number]->pos.x = coords.first; creAnims[number]->pos.y = coords.second; } @@ -360,6 +487,20 @@ void CBattleInterface::showRange(SDL_Surface * to, int ID) void CBattleHero::show(SDL_Surface *to) { + //animation of flag + if(flip) + { + CSDL_Ext::blit8bppAlphaTo24bpp(flag->ourImages[flagAnim].bitmap, NULL, screen, &genRect(flag->ourImages[flagAnim].bitmap->h, flag->ourImages[flagAnim].bitmap->w, 752, 39)); + } + else + { + CSDL_Ext::blit8bppAlphaTo24bpp(flag->ourImages[flagAnim].bitmap, NULL, screen, &genRect(flag->ourImages[flagAnim].bitmap->h, flag->ourImages[flagAnim].bitmap->w, 31, 39)); + } + { + ++flagAnim; + flagAnim %= flag->ourImages.size(); + } + //animation of hero int tick=-1; for(int i=0; iourImages.size(); ++i) { @@ -377,18 +518,6 @@ void CBattleHero::show(SDL_Surface *to) break; } } - if(flip) - { - CSDL_Ext::blit8bppAlphaTo24bpp(flag->ourImages[flagAnim].bitmap, NULL, screen, &genRect(flag->ourImages[flagAnim].bitmap->h, flag->ourImages[flagAnim].bitmap->w, 752, 39)); - } - else - { - CSDL_Ext::blit8bppAlphaTo24bpp(flag->ourImages[flagAnim].bitmap, NULL, screen, &genRect(flag->ourImages[flagAnim].bitmap->h, flag->ourImages[flagAnim].bitmap->w, 31, 39)); - } - { - ++flagAnim; - flagAnim %= flag->ourImages.size(); - } } CBattleHero::CBattleHero(std::string defName, int phaseG, int imageG, bool flipG, unsigned char player): phase(phaseG), image(imageG), flip(flipG), flagAnim(0) @@ -421,7 +550,7 @@ CBattleHero::~CBattleHero() delete flag; } -std::pair CBattleHex::getXYUnitAnim(int hexNum, bool attacker) +std::pair CBattleHex::getXYUnitAnim(int hexNum, bool attacker, CCreature * creature) { std::pair ret = std::make_pair(-500, -500); //returned value ret.second = -139 + 42 * (hexNum/17); //counting y @@ -434,6 +563,18 @@ std::pair CBattleHex::getXYUnitAnim(int hexNum, bool attacker) { ret.first = -219 + 22 * ( ((hexNum/17) + 1)%2 ) + 44 * (hexNum % 17); } + //shifting position for double - hex creatures + if(creature->isDoubleWide()) + { + if(attacker) + { + ret.first -= 42; + } + else + { + ret.first += 42; + } + } //returning return ret; } diff --git a/CBattleInterface.h b/CBattleInterface.h index 6bc2e8ff3..9d121c711 100644 --- a/CBattleInterface.h +++ b/CBattleInterface.h @@ -32,7 +32,7 @@ public: //CStack * ourStack; bool hovered, strictHovered; CBattleInterface * myInterface; //interface that owns me - static std::pair getXYUnitAnim(int hexNum, bool attacker); //returns (x, y) of left top corner of animation + static std::pair getXYUnitAnim(int hexNum, bool attacker, CCreature * creature); //returns (x, y) of left top corner of animation static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left) //for user interactions void hover (bool on); @@ -51,13 +51,14 @@ class CBattleObstacle class CBattleInterface : public IActivable, public IShowable { private: - SDL_Surface * background, * menu; + SDL_Surface * background, * menu, * amountBasic, * amountNormal; AdventureMapButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell, * bWait, * bDefence, * bConsoleUp, * bConsoleDown; CBattleHero * attackingHero, * defendingHero; CCreatureSet * army1, * army2; //fighting armies CGHeroInstance * attackingHeroInstance, * defendingHeroInstance; std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID) + std::map< int, bool > creDir; // unsigned char animCount; int activeStack; //number of active stack; -1 - no one void showRange(SDL_Surface * to, int ID); //show helper funtion ot mark range of a unit @@ -88,12 +89,13 @@ public: void activate(); void deactivate(); void show(SDL_Surface * to = NULL); + bool reverseCreature(int number, int hex); //reverses animation of given creature playing animation of reversing //call-ins void newStack(CStack stack); //new stack appeared on battlefield void stackRemoved(CStack stack); //stack disappeared from batlefiled void stackActivated(int number); //active stack has been changed - void stackMoved(int number, int destHex); //stack with id number moved to destHex + void stackMoved(int number, int destHex, bool startMoving, bool endMoving); //stack with id number moved to destHex void stackAttacking(int ID, int dest); //called when stack with id ID is attacking something on hex dest void turnEnded(); //caled when current unit cannot get new orders void hexLclicked(int whichOne); //hex only call-in diff --git a/CGameInterface.h b/CGameInterface.h index ce60e213e..5b65d9242 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -58,7 +58,7 @@ public: virtual void actionFinished(BattleAction action){};//occurs AFTER every action taken by any stack or by the hero virtual void activeStack(int stackID){}; //called when it's turn of that stack virtual void battleEnd(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, std::vector capturedArtifacts, int expForWinner, bool winner){}; - virtual void battleStackMoved(int ID, int dest)=0; + virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving)=0; // }; @@ -74,6 +74,6 @@ public: virtual void yourTurn(){}; virtual void heroKilled(const CGHeroInstance*){}; virtual void heroCreated(const CGHeroInstance*){}; - virtual void battleStackMoved(int ID, int dest){}; + virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving){}; }; #endif //CGAMEINTERFACE_H \ No newline at end of file diff --git a/CGameState.cpp b/CGameState.cpp index db8e3689e..8e2c371a0 100644 --- a/CGameState.cpp +++ b/CGameState.cpp @@ -12,7 +12,7 @@ class CMP_stack public: bool operator ()(const CStack* a, const CStack* b) { - return (a->creature->speed)<(b->creature->speed); + return (a->creature->speed)>(b->creature->speed); } } cmpst ; @@ -31,7 +31,7 @@ void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, C curB->stackActionPerformed = false; for(std::map >::iterator i = army1->slots.begin(); i!=army1->slots.end(); i++) { - stacks.push_back(new CStack(i->second.first,i->second.second,0, stacks.size())); + 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 @@ -85,8 +85,8 @@ void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, C break; } for(std::map >::iterator i = army2->slots.begin(); i!=army2->slots.end(); i++) - stacks.push_back(new CStack(i->second.first,i->second.second,1, stacks.size())); - switch(army2->slots.size()) //for attacker + stacks.push_back(new CStack(i->second.first,i->second.second,1, stacks.size(), false)); + switch(army2->slots.size()) //for defender { case 0: break; @@ -135,6 +135,17 @@ void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, C default: //fault break; } + for(int g=0; gposition%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 @@ -180,7 +191,7 @@ void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, C curB->stackActionPerformed = false; if(stacks[i]->alive) //niech interfejs ruszy oddzialem { - unsigned char owner = (stacks[i]->owner)?(hero2->tempOwner):(hero1->tempOwner); + unsigned char owner = (stacks[i]->owner)?(hero2 ? hero2->tempOwner : 255):(hero1->tempOwner); unsigned char serialOwner = -1; for(int g=0; gplayerint.size(); ++g) { @@ -190,7 +201,10 @@ void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, C break; } } - if(CGI->playerint[serialOwner]->human) + if(serialOwner==255) //neutral unit + { + } + else if(CGI->playerint[serialOwner]->human) { ((CPlayerInterface*)CGI->playerint[serialOwner])->activeStack(stacks[i]->ID); } @@ -252,7 +266,16 @@ bool CGameState::battleMoveCreatureStack(int ID, int dest) for(int g=0; gstacks.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) @@ -326,7 +349,7 @@ bool CGameState::battleMoveCreatureStack(int ID, int dest) { if(v!=0 || !stackAtEnd) //it's not the last step { - LOCPLINT->battleStackMoved(ID, path[v]); + 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 @@ -361,7 +384,16 @@ std::vector CGameState::battleGetRange(int ID) for(int g=0; gstacks.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; + } + } } diff --git a/CGameState.h b/CGameState.h index 54f2d1c92..b00d6e914 100644 --- a/CGameState.h +++ b/CGameState.h @@ -45,10 +45,11 @@ public: CCreature * creature; int amount; int owner; + bool attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle) int position; //position on battlefield bool alive; //true if it is alive - CStack(CCreature * C, int A, int O, int I):creature(C),amount(A),owner(O), alive(true), position(-1), ID(I){}; - CStack() : creature(NULL),amount(-1),owner(255), alive(true), position(-1), ID(-1){}; + CStack(CCreature * C, int A, int O, int I, bool AO):creature(C),amount(A),owner(O), alive(true), position(-1), ID(I), attackerOwned(AO){}; + CStack() : creature(NULL),amount(-1),owner(255), alive(true), position(-1), ID(-1), attackerOwned(true){}; }; class CGameState diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index da3e023cc..13bef166d 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -1986,9 +1986,9 @@ void CPlayerInterface::battleEnd(CCreatureSet * army1, CCreatureSet * army2, CGH { } -void CPlayerInterface::battleStackMoved(int ID, int dest) +void CPlayerInterface::battleStackMoved(int ID, int dest, bool startMoving, bool endMoving) { - dynamic_cast(curint)->stackMoved(ID, dest); + dynamic_cast(curint)->stackMoved(ID, dest, startMoving, endMoving); } void CPlayerInterface::battleStackAttacking(int ID, int dest) diff --git a/CPlayerInterface.h b/CPlayerInterface.h index afe8ce12e..179d10c14 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -334,7 +334,7 @@ public: void actionFinished(BattleAction action);//occurs AFTER every action taken by any stack or by the hero void activeStack(int stackID); //called when it's turn of that stack void battleEnd(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, std::vector capturedArtifacts, int expForWinner, bool winner); - void battleStackMoved(int ID, int dest); + void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving); void battleStackAttacking(int ID, int dest); diff --git a/hch/CCreatureHandler.cpp b/hch/CCreatureHandler.cpp index 59bf19a99..27be61cc3 100644 --- a/hch/CCreatureHandler.cpp +++ b/hch/CCreatureHandler.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "../SDL_Extensions.h" @@ -32,6 +33,16 @@ int CCreature::getQuantityID(int quantity) return 8; } +bool CCreature::isDoubleWide() +{ + return boost::algorithm::find_first(abilityRefs, "DOUBLE_WIDE"); +} + +bool CCreature::isFlying() +{ + return boost::algorithm::find_first(abilityRefs, "FLYING_ARMY"); +} + void CCreatureHandler::loadCreatures() { std::string buf = CGameInfo::mainObj->bitmaph->getTextFile("ZCRTRAIT.TXT"); @@ -953,6 +964,17 @@ int CCreatureAnimation::nextFrame(SDL_Surface *dest, int x, int y, bool attacker return 0; } +int CCreatureAnimation::framesInGroup(int group) const +{ + int ret = 0; //number of frames in given group + for(int g=0; g