1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

* redone stack queue algorithm

* recalculating paths only after finished movement / switching selection
* moving hero uses "new" pathfinder
* moving hero by arrow keys / numpad
* VCMI window should start centered
* fixed pairing Subterranean Gates
* fixed issues with creatures sounds after loading
* several minor changes and improvements
This commit is contained in:
Michał W. Urbańczyk 2009-09-07 02:29:44 +00:00
parent 1772f52554
commit 956a87f264
26 changed files with 613 additions and 258 deletions

View File

@ -1110,6 +1110,8 @@ BattleAction CGeniusAI::activeStack(int stackID)
message += ")";
DbgBox(message.c_str());
return m_battleLogic->MakeDecision(stackID);
BattleAction bact = m_battleLogic->MakeDecision(stackID);
assert(m_cb->battleGetStackByID(bact.stackNumber));
return bact;
};

View File

@ -500,14 +500,14 @@ std::map<int, CStack> CCallback::battleGetStacks()
return ret;
}
std::vector<CStack> CCallback::battleGetStackQueue()
void CCallback::getStackQueue( std::vector<const CStack *> &out, int howMany )
{
if(!gs->curB)
{
tlog2<<"battleGetStackQueue called when there is not battle!"<<std::endl;
return std::vector<CStack>();
tlog2 << "battleGetStackQueue called when there is not battle!" << std::endl;
return;
}
return gs->curB->getStackQueue();
gs->curB->getStackQueue(out, howMany);
}
CCreature CCallback::battleGetCreature(int number)
@ -834,9 +834,25 @@ const CGPathNode * CCallback::getPathInfo( int3 tile )
bool CCallback::getPath2( int3 dest, CGPath &ret )
{
const CGHeroInstance *h = cl->IGameCallback::getSelectedHero(player);
assert(cl->pathInfo->hero == h);
if(cl->pathInfo->hpos != h->getPosition(false)) //hero position changed, must update paths
{
recalculatePaths();
}
return cl->pathInfo->getPath(dest, ret);
}
void CCallback::recalculatePaths()
{
gs->calculatePaths(cl->IGameCallback::getSelectedHero(player), *cl->pathInfo);
}
void CCallback::calculatePaths( const CGHeroInstance *hero, CPathsInfo &out, int3 src /*= int3(-1,-1,-1)*/, int movement /*= -1*/ )
{
gs->calculatePaths(hero, out, src, movement);
}
InfoAboutHero::InfoAboutHero()
{
details = NULL;

View File

@ -137,8 +137,10 @@ public:
virtual std::vector < const CGHeroInstance *> getHeroesInfo(bool onlyOur=true)const =0;
virtual bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const = 0;
virtual bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret)=0;
virtual const CGPathNode *getPathInfo(int3 tile)=0;
virtual bool getPath2(int3 dest, CGPath &ret)=0;
virtual const CGPathNode *getPathInfo(int3 tile)=0; //uses main, client pathfinder info
virtual bool getPath2(int3 dest, CGPath &ret)=0; //uses main, client pathfinder info
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1) =0;
virtual void recalculatePaths()=0; //updates main, client pathfinder info (should be called when moving hero is over)
//map
virtual std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos)const =0;
@ -172,7 +174,7 @@ public:
virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
virtual std::map<int, CStack> battleGetStacks()=0; //returns stacks on battlefield
virtual std::vector<CStack> battleGetStackQueue()=0; //returns vector of stack in order of their move sequence
virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
virtual CCreature battleGetCreature(int number)=0; //returns type of creature by given number of stack
//virtual bool battleMoveCreature(int ID, int dest)=0; //moves creature with id ID to dest if possible
virtual std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable)=0; //reutrns numbers of hexes reachable by creature with id ID
@ -269,6 +271,8 @@ public:
bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret);
const CGPathNode *getPathInfo(int3 tile);
bool getPath2(int3 dest, CGPath &ret);
void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1); //calculates possible paths for hero, by default uses current hero position and movement left;
void recalculatePaths(); //updates pathfinder info (should be called when moving hero is over)
bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
@ -282,7 +286,7 @@ public:
int battleGetPos(int stack); //returns position (tile ID) of stack
int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
std::map<int, CStack> battleGetStacks(); //returns stacks on battlefield
std::vector<CStack> battleGetStackQueue(); //returns vector of stack in order of their move sequence
void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
CCreature battleGetCreature(int number); //returns type of creature by given number of stack
std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable); //reutrns numbers of hexes reachable by creature with id ID
bool battleIsStackMine(int ID); //returns true if stack with id ID belongs to caller

View File

@ -632,5 +632,5 @@ void CSlider::setAmount( int to )
{
amount = to;
positions = to - capacity;
amax(positions, 1);
amax(positions, 0);
}

View File

