1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-24 03:47:18 +02:00

* nicer movement of creatures on battlefield

* amounts of creatures on battlefield
* partial support for two hex creatures
* a few minor things
This commit is contained in:
mateuszb 2008-04-14 18:24:46 +00:00
parent fb5c26437c
commit 063d2279ee
9 changed files with 240 additions and 38 deletions

View File

@ -9,8 +9,11 @@
#include "CCallback.h"
#include "CGameState.h"
#include <queue>
#include <sstream>
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<int, CStack> stacks = LOCPLINT->cb->battleGetStacks();
for(std::map<int, CStack>::iterator b=stacks.begin(); b!=stacks.end(); ++b)
{
std::pair <int, int> coords = CBattleHex::getXYUnitAnim(b->second.position, b->second.owner == attackingHeroInstance->tempOwner);
std::pair <int, int> 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; g<amountNormal->format->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<int, CCreatureAnimation*>::iterator j=creAnims.begin(); j!=creAnims.end(); ++j)
int stackByHex[187];
for(int b=0; b<187; ++b)
stackByHex[b] = -1;
for(std::map<int, CStack>::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<<stacks[stackByHex[b]].amount;
CSDL_Ext::printAtMiddleWB(ss.str(), creAnims[stackByHex[b]]->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<<stacks[stackByHex[b]].amount;
CSDL_Ext::printAtMiddleWB(ss.str(), creAnims[stackByHex[b]]->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; g<creAnims[number]->framesInGroup(8); ++g)
{
show();
SDL_framerateDelay(LOCPLINT->mainFPSmng);
}
creDir[number] = !creDir[number];
CStack curs = LOCPLINT->cb->battleGetStackByID(number);
std::pair <int, int> 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; g<creAnims[number]->framesInGroup(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; i<creAnims[number]->framesInGroup(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; i<steps; ++i)
{
@ -320,11 +432,26 @@ void CBattleInterface::stackMoved(int number, int destHex)
show();
SDL_framerateDelay(LOCPLINT->mainFPSmng);
}
if(endMoving) //animation of starting move
{
for(int i=0; i<creAnims[number]->framesInGroup(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 <int, int> coords = CBattleHex::getXYUnitAnim(destHex, curs.owner == attackingHeroInstance->tempOwner);
std::pair <int, int> 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; i<dh->ourImages.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<int, int> CBattleHex::getXYUnitAnim(int hexNum, bool attacker)
std::pair<int, int> CBattleHex::getXYUnitAnim(int hexNum, bool attacker, CCreature * creature)
{
std::pair<int, int> ret = std::make_pair(-500, -500); //returned value
ret.second = -139 + 42 * (hexNum/17); //counting y
@ -434,6 +563,18 @@ std::pair<int, int> 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;
}

View File

@ -32,7 +32,7 @@ public:
//CStack * ourStack;
bool hovered, strictHovered;
CBattleInterface * myInterface; //interface that owns me
static std::pair<int, int> getXYUnitAnim(int hexNum, bool attacker); //returns (x, y) of left top corner of animation
static std::pair<int, int> 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<CBattleInterface> * 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; // <creatureID, if false reverse creature's animation>
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

View File

@ -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<int> 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

View File

@ -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<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()));
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<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()));
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; 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
@ -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; g<CGI->playerint.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; 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)
@ -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<int> CGameState::battleGetRange(int ID)
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;
}
}
}

View File

@ -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

View File

@ -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<CBattleInterface*>(curint)->stackMoved(ID, dest);
dynamic_cast<CBattleInterface*>(curint)->stackMoved(ID, dest, startMoving, endMoving);
}
void CPlayerInterface::battleStackAttacking(int ID, int dest)

View File

@ -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<int> 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);

View File

@ -6,6 +6,7 @@
#include <sstream>
#include <boost/assign/std/vector.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/find.hpp>
#include <boost/algorithm/string/replace.hpp>
#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<SEntries.size(); ++g)
{
if(SEntries[g].group == group)
++ret;
}
return ret;
}
CCreatureAnimation::~CCreatureAnimation()
{
delete [] FDef;

View File

@ -40,6 +40,8 @@ public:
//TODO - zdolnoœci - na typie wyliczeniowym czy czymœ
static int getQuantityID(int quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
bool isDoubleWide(); //returns true if unit is double wide on battlefield
bool isFlying(); //returns true if it is a flying unit
};
class CCreatureSet //seven combined creatures
@ -96,13 +98,15 @@ private:
public:
int fullWidth, fullHeight; //read-only, please!
CCreatureAnimation(std::string name); //c-tor
~CCreatureAnimation(); //d-tor //not necessery ATM
~CCreatureAnimation(); //d-tor
void setType(int type); //sets type of animation and cleares framecount
int getType() const; //returns type of animation
int nextFrame(SDL_Surface * dest, int x, int y, bool attacker, bool incrementFrame = true, bool yellowBorder = false); //0 - success, any other - error //print next
int nextFrameMiddle(SDL_Surface * dest, int x, int y, bool attacker, bool incrementFrame = true, bool yellowBorder = false); //0 - success, any other - error //print next
int framesInGroup(int group) const; //retirns number of fromes in given group
};
#endif //CCREATUREHANDLER_H