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:
parent
1772f52554
commit
956a87f264
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
12
CCallback.h
12
CCallback.h
@ -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
|
||||
|
@ -632,5 +632,5 @@ void CSlider::setAmount( int to )
|
||||
{
|
||||
amount = to;
|
||||
positions = to - capacity;
|
||||
amax(positions, 1);
|
||||
amax(positions, 0);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
if(key.state == SDL_PRESSED //arrow is pressed
|
||||
|
||||
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(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);
|
||||
|
@ -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();
|
||||
|
@ -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,25 +560,23 @@ 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)
|
||||
{
|
||||
if(stacksSorted[n].ID == activeStack)
|
||||
{
|
||||
startFrom = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(startFrom != -1)
|
||||
{
|
||||
for(size_t b=startFrom; b<stacksSorted.size()+startFrom; ++b)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -587,9 +585,9 @@ void CBattleInterface::show(SDL_Surface * to)
|
||||
if(xFrom == xPos-1 || xFrom == xPos+32 || yFrom == yPos-1 || yFrom == yPos+32)
|
||||
{
|
||||
SDL_Color pc;
|
||||
if(stacksSorted[b % stacksSorted.size()].owner != 255)
|
||||
if(s->owner != 255)
|
||||
{
|
||||
pc = graphics->playerColors[stacksSorted[b % stacksSorted.size()].owner];
|
||||
pc = graphics->playerColors[s->owner];
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -600,11 +598,10 @@ void CBattleInterface::show(SDL_Surface * to)
|
||||
}
|
||||
}
|
||||
//colored border printed
|
||||
SDL_BlitSurface(graphics->smallImgs[stacksSorted[b % stacksSorted.size()].creature->idNumber], NULL, to, &genRect(32, 32, xPos, yPos));
|
||||
SDL_BlitSurface(graphics->smallImgs[s->creature->idNumber], NULL, to, &genRect(32, 32, xPos, yPos));
|
||||
xPos += 37;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetClipRect(to, &buf); //restoring previous clip_rect
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
@ -701,3 +697,39 @@ void IShowable::redraw()
|
||||
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;
|
||||
}
|
@ -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
|
||||
|
@ -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(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()
|
||||
|
@ -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);
|
||||
|
1
global.h
1
global.h
@ -302,6 +302,7 @@ extern DLL_EXPORT CLogger<5> tlog5; //gray - minor log info
|
||||
#define HANDLE_EXCEPTION \
|
||||
catch (const std::exception& e) { \
|
||||
tlog1 << e.what() << std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::exception * e) \
|
||||
{ \
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
ret = fastest;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; //no stacks have been found, so none of them will be found in next iterations
|
||||
}
|
||||
}
|
||||
for(j = i + 1; j < st.size(); j++)
|
||||
{
|
||||
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;
|
||||
@ -2798,3 +2913,67 @@ CPathsInfo::~CPathsInfo()
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
@ -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]
|
||||
|
||||
|
@ -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:
|
||||
|
@ -407,6 +407,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
|
||||
}
|
||||
|
||||
h & CGTeleport::objs;
|
||||
h & CGTeleport::gates;
|
||||
h & CGKeys::playerKeyMap;
|
||||
h & CGMagi::eyelist;
|
||||
|
||||
|
@ -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;
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user