@ -545,9 +545,9 @@ void CTerrainRect::clickLeft(tribool down, bool previousState)
else if(mp.z == currentHero->pos.z) //remove old path and find a new one if we clicked on the map level on which hero is present
{
int3 bufpos = currentHero->getPosition(false);
CPath &path = LOCPLINT->adventureInt->paths[currentHero];
CGPath &path = LOCPLINT->adventureInt->paths[currentHero];
currentPath = &path;
if(!LOCPLINT->cb->getPath(bufpos, mp, currentHero, path))
if(!LOCPLINT->cb->getPath2(mp, path))
{
LOCPLINT->adventureInt->paths.erase(currentHero);
currentPath = NULL;
@ -799,7 +799,7 @@ void CTerrainRect::showPath(const SDL_Rect * extRect)
* 7 8 9
* ie. 157 means an arrow from left upper tile to left bottom tile through 5 (all arrows go through 5 in this notation)
*/
std::vector<CPathNode> & cv = currentPath->nodes;
std::vector<CGPathNode> & cv = currentPath->nodes;
if (cv[i+1].coord.x == cv[i].coord.x-1 && cv[i+1].coord.y == cv[i].coord.y-1) //15x
{
if(cv[i-1].coord.x == cv[i].coord.x+1 && cv[i-1].coord.y == cv[i].coord.y) //156
@ -1042,7 +1042,7 @@ void CTerrainRect::showPath(const SDL_Rect * extRect)
}
}
if ( ((currentPath->nodes[i].dist)-(*(currentPath->nodes.end()-1)).dist) > (static_cast<const CGHeroInstance*>(LOCPLINT->adventureInt->selection))->movement)
if (currentPath->nodes[i].turns)
pn+=25;
if (pn>=0)
{
@ -1712,8 +1712,9 @@ void CAdvMapInt::centerOn(int3 on)
}
void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
{
ui8 Dir;
switch(key.keysym.sym)
ui8 Dir = 0;
int k = key.keysym.sym;
switch(k)
{
case SDLK_i:
if(active)
@ -1723,18 +1724,6 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
if(active)
GH.pushInt(new CSelectionScreen(saveGame));
return;
case SDLK_UP:
Dir = UP;
break;
case SDLK_LEFT:
Dir = LEFT;
break;
case SDLK_RIGHT:
Dir = RIGHT;
break;
case SDLK_DOWN:
Dir = DOWN;
break;
case SDLK_SPACE: //space - try to revisit current object with selected hero
{
if(!active)
@ -1777,9 +1766,70 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
return;
}
default:
{
static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0),
int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0),
int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) };
//numpad arrow
if(isArrowKey(SDLKey(k)))
{
switch(k)
{
case SDLK_UP:
Dir = UP;
break;
case SDLK_LEFT:
Dir = LEFT;
break;
case SDLK_RIGHT:
Dir = RIGHT;
break;
case SDLK_DOWN:
Dir = DOWN;
break;
}
k = arrowToNum(SDLKey(k));
}
if(!active)
break;
k -= SDLK_KP0 + 1;
if(k < 0 || k > 8 || key.state != SDL_PRESSED)
return;
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(selection);
if(!h) break;
if(k == 4)
{
centerOn(h->getPosition(false));
return;
}
int3 dir = directions[k];
CGPath &path = paths[h];
terrain.currentPath = &path;
if(!LOCPLINT->cb->getPath2(h->getPosition(false) + dir, path))
{
terrain.currentPath = NULL;
return;
}
if(!path.nodes[0].turns)
{
LOCPLINT->pim->unlock();
LOCPLINT->moveHero(h, path);
LOCPLINT->pim->lock();
}
}
return;
}
if(key.state == SDL_PRESSED //arrow is pressed
if(Dir && key.state == SDL_PRESSED //arrow is pressed
&& (SDL_GetKeyState(NULL)[SDLK_LCTRL]
|| SDL_GetKeyState(NULL)[SDLK_RCTRL])
)
@ -1816,6 +1866,7 @@ int3 CAdvMapInt::verifyPos(int3 ver)
void CAdvMapInt::select(const CArmedInstance *sel )
{
LOCPLINT->cb->setSelection(sel);
centerOn(sel->pos);
selection = sel;
@ -1834,9 +1885,10 @@ void CAdvMapInt::select(const CArmedInstance *sel )
if(vstd::contains(paths,h)) //hero has assigned path
{
CPath &path = paths[h];
CGPath &path = paths[h];
assert(h->getPosition(false) == path.startPos());
//update the hero path in case of something has changed on map
if(LOCPLINT->cb->getPath(path.startPos(), path.endPos(), h, path))
if(LOCPLINT->cb->getPath2(path.endPos(), path))
terrain.currentPath = &path;
else
paths.erase(h);

View File

@ -8,7 +8,7 @@
#include "GUIClasses.h"
class CDefHandler;
class CCallback;
struct CPath;
struct CGPath;
class CAdvMapInt;
class CGHeroInstance;
class CGTownInstance;
@ -80,7 +80,7 @@ public:
CDefHandler * arrows;
CTerrainRect();
~CTerrainRect();
CPath * currentPath;
CGPath * currentPath;
void activate();
void deactivate();
void clickLeft(tribool down, bool previousState);
@ -173,7 +173,7 @@ public:
CHeroWindow * heroWindow;
const CArmedInstance *selection; //currently selected town/hero
std::map<const CGHeroInstance *, CPath> paths; //maps hero => selected path in adventure map
std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
//functions bound to buttons
void fshowOverview();

View File

@ -124,7 +124,7 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
background = BitmapHandler::loadBitmap(backref[ rand() % backref.size()] );
}
//preparign menu background
//preparing menu background
menu = BitmapHandler::loadBitmap("CBAR.BMP");
graphics->blueToPlayersAdv(menu, hero1->tempOwner);
@ -560,49 +560,46 @@ void CBattleInterface::show(SDL_Surface * to)
//showing queue of stacks
if(showStackQueue)
{
const int QUEUE_SIZE = 10;
int xPos = screen->w/2 - ( stacks.size() * 37 )/2;
int yPos = (screen->h - 600)/2 + 10;
std::vector<CStack> stacksSorted;
stacksSorted = LOCPLINT->cb->battleGetStackQueue();
int startFrom = -1;
for(size_t n=0; n<stacksSorted.size(); ++n)
std::vector<const CStack *> stacksSorted;
// const CStack *curStack = LOCPLINT->cb->battleGetStackByID(activeStack);
// if(curStack)
// stacksSorted.push_back(curStack);
LOCPLINT->cb->getStackQueue(stacksSorted, QUEUE_SIZE);
for(size_t b=0; b < stacksSorted.size(); ++b)
{
if(stacksSorted[n].ID == activeStack)
const CStack * s = stacksSorted[b];
SDL_BlitSurface(graphics->smallImgs[-2], NULL, to, &genRect(32, 32, xPos, yPos));
//printing colored border
for(int xFrom = xPos-1; xFrom<xPos+33; ++xFrom)
{
startFrom = n;
break;
}
}
if(startFrom != -1)
{
for(size_t b=startFrom; b<stacksSorted.size()+startFrom; ++b)
{
SDL_BlitSurface(graphics->smallImgs[-2], NULL, to, &genRect(32, 32, xPos, yPos));
//printing colored border
for(int xFrom = xPos-1; xFrom<xPos+33; ++xFrom)
for(int yFrom = yPos-1; yFrom<yPos+33; ++yFrom)
{
for(int yFrom = yPos-1; yFrom<yPos+33; ++yFrom)
if(xFrom == xPos-1 || xFrom == xPos+32 || yFrom == yPos-1 || yFrom == yPos+32)
{
if(xFrom == xPos-1 || xFrom == xPos+32 || yFrom == yPos-1 || yFrom == yPos+32)
SDL_Color pc;
if(s->owner != 255)
{
SDL_Color pc;
if(stacksSorted[b % stacksSorted.size()].owner != 255)
{
pc = graphics->playerColors[stacksSorted[b % stacksSorted.size()].owner];
}
else
{
pc = *graphics->neutralColor;
}
CSDL_Ext::SDL_PutPixelWithoutRefresh(to, xFrom, yFrom, pc.r, pc.g, pc.b);
pc = graphics->playerColors[s->owner];
}
else
{
pc = *graphics->neutralColor;
}
CSDL_Ext::SDL_PutPixelWithoutRefresh(to, xFrom, yFrom, pc.r, pc.g, pc.b);
}
}
//colored border printed
SDL_BlitSurface(graphics->smallImgs[stacksSorted[b % stacksSorted.size()].creature->idNumber], NULL, to, &genRect(32, 32, xPos, yPos));
xPos += 37;
}
//colored border printed
SDL_BlitSurface(graphics->smallImgs[s->creature->idNumber], NULL, to, &genRect(32, 32, xPos, yPos));
xPos += 37;
}
}
@ -2478,12 +2475,11 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
}
SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[ID]->pos.x + xAdd + pos.x, creAnims[ID]->pos.y + 260 + pos.y));
//blitting amount
CSDL_Ext::printAtMiddleWB(
CSDL_Ext::printAtMiddle(
makeNumberShort(curStack.amount),
creAnims[ID]->pos.x + xAdd + 14 + pos.x,
creAnims[ID]->pos.y + 260 + 4 + pos.y,
GEOR13,
20,
creAnims[ID]->pos.x + xAdd + 15 + pos.x,
creAnims[ID]->pos.y + 260 + 5 + pos.y,
FONT_TINY,
zwykly,
to
);

View File

@ -150,7 +150,7 @@ struct BattleSettings
template <typename Handler> void serialize(Handler &h, const int version)
{
h & printCellBorders & printStackRange & printMouseShadow;
h & printCellBorders & printStackRange & animSpeed & printMouseShadow;
}
};

View File

@ -992,7 +992,7 @@ void CCastleInterface::enterTavern()
void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key )
{
if(key.state != SDL_RELEASED) return;
if(key.state != SDL_PRESSED) return;
switch(key.keysym.sym)
{

View File

@ -163,6 +163,9 @@ int _tmain(int argc, _TCHAR* argv[])
int main(int argc, char** argv)
#endif
{
putenv("SDL_VIDEO_WINDOW_POS");
putenv("SDL_VIDEO_CENTERED=1");
tlog0 << "Starting... " << std::endl;
timeHandler total, pomtime;
std::cout.flags(std::ios::unitbuf);

View File

@ -1415,7 +1415,7 @@ void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero)
adventureInt->infoBar.draw(screen);
}
bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path )
bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
{
if (!h)
return false; //can't find hero
@ -1442,10 +1442,6 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path )
// TODO
if (hero is flying && sh == -1)
sh = CGI->soundh->playSound(soundBase::horseFlying, -1);
}
else if (hero is in a boat && sh = -1) {
sh = CGI->soundh->playSound(soundBase::sound_todo, -1);
} else
#endif
{
newTerrain = cb->getTileInfo(CGHeroInstance::convertPosition(path.nodes[i].coord, false))->tertype;
@ -1468,6 +1464,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath path )
CGI->soundh->stopSound(sh);
//stillMoveHero = false;
cb->recalculatePaths();
return result;
}

View File

@ -42,7 +42,7 @@ class CStack;
class SComponent;
class CCreature;
struct SDL_Surface;
struct CPath;
struct CGPath;
class CCreatureAnimation;
class CSelectableComponent;
class CCreatureSet;
@ -198,7 +198,7 @@ public:
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components = std::vector<SComponent*>(), int soundID = 0);
void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
bool moveHero(const CGHeroInstance *h, CPath path);
bool moveHero(const CGHeroInstance *h, CGPath path);
CPlayerInterface(int Player, int serial);//c-tor
~CPlayerInterface();//d-tor

View File

@ -977,7 +977,7 @@ void InfoCard::showAll( SDL_Surface * to )
void InfoCard::changeSelection( const CMapInfo *to )
{
if(to/* && type != newGame*/)
if(to && type != newGame)
difficulty->select(curOpts->difficulty, 0);
GH.totalRedraw();
}
@ -1257,6 +1257,9 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
btns[4] = new AdventureMapButton(CGI->generaltexth->zelp[164], bind(&OptionsTab::nextBonus, owner, s.serial, -1), 259, 5, "ADOPLFA.DEF");
btns[5] = new AdventureMapButton(CGI->generaltexth->zelp[165], bind(&OptionsTab::nextBonus, owner, s.serial, +1), 320, 5, "ADOPRTA.DEF");
}
else
for(int i = 0; i < 6; i++)
btns[i] = NULL;
fixedHero = s.hero != -1; //if we doesn't start with "random hero" it must be fixed or none
selectButtons(false);
@ -1287,7 +1290,7 @@ void OptionsTab::PlayerOptionsEntry::showAll( SDL_Surface * to )
void OptionsTab::PlayerOptionsEntry::selectButtons(bool onlyHero)
{
if(type != newGame)
if(!btns[0])
return;
if(!onlyHero && s.castle != -1)

View File

@ -150,11 +150,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
SDL_KeyboardEvent key = sEvent->key;
//translate numpad keys
if (key.keysym.sym >= SDLK_KP0 && key.keysym.sym <= SDLK_KP9)
{
key.keysym.sym = (SDLKey) (key.keysym.sym - SDLK_KP0 + SDLK_0);
}
else if(key.keysym.sym == SDLK_KP_ENTER)
if(key.keysym.sym == SDLK_KP_ENTER)
{
key.keysym.sym = (SDLKey)SDLK_RETURN;
}
@ -700,4 +696,40 @@ void IShowable::redraw()
showAll(screenBuf);
if(screenBuf != screen)
showAll(screen);
}
SDLKey arrowToNum( SDLKey key )
{
switch(key)
{
case SDLK_DOWN:
return SDLK_KP2;
case SDLK_UP:
return SDLK_KP8;
case SDLK_LEFT:
return SDLK_KP4;
case SDLK_RIGHT:
return SDLK_KP6;
default:
assert(0);
}
throw std::string("Wrong key!");
}
SDLKey numToDigit( SDLKey key )
{
return SDLKey(key - SDLK_KP0 + SDLK_0);
}
bool isNumKey( SDLKey key, bool number )
{
if(number)
return key >= SDLK_KP0 && key <= SDLK_KP_EQUALS;
else
return key >= SDLK_KP0 && key <= SDLK_KP9;
}
bool isArrowKey( SDLKey key )
{
return key >= SDLK_UP && key <= SDLK_LEFT;
}

View File

@ -442,6 +442,11 @@ public:
std::list<CIntObject *> createdObj; //stack of objs being created
};
SDLKey arrowToNum(SDLKey key); //converts arrow key to according numpad key
SDLKey numToDigit(SDLKey key);//converts numpad digit key to normal digit key
bool isNumKey(SDLKey key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
bool isArrowKey(SDLKey key);
extern CGuiHandler GH; //global gui handler
struct ObjectConstruction

View File

@ -41,6 +41,7 @@
#include "CHeroWindow.h"
#include "../hch/CVideoHandler.h"
#include "../StartInfo.h"
#include "CPreGame.h"
/*
* GUIClasses.cpp, part of VCMI engine
@ -1308,11 +1309,13 @@ void CHeroList::updateHList(const CGHeroInstance *toRemove)
if(selected >= heroes.size())
select(heroes.size()-1);
if(heroes.size() == 0)
LOCPLINT->adventureInt->townList.select(0);
else
select(selected);
if(toRemove)
{
if(heroes.size() == 0)
LOCPLINT->adventureInt->townList.select(0);
else
select(selected);
}
}
void CHeroList::updateMove(const CGHeroInstance* which) //draws move points bar
@ -1990,23 +1993,27 @@ void CSplitWindow::show(SDL_Surface * to)
void CSplitWindow::keyPressed (const SDL_KeyboardEvent & key)
{
SDLKey k = key.keysym.sym;
if (isNumKey(k)) //convert numpad number to normal digit
k = numToDigit(k);
if(key.state != SDL_PRESSED)
return;
int &cur = (which ? a2 : a1),
&sec = (which ? a1 : a2),
ncur = cur;
if (key.keysym.sym == SDLK_BACKSPACE)
if (k == SDLK_BACKSPACE)
{
ncur /= 10;
}
else if(key.keysym.sym == SDLK_TAB)
else if(k == SDLK_TAB)
{
which = !which;
}
else
{
int number = key.keysym.sym - SDLK_0;
int number = k - SDLK_0;
if (number < 0 || number > 9) //not a number pressed
{
return;
@ -2811,13 +2818,15 @@ void CSystemOptionsWindow::breturnf()
void CSystemOptionsWindow::bsavef()
{
using namespace boost::posix_time;
GH.popIntTotally(this);
GH.pushInt(new CSelectionScreen(saveGame));
/*using namespace boost::posix_time;
std::ostringstream fnameStream;
fnameStream << second_clock::local_time();
std::string fname = fnameStream.str();
boost::algorithm::replace_all(fname,":","");
boost::algorithm::replace_all(fname," ","-");
LOCPLINT->showYesNoDialog("Do you want to save current game as " + fname, std::vector<SComponent*>(), boost::bind(&CCallback::save, LOCPLINT->cb, fname), boost::bind(&CSystemOptionsWindow::activate, this), false);
LOCPLINT->showYesNoDialog("Do you want to save current game as " + fname, std::vector<SComponent*>(), boost::bind(&CCallback::save, LOCPLINT->cb, fname), boost::bind(&CSystemOptionsWindow::activate, this), false);*/
}
void CSystemOptionsWindow::activate()

View File

@ -500,15 +500,6 @@ void EndAction::applyCl( CClient *cl )
void PackageApplied::applyCl( CClient *cl )
{
ui8 player = GS(cl)->currentPlayer;
if(packType == typeList.getTypeID((MoveHero*)NULL))
{
//we've finished moving hero - paths info must be updated
const CGHeroInstance *h = cl->IGameCallback::getSelectedHero(player);
if(h)
GS(cl)->calculatePaths(h, *cl->pathInfo);
}
INTERFACE_CALL_IF_PRESENT(player, requestRealized, this);
if(cl->waitingRequest.get())
cl->waitingRequest.setn(false);

View File

@ -301,7 +301,8 @@ extern DLL_EXPORT CLogger<5> tlog5; //gray - minor log info
//XXX pls dont - 'debug macros' are usually more trubble then its worth
#define HANDLE_EXCEPTION \
catch (const std::exception& e) { \
tlog1 << e.what() << std::endl; \
tlog1 << e.what() << std::endl; \
throw; \
} \
catch (const std::exception * e) \
{ \

View File

@ -57,6 +57,11 @@ public:
soundBase::soundID ext2; // creature specific extension
soundBase::soundID startMoving; // usually same as ext1
soundBase::soundID endMoving; // usually same as ext2
template <typename Handler> void serialize(Handler &h, const int version)
{
h & attack & defend & killed & move & shoot & wince & ext1 & ext2 & startMoving & endMoving;
}
} sounds;
bool isDoubleWide() const; //returns true if unit is double wide on battlefield
@ -89,6 +94,8 @@ public:
& timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance
& upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY
& missleFrameAngles & troopCountLocationOffset & attackClimaxFrame;
h & sounds;
}
};

View File

@ -35,6 +35,7 @@ using namespace boost::assign;
*/
std::map<int,std::map<int, std::vector<int> > > CGTeleport::objs;
std::vector<std::pair<int, int> > CGTeleport::gates;
IGameCallback * IObjectInterface::cb = NULL;
DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
extern CLodHandler * bitmaph;
@ -64,6 +65,12 @@ void IObjectInterface::initObj()
void IObjectInterface::setProperty( ui8 what, ui32 val )
{}
void IObjectInterface::postInit()
{}
void IObjectInterface::preInit()
{}
void CPlayersVisited::setPropertyDer( ui8 what, ui32 val )
{
if(what == 10)
@ -2476,27 +2483,25 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
break;
case 103: //find nearest subterranean gate on the other level
{
std::pair<int,double> best(-1,150000); //pair<id,dist>
for(int i=0; i<objs[103][0].size(); i++)
for(int i=0; i < gates.size(); i++)
{
if(cb->getObj(objs[103][0][i])->pos.z == pos.z) continue; //gates on our level are not interesting
double hlp = cb->getObj(objs[103][0][i])->pos.dist2d(pos);
if(hlp<best.second)
if(gates[i].first == id)
{
best.first = objs[103][0][i];
best.second = hlp;
destinationid = gates[i].second;
break;
}
else if(gates[i].second == id)
{
destinationid = gates[i].first;
break;
}
}
if(best.first<0)
return;
else
destinationid = best.first;
break;
}
}
if(destinationid < 0)
{
tlog2 << "Cannot find exit... :( \n";
tlog2 << "Cannot find exit... (obj at " << pos << ") :( \n";
return;
}
cb->moveHero(h->id,CGHeroInstance::convertPosition(cb->getObj(destinationid)->pos,true) - getVisitableOffset(),
@ -2505,7 +2510,51 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
void CGTeleport::initObj()
{
objs[ID][subID].push_back(id);
int si = subID;
if(ID == 103) //ignore subterranean gates subid
si = 0;
objs[ID][si].push_back(id);
}
void CGTeleport::postInit() //matches subterranean gates into pairs
{
//split on underground and surface gates
std::vector<const CGObjectInstance *> gatesSplit[2]; //surface and underground gates
for(size_t i = 0; i < objs[103][0].size(); i++)
{
const CGObjectInstance *hlp = cb->getObj(objs[103][0][i]);
gatesSplit[hlp->pos.z].push_back(hlp);
}
//sort by position
std::sort(gatesSplit[0].begin(), gatesSplit[0].end(), boost::bind(&CGObjectInstance::pos, _1) < boost::bind(&CGObjectInstance::pos, _2));
for(size_t i = 0; i < gatesSplit[0].size(); i++)
{
const CGObjectInstance *cur = gatesSplit[0][i];
//find nearest underground exit
std::pair<int,double> best(-1,150000); //pair<pos_in_vector, distance>
for(int j = 0; j < gatesSplit[1].size(); j++)
{
const CGObjectInstance *checked = gatesSplit[1][j];
if(!checked)
continue;
double hlp = checked->pos.dist2d(cur->pos);
if(hlp < best.second)
{
best.first = j;
best.second = hlp;
}
}
gates.push_back(std::pair<int, int>(cur->id, gatesSplit[1][best.first]->id));
gatesSplit[1][best.first] = NULL;
}
objs.erase(103);
}
void CGArtifact::initObj()
@ -4042,7 +4091,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
int slot = ourArmy.getSlotFor (it->second);
ourArmy.slots[slot] = *it; //assuming we're not going to add multiple stacks of same creature
}
cb->giveCreatures (id, cb->getHero (h->getOwner()), &ourArmy);
cb->giveCreatures (id, h, &ourArmy);
cb->setObjProperty (id, 15, 0); //bc = NULL
}
else

View File

@ -103,6 +103,9 @@ public:
virtual void newTurn() const;
virtual void initObj(); //synchr
virtual void setProperty(ui8 what, ui32 val);//synchr
static void preInit(); //called before objs receive their initObj
static void postInit();//caleed after objs receive their initObj
};
class DLL_EXPORT IShipyard
@ -121,7 +124,7 @@ public:
static IShipyard *castFrom(CGObjectInstance *obj);
};
class DLL_EXPORT CGObjectInstance : protected IObjectInterface
class DLL_EXPORT CGObjectInstance : public IObjectInterface
{
protected:
void getNameVis(std::string &hname) const;
@ -388,16 +391,6 @@ public:
std::vector<CGTownBuilding*> bonusingBuildings;
std::vector<ui32> possibleSpells, obligatorySpells;
std::vector<std::vector<ui32> > spells; //spells[level] -> vector of spells, first will be available in guild
//struct StrInfo
//{
// std::map<si32,ui32> creatures; //level - available amount
// template <typename Handler> void serialize(Handler &h, const int version)
// {
// h & creatures;
// }
//} strInfo;
std::set<CCastleEvent> events;
//////////////////////////////////////////////////////////////////////////
@ -723,9 +716,11 @@ public:
class DLL_EXPORT CGTeleport : public CGObjectInstance //teleports and subterranean gates
{
public:
static std::map<int,std::map<int, std::vector<int> > > objs; //map[ID][subID] => vector of ids
static std::map<int,std::map<int, std::vector<int> > > objs; //teleports: map[ID][subID] => vector of ids
static std::vector<std::pair<int, int> > gates; //subterranean gates: pairs of ids
void onHeroVisit(const CGHeroInstance * h) const;
void initObj();
static void postInit();
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -90,6 +90,61 @@ public:
} *applierGs = NULL;
class IObjectCaller
{
public:
virtual void preInit()=0;
virtual void postInit()=0;
};
template <typename T>
class CObjectCaller : public IObjectCaller
{
public:
void preInit()
{
T::preInit();
}
void postInit()
{
T::postInit();
}
};
class CObjectCallersHandler
{
public:
std::vector<IObjectCaller*> apps;
template<typename T> void registerType(const T * t=NULL)
{
apps.push_back(new CObjectCaller<T>);
}
CObjectCallersHandler()
{
registerTypes1(*this);
}
~CObjectCallersHandler()
{
for (size_t i = 0; i < apps.size(); i++)
delete apps[i];
}
void preInit()
{
for (size_t i = 0; i < apps.size(); i++)
apps[i]->preInit();
}
void postInit()
{
for (size_t i = 0; i < apps.size(); i++)
apps[i]->postInit();
}
} *objCaller = NULL;
void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst) const
{
int type = txt.first, ser = txt.second;
@ -252,12 +307,7 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive)
const CStack * BattleInfo::getStack(int stackID, bool onlyAlive) const
{
for(unsigned int g=0; g<stacks.size(); ++g)
{
if(stacks[g]->ID == stackID && (!onlyAlive || stacks[g]->alive()))
return stacks[g];
}
return NULL;
return const_cast<BattleInfo * const>(this)->getStack(stackID, onlyAlive);
}
CStack * BattleInfo::getStackT(int tileID, bool onlyAlive)
@ -279,19 +329,7 @@ CStack * BattleInfo::getStackT(int tileID, bool onlyAlive)
const CStack * BattleInfo::getStackT(int tileID, bool onlyAlive) const
{
for(unsigned int g=0; g<stacks.size(); ++g)
{
if(stacks[g]->position == tileID
|| (stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID)
|| (stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID))
{
if(!onlyAlive || stacks[g]->alive())
{
return stacks[g];
}
}
}
return NULL;
return const_cast<BattleInfo * const>(this)->getStackT(tileID, onlyAlive);
}
void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set<int> & occupyable, bool flying, int stackToOmmit) const
@ -749,14 +787,24 @@ ui16 CStack::MaxHealth() const
return creature->hitPoints + valOfFeatures(StackFeature::HP_BONUS);
}
bool CStack::willMove()
bool CStack::willMove() const
{
return !vstd::contains(state, DEFENDING)
&& !vstd::contains(state, MOVED)
&& alive()
&& !moved()
&& canMove();
}
bool CStack::canMove() const
{
return alive()
&& ! hasFeatureOfType(StackFeature::NOT_ACTIVE); //eg. Ammo Cart
}
bool CStack::moved() const
{
return vstd::contains(state, MOVED);
}
CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, std::map<ui32,CGHeroInstance *> &available) const
{
CGHeroInstance *ret = NULL;
@ -1105,6 +1153,7 @@ CGameState::CGameState()
curB = NULL;
scenarioOps = NULL;
applierGs = new CGSApplier;
objCaller = new CObjectCallersHandler;
}
CGameState::~CGameState()
{
@ -1113,6 +1162,7 @@ CGameState::~CGameState()
delete curB;
delete scenarioOps;
delete applierGs;
delete objCaller;
}
void CGameState::init(StartInfo * si, Mapa * map, int Seed)
{
@ -1456,12 +1506,14 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
map->defy[i]->serial = i;
}
objCaller->preInit();
for(unsigned int i=0; i<map->objects.size(); i++)
{
map->objects[i]->initObj();
if(map->objects[i]->ID == 62) //prison also needs to initialize hero
static_cast<CGHeroInstance*>(map->objects[i])->initHero();
}
objCaller->postInit();
}
bool CGameState::battleShootCreatureStack(int ID, int dest)
@ -1915,11 +1967,15 @@ bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath
void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src, int movement)
{
assert(hero);
if(src.x < 0)
src = hero->getPosition(false);
if(movement < 0)
movement = hero->movement;
out.hero = hero;
out.hpos = src;
if(!map->isInTheMap(src)/* || !map->isInTheMap(dest)*/) //check input
{
tlog1 << "CGameState::calculatePaths: Hero outside the map? How dare you...\n";
@ -1953,6 +2009,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
node.coord.y = j;
node.coord.z = k;
node.land = tinfo->tertype != TerrainTile::water;
node.theNodeBefore = NULL;
if ( tinfo->tertype == TerrainTile::rock//it's rock
|| onLand && !node.land //it's sea and we cannot walk on sea
@ -1988,7 +2045,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
else if(!onLand && tinfo->tertype != TerrainTile::water) //hero is moving by water
{
if((tinfo->siodmyTajemniczyBajt & 64) && !tinfo->blocked)
node.accessible = CGPathNode::ACCESSIBLE; //tile is accessible if it's coastal and not blocked
node.accessible = CGPathNode::VISITABLE; //tile is accessible if it's coastal and not blocked
}
}
}
@ -2213,7 +2270,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange(const CStack* attacker, cons
affectedIds.push_back(151); //diamond dragon
affectedIds.push_back(154); //blood dragon
affectedIds.push_back(155); //darkness dragon
affectedIds.push_back(156); //ghost behemot
affectedIds.push_back(156); //ghost behemoth
affectedIds.push_back(157); //hell hydra
break;
}
@ -2412,17 +2469,17 @@ si8 CGameState::battleMaxSpellLevel()
std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHeroInstance * caster, int destinationTile)
{
std::set<ui16> attackedHexes = s->rangeInHexes(destinationTile, caster->getSpellSchoolLevel(s));
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurences of two hex creatures*/
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurrences of two hex creatures*/
bool onlyAlive = s->id != 38 && s->id != 39; //when casting resurrection or animate dead we should be allow to select dead stack
if(s->id == 24 || s->id == 25 || s->id == 26) //death ripple, destroy undead and armageddon
if(s->id == 24 || s->id == 25 || s->id == 26) //death ripple, destroy undead and Armageddon
{
for(int it=0; it<stacks.size(); ++it)
{
if((s->id == 24 && !stacks[it]->creature->isUndead()) //death ripple
|| (s->id == 25 && stacks[it]->creature->isUndead()) //destroy undead
|| (s->id == 26) //armageddon
|| (s->id == 26) //Armageddon
)
{
attackedCres.insert(stacks[it]);
@ -2641,92 +2698,150 @@ bool CGameState::battleCanShoot(int ID, int dest)
return false;
}
CStack * BattleInfo::getNextStack()
const CStack * BattleInfo::getNextStack() const
{
CStack *current = getStack(activeStack);
for (unsigned int i = 0; i < stacks.size(); i++) //find fastest not moved/waited stack (stacks vector is sorted by speed)
{
if(stacks[i]->willMove() && !vstd::contains(stacks[i]->state,WAITING))
return stacks[i];
}
for (int i = stacks.size() - 1; i >= 0 ; i--) //find slowest waiting stack
{
if(stacks[i]->willMove())
return stacks[i];
}
return NULL; //all stacks moved or defending!
std::vector<const CStack *> hlp;
getStackQueue(hlp, 1, 2);
if(hlp.size())
return hlp[0];
else
return NULL;
}
std::vector<CStack> BattleInfo::getStackQueue()
static const CStack *takeStack(std::vector<const CStack *> &st, int &curside)
{
std::vector<CStack> ret;
std::vector<int> taken; //if non-zero value, corresponding stack has been placed in ret
taken.resize(stacks.size());
for(unsigned int g=0; g<taken.size(); ++g)
{
taken[g] = 0;
}
const CStack *ret = NULL;
unsigned i, //fastest stack
j; //fastest stack of the other side
for(i = 0; i < st.size(); i++)
if(st[i])
break;
for(int moved=0; moved<2; ++moved) //in first cycle we add stacks that can act in current turn, in second one the rest of them
//no stacks left
if(i == st.size())
return NULL;
const CStack *fastest = st[i], *other = NULL;
int bestSpeed = fastest->Speed();
if(fastest->attackerOwned != curside)
{
for(unsigned int gc=0; gc<stacks.size(); ++gc)
ret = fastest;
}
else
{
for(j = i + 1; j < st.size(); j++)
{
int id = -1, speed = -1;
for(unsigned int i=0; i<stacks.size(); ++i) //find not waited stacks only
{
if((moved == 1 ||!vstd::contains(stacks[i]->state, DEFENDING))
&& stacks[i]->alive()
&& (moved == 1 || !vstd::contains(stacks[i]->state, MOVED))
&& !vstd::contains(stacks[i]->state,WAITING)
&& taken[i]==0
&& !stacks[i]->hasFeatureOfType(StackFeature::NOT_ACTIVE)) //eg. Ammo Cart
{
if(speed == -1 || stacks[i]->Speed() > speed)
{
id = i;
speed = stacks[i]->Speed();
}
}
}
if(id != -1)
{
ret.push_back(*stacks[id]);
taken[id] = 1;
}
else //choose something from not moved stacks
{
int id = -1, speed = 10000; //infinite speed
for(unsigned int i=0; i<stacks.size(); ++i) //find waited stacks only
{
if((moved == 1 ||!vstd::contains(stacks[i]->state, DEFENDING))
&& stacks[i]->alive()
&& (moved == 1 || !vstd::contains(stacks[i]->state, MOVED))
&& vstd::contains(stacks[i]->state,WAITING)
&& taken[i]==0
&& !stacks[i]->hasFeatureOfType(StackFeature::NOT_ACTIVE)) //eg. Ammo Cart
{
if(stacks[i]->Speed() < speed) //slowest one
{
id = i;
speed = stacks[i]->Speed();
}
}
}
if(id != -1)
{
ret.push_back(*stacks[id]);
taken[id] = 1;
}
else
{
break; //no stacks have been found, so none of them will be found in next iterations
}
}
if(!st[j]) continue;
if(st[j]->attackerOwned != curside || st[j]->Speed() != bestSpeed)
break;
}
if(j >= st.size())
{
ret = fastest;
}
else
{
other = st[j];
if(other->Speed() != bestSpeed)
ret = fastest;
else
ret = other;
}
}
assert(ret);
if(ret == fastest)
st[i] = NULL;
else
st[j] = NULL;
curside = ret->attackerOwned;
return ret;
}
void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, int mode, int lastMoved ) const
{
//we'll split creatures with remaining movement to 4 parts
std::vector<const CStack *> phase[4]; //0 - turrets/catapult, 1 - normal (unmoved) creatures, other war machines, 2 - waited cres that had morale, 3 - rest of waited cres
int toMove = 0; //how many stacks still has move
for(unsigned int i=0; i<stacks.size(); ++i)
{
const CStack * const s = stacks[i];
if(mode != 1 && s->willMove()
|| mode == 1 && s->canMove())
{
int p = -1; //in which phase this tack will move?
if(!mode && vstd::contains(s->state, WAITING))
{
if(vstd::contains(s->state, HAD_MORALE))
p = 2;
else
p = 3;
}
else if(vstd::contains(s->state, StackFeature::SIEGE_WEAPON) //catapult and turrets are first
&& (s->creature->idNumber == 145 || s->creature->idNumber == 149))
{
p = 0;
}
else
{
p = 1;
}
phase[p].push_back(s);
toMove++;
}
}
for(int i = 0; i < 4; i++)
std::sort(phase[i].begin(), phase[i].end(), CMP_stack(i));
for(size_t i = 0; i < phase[0].size() && i < howMany; i++)
out.push_back(phase[0][i]);
if(out.size() == howMany)
return;
if(lastMoved == -1)
{
const CStack *current = getStack(activeStack);
if(current)
{
lastMoved = !current->attackerOwned;
if(!current->willMove() || mode == 2)
lastMoved = !lastMoved;
}
else
{
lastMoved = 0;
}
}
int pi = 1;
while(out.size() < howMany)
{
const CStack *hlp = takeStack(phase[pi], lastMoved);
if(!hlp)
{
pi++;
if(pi > 3)
{
if(mode != 2)
getStackQueue(out, howMany, 1, lastMoved);
return;
}
}
else
{
out.push_back(hlp);
}
}
}
int3 CPath::startPos() const
{
return nodes[nodes.size()-1].coord;
@ -2764,7 +2879,7 @@ bool CPathsInfo::getPath( const int3 &dst, CGPath &out )
if(!curnode->theNodeBefore)
return false;
while(curnode->theNodeBefore)
while(curnode)
{
out.nodes.push_back(*curnode);
curnode = curnode->theNodeBefore;
@ -2797,4 +2912,68 @@ CPathsInfo::~CPathsInfo()
delete [] nodes[i];
}
delete [] nodes;
}
int3 CGPath::startPos() const
{
return nodes[nodes.size()-1].coord;
}
int3 CGPath::endPos() const
{
return nodes[0].coord;
}
void CGPath::convert( ui8 mode )
{
if(mode==0)
{
for(unsigned int i=0;i<nodes.size();i++)
{
nodes[i].coord = CGHeroInstance::convertPosition(nodes[i].coord,true);
}
}
}
bool CMP_stack::operator()( const CStack* a, const CStack* b )
{
switch(phase)
{
case 0: //catapult moves after turrets
return a->creature->idNumber < b->creature->idNumber; //catapult is 145 and turrets are 149
//TODO? turrets order
case 1: //fastest first, upper slot first
{
int as = a->Speed(), bs = b->Speed();
if(as != bs)
return as > bs;
else
return a->slot < b->slot;
}
case 2: //fastest last, upper slot first
//TODO: should be replaced with order of receiving morale!
case 3: //fastest last, upper slot first
{
int as = a->Speed(), bs = b->Speed();
if(as != bs)
return as < bs;
else
return a->slot < b->slot;
}
default:
assert(0);
return false;
}
}
CMP_stack::CMP_stack( int Phase /*= 1*/ )
{
phase = Phase;
}
PlayerState::PlayerState()
: color(-1), currentSelection(0xffffffff)
{
}

View File

@ -66,7 +66,9 @@ public:
std::vector<CGHeroInstance *> heroes;
std::vector<CGTownInstance *> towns;
std::vector<CGHeroInstance *> availableHeroes; //heroes available in taverns
PlayerState():color(-1),currentSelection(0xffffffff){};
PlayerState();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & color & serial & human & currentSelection & fogOfWarMap & resources;
@ -135,8 +137,8 @@ struct DLL_EXPORT BattleInfo
h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & hero1 & hero2 & obstacles
& castSpells & si;
}
CStack * getNextStack(); //which stack will have turn after current one
std::vector<CStack> getStackQueue(); //returns stack in order of their movement action
const CStack * getNextStack() const; //which stack will have turn after current one
void getStackQueue(std::vector<const CStack *> &out, int howMany, int mode = 0, int lastMoved = -1) const; //returns stack in order of their movement action
CStack * getStack(int stackID, bool onlyAlive = true);
const CStack * getStack(int stackID, bool onlyAlive = true) const;
CStack * getStackT(int tileID, bool onlyAlive = true);
@ -196,7 +198,9 @@ public:
CStack() : ID(-1), creature(NULL), amount(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor
const StackEffect * getEffect(ui16 id) const; //effect id (SP)
ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack
bool willMove(); //if stack has remaining move this turn
bool willMove() const; //if stack has remaining move this turn
bool moved() const; //if stack was already moved this turn
bool canMove() const; //if stack can move
ui32 Speed() const; //get speed of creature with all modificators
si8 Morale() const; //get morale of stack with all modificators
si8 Luck() const; //get luck of stack with all modificators
@ -229,6 +233,15 @@ public:
}
};
class DLL_EXPORT CMP_stack
{
int phase; //rules of which phase will be used
public:
bool operator ()(const CStack* a, const CStack* b);
CMP_stack(int Phase = 1);
};
struct UpgradeInfo
{
int oldID; //creature to be upgraded
@ -279,6 +292,8 @@ struct DLL_EXPORT CGPath
struct DLL_EXPORT CPathsInfo
{
const CGHeroInstance *hero;
int3 hpos;
int3 sizes;
CGPathNode ***nodes; //[w][h][level]

View File

@ -646,6 +646,7 @@ DLL_EXPORT void BattleSetActiveStack::applyGs( CGameState *gs )
{
gs->curB->activeStack = stack;
CStack *st = gs->curB->getStack(stack);
st->state -= WAITING; //if stack was waiting it'll now make move, so it won't be "waiting" anymore
if(vstd::contains(st->state,MOVED)) //if stack is moving second time this turn it must had a high morale bonus
st->state.insert(HAD_MORALE);
}
@ -719,6 +720,7 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
DLL_EXPORT void StartAction::applyGs( CGameState *gs )
{
CStack *st = gs->curB->getStack(ba.stackNumber);
assert(st);
switch(ba.actionType)
{
case 3:

View File

@ -407,6 +407,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
}
h & CGTeleport::objs;
h & CGTeleport::gates;
h & CGKeys::playerKeyMap;
h & CGMagi::eyelist;

View File

@ -84,14 +84,7 @@ public:
} *applier = NULL;
class CMP_stack
{
public:
inline bool operator ()(const CStack* a, const CStack* b)
{
return (a->Speed())>(b->Speed());
}
} cmpst ;
CMP_stack cmpst ;
static inline double distance(int3 a, int3 b)
{
@ -324,11 +317,15 @@ static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInf
void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town)
{
BattleInfo *curB = new BattleInfo;
curB->side1 = army1->tempOwner;
curB->side2 = army2->tempOwner;
if(curB->side2 == 254) curB->side2 = 255;
setupBattle(curB, tile, army1->army, army2->army, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
{
BattleInfo *curB = new BattleInfo;
curB->side1 = army1->tempOwner;
curB->side2 = army2->tempOwner;
if(curB->side2 == 254)
curB->side2 = 255;
setupBattle(curB, tile, army1->army, army2->army, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
}
NEW_ROUND;
//TODO: pre-tactic stuff, call scripts etc.
@ -351,10 +348,9 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
const BattleInfo & curB = *gs->curB;
//stack loop
CStack *next;
while(!battleResult.get() && (next=gs->curB->getNextStack()))
const CStack *next;
while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove())
{
next->state -= WAITING; //if stack was waiting it'll now make move, so it won't be "waiting" anymore
//check for bad morale => freeze
if(next->Morale() < 0 &&
@ -1369,8 +1365,6 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
return false;
}
if(states.checkFlag(h->tempOwner, &PlayerStatus::engagedIntoBattle) && complain("Cannot move hero during the battle"))
return false;
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
int3 hmpos = dst + int3(-1,0,0);
@ -1403,7 +1397,9 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
|| (h->boat && t.tertype != TerrainTile::water && t.blocked)
&& complain("Cannot disembark hero, tile is blocked!")
|| (!h->movement && dst != h->pos)
&& complain("Hero don't have any movement points left!"))
&& complain("Hero don't have any movement points left!")
|| states.checkFlag(h->tempOwner, &PlayerStatus::engagedIntoBattle)
&& complain("Cannot move hero during the battle"))
{
//send info about movement failure
sendAndApply(&tmh);