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

Fixes for adventure AI: battles where AI is the attacker should work, fixed drawing AI heroes under FoW.

Restructured thread structure: no new thread on yourturn, instead of that introduced update() method called by thread dispatching GUI events. 

Further changes are planned.
This commit is contained in:
Michał W. Urbańczyk 2009-12-28 04:08:24 +00:00
parent e05c73d6ea
commit 01831e912a
16 changed files with 353 additions and 249 deletions

View File

@ -39,7 +39,7 @@ ui8 side; //who made this action: false - left, true - right player
*/
CBattleLogic::CBattleLogic(ICallback *cb, CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) :
m_iCurrentTurn(-2),
m_bIsAttacker(false),
m_bIsAttacker(!side),
m_cb(cb),
m_army1(army1),
m_army2(army2),
@ -261,7 +261,7 @@ BattleAction CBattleLogic::MakeDecision(int stackID)
MakeStatistics(stackID);
list<int> creatures;
int additionalInfo;
int additionalInfo = 0; //?
if (m_bEnemyDominates)
{

View File

@ -710,138 +710,140 @@ void CTerrainRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
int turns = pnode->turns;
amin(turns, 3);
if(LOCPLINT->adventureInt->selection->ID == TOWNI_TYPE)
if(LOCPLINT->adventureInt->selection)
{
if(obj)
if(LOCPLINT->adventureInt->selection->ID == TOWNI_TYPE)
{
if(obj->ID == TOWNI_TYPE)
if(obj)
{
CGI->curh->changeGraphic(0, 3);
if(obj->ID == TOWNI_TYPE)
{
CGI->curh->changeGraphic(0, 3);
}
else if(obj->ID == HEROI_TYPE)
{
CGI->curh->changeGraphic(0, 2);
}
}
else if(obj->ID == HEROI_TYPE)
else
{
CGI->curh->changeGraphic(0, 2);
CGI->curh->changeGraphic(0, 0);
}
}
else
else if(LOCPLINT->adventureInt->selection->ID == HEROI_TYPE)
{
CGI->curh->changeGraphic(0, 0);
}
}
else if(LOCPLINT->adventureInt->selection->ID == HEROI_TYPE)
{
const CGHeroInstance *h = static_cast<const CGHeroInstance *>(LOCPLINT->adventureInt->selection);
if(obj)
{
if(obj->ID == HEROI_TYPE)
const CGHeroInstance *h = static_cast<const CGHeroInstance *>(LOCPLINT->adventureInt->selection);
if(obj)
{
if(obj->tempOwner != LOCPLINT->playerID) //enemy hero TODO: allies
if(obj->ID == HEROI_TYPE)
{
if(obj->tempOwner != LOCPLINT->playerID) //enemy hero TODO: allies
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else //our hero
{
if(LOCPLINT->adventureInt->selection == obj)
CGI->curh->changeGraphic(0, 2);
else if(accessible)
CGI->curh->changeGraphic(0, 8 + turns*6);
else
CGI->curh->changeGraphic(0, 2);
}
}
else if(obj->ID == TOWNI_TYPE)
{
if(obj->tempOwner != LOCPLINT->playerID) //enemy town TODO: allies
{
if(accessible) {
const CGTownInstance* townObj = dynamic_cast<const CGTownInstance*>(obj);
// Show movement cursor for unguarded enemy towns, otherwise attack cursor.
if (townObj && townObj->army.slots.empty())
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 5 + turns*6);
} else {
CGI->curh->changeGraphic(0, 0);
}
}
else //our town
{
if(accessible)
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 3);
}
}
else if(obj->ID == 54) //monster
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else //our hero
else if(obj->ID == 8) //boat
{
if(LOCPLINT->adventureInt->selection == obj)
CGI->curh->changeGraphic(0, 2);
else if(accessible)
CGI->curh->changeGraphic(0, 8 + turns*6);
if(accessible)
CGI->curh->changeGraphic(0, 6 + turns*6);
else
CGI->curh->changeGraphic(0, 2);
CGI->curh->changeGraphic(0, 0);
}
}
else if(obj->ID == TOWNI_TYPE)
{
if(obj->tempOwner != LOCPLINT->playerID) //enemy town TODO: allies
else if (obj->ID == 33 || obj->ID == 219) // Garrison
{
if(accessible) {
const CGTownInstance* townObj = dynamic_cast<const CGTownInstance*>(obj);
if (accessible) {
const CGGarrison* garrObj = dynamic_cast<const CGGarrison*>(obj);
// Show movement cursor for unguarded enemy towns, otherwise attack cursor.
if (townObj && townObj->army.slots.empty())
CGI->curh->changeGraphic(0, 9 + turns*6);
else
// Show battle cursor for guarded enemy garrisons, otherwise movement cursor.
if (garrObj && garrObj->tempOwner != LOCPLINT->playerID
&& !garrObj->army.slots.empty())
{
CGI->curh->changeGraphic(0, 5 + turns*6);
}
else
{
CGI->curh->changeGraphic(0, 9 + turns*6);
}
} else {
CGI->curh->changeGraphic(0, 0);
}
}
else //our town
else
{
if(accessible)
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 3);
}
}
else if(obj->ID == 54) //monster
{
if(accessible)
CGI->curh->changeGraphic(0, 5 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else if(obj->ID == 8) //boat
{
if(accessible)
CGI->curh->changeGraphic(0, 6 + turns*6);
else
CGI->curh->changeGraphic(0, 0);
}
else if (obj->ID == 33 || obj->ID == 219) // Garrison
{
if (accessible) {
const CGGarrison* garrObj = dynamic_cast<const CGGarrison*>(obj);
// Show battle cursor for guarded enemy garrisons, otherwise movement cursor.
if (garrObj && garrObj->tempOwner != LOCPLINT->playerID
&& !garrObj->army.slots.empty())
{
CGI->curh->changeGraphic(0, 5 + turns*6);
if(pnode->land)
CGI->curh->changeGraphic(0, 9 + turns*6);
else
CGI->curh->changeGraphic(0, 28 + turns);
}
else
{
CGI->curh->changeGraphic(0, 9 + turns*6);
}
} else {
CGI->curh->changeGraphic(0, 0);
CGI->curh->changeGraphic(0, 0);
}
}
else
}
else //no objs
{
if(accessible)
{
if(pnode->land)
CGI->curh->changeGraphic(0, 9 + turns*6);
{
if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water)
CGI->curh->changeGraphic(0, 4 + turns*6);
else
CGI->curh->changeGraphic(0, 7 + turns*6); //anchor
}
else
CGI->curh->changeGraphic(0, 28 + turns);
CGI->curh->changeGraphic(0, 6 + turns*6);
}
else
CGI->curh->changeGraphic(0, 0);
}
}
else //no objs
{
if(accessible)
{
if(pnode->land)
{
if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water)
CGI->curh->changeGraphic(0, 4 + turns*6);
else
CGI->curh->changeGraphic(0, 7 + turns*6); //anchor
}
else
CGI->curh->changeGraphic(0, 6 + turns*6);
}
else
CGI->curh->changeGraphic(0, 0);
}
}
//tlog1 << "Tile " << pom << ": Turns=" << (int)pnode->turns <<" Move:=" << pnode->moveRemains <</* " (from " << ")" << */std::endl;
}
void CTerrainRect::hover(bool on)
@ -1515,7 +1517,6 @@ townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlis
pos.x = pos.y = 0;
pos.w = screen->w;
pos.h = screen->h;
active = 0;
selection = NULL;
townList.fun = boost::bind(&CAdvMapInt::selectionChanged,this);
LOCPLINT->adventureInt=this;
@ -1631,14 +1632,14 @@ void CAdvMapInt::fnextHero()
void CAdvMapInt::fendTurn()
{
LOCPLINT->makingTurn = false;
LOCPLINT->cb->endTurn();
}
void CAdvMapInt::activate()
{
if(active++)
if(isActive())
{
tlog1 << "Error: advmapint already active...\n";
active--;
return;
}
screenBuf = screen;
@ -1689,12 +1690,6 @@ void CAdvMapInt::deactivate()
infoBar.mode=-1;
LOCPLINT->cingconsole->deactivate();
if(--active)
{
tlog1 << "Error: advmapint still active...\n";
deactivate();
}
}
void CAdvMapInt::showAll(SDL_Surface *to)
{
@ -1807,16 +1802,16 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
switch(k)
{
case SDLK_i:
if(active)
if(isActive())
CAdventureOptions::showScenarioInfo();
return;
case SDLK_s:
if(active)
if(isActive())
GH.pushInt(new CSelectionScreen(saveGame));
return;
case SDLK_SPACE: //space - try to revisit current object with selected hero
{
if(!active)
if(!isActive())
return;
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance*>(selection);
if(h && key.state == SDL_PRESSED)
@ -1829,7 +1824,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
return;
case SDLK_RETURN:
{
if(!active || !selection || key.state != SDL_PRESSED)
if(!isActive() || !selection || key.state != SDL_PRESSED)
return;
if(selection->ID == HEROI_TYPE)
LOCPLINT->openHeroWindow(static_cast<const CGHeroInstance*>(selection));
@ -1883,7 +1878,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
k = arrowToNum(SDLKey(k));
}
if(!active || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero
if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero
break;
k -= SDLK_KP0 + 1;
@ -2003,7 +1998,7 @@ void CAdvMapInt::select(const CArmedInstance *sel )
void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
{
//adventure map scrolling with mouse
if(!SDL_GetKeyState(NULL)[SDLK_LCTRL] && active)
if(!SDL_GetKeyState(NULL)[SDLK_LCTRL] && isActive())
{
if(sEvent.x<15)
{
@ -2040,6 +2035,11 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
}
}
bool CAdvMapInt::isActive()
{
return active & ~CIntObject.KEYBOARD;
}
CAdventureOptions::CAdventureOptions()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;

View File

@ -138,7 +138,7 @@ public:
~CAdvMapInt();
int3 position; //top left corner of visible map part
int player, active;
int player;
enum{LEFT=1, RIGHT=2, UP=4, DOWN=8};
@ -202,5 +202,6 @@ public:
void handleRightClick(std::string text, tribool down, CIntObject * client);
void keyPressed(const SDL_KeyboardEvent & key);
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
bool isActive();
};
#endif // __CADVMAPINTERFACE_H__

View File

@ -2327,13 +2327,13 @@ void CBattleInterface::hexLclicked(int whichOne)
giveCommand(9,whichOne,activeStack);
}
}
else if(dest->owner != attackingHeroInstance->tempOwner
else if(dest->owner != actSt->owner
&& LOCPLINT->cb->battleCanShoot(activeStack, whichOne) ) //shooting
{
CGI->curh->changeGraphic(1, 6); //cursor should be changed
giveCommand(7,whichOne,activeStack);
}
else if(dest->owner != attackingHeroInstance->tempOwner) //attacking
else if(dest->owner != actSt->owner) //attacking
{
const CStack * actStack = LOCPLINT->cb->battleGetStackByID(activeStack);
int attackFromHex = -1; //hex from which we will attack chosen stack

View File

@ -69,7 +69,7 @@ static CClient *client;
SDL_Surface *screen = NULL, //main screen surface
*screen2 = NULL,//and hlp surface (used to store not-active interfaces layer)
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
static boost::thread *hhh;
static boost::thread *mainGUIThread;
SystemOptions GDefaultOptions;
VCMIDirs GVCMIDirs;
@ -214,8 +214,8 @@ int main(int argc, char** argv)
CGI->musich->playMusic(musicBase::mainMenu, -1);
new CGPreGame; //will set CGP pointer to itself
hhh = new boost::thread(&CGPreGame::run, CGP);
GH.curInt = new CGPreGame; //will set CGP pointer to itself
mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH));
listenForEvents();
return 0;
@ -472,18 +472,18 @@ static void listenForEvents()
{
if (client)
client->stop();
if (hhh) {
CGP->terminate = true;
hhh->join();
delete hhh;
hhh = NULL;
if (mainGUIThread)
{
GH.terminate = true;
mainGUIThread->join();
delete mainGUIThread;
mainGUIThread = NULL;
}
delete console;
console = NULL;
SDL_Delay(750);
SDL_Quit();
tlog0 << "Ending...\n";
break;
}
else if(LOCPLINT && ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4)
@ -501,9 +501,12 @@ static void listenForEvents()
delete ev;
continue;
}
else if (ev->type == SDL_USEREVENT && ev->user.code == 2) {
else if (ev->type == SDL_USEREVENT && ev->user.code == 2)
{
client->stop();
delete ev;
GH.curInt = CGP;
continue;
}
@ -517,6 +520,7 @@ static void listenForEvents()
void startGame(StartInfo * options)
{
GH.curInt =NULL;
if(gOnlyAI)
{
for (size_t i =0; i < options->playerInfos.size(); i++)
@ -534,22 +538,18 @@ void startGame(StartInfo * options)
SDL_PushEvent(&ev);
}
CClient cl;
client = new CClient;
if(options->mode == 0) //new game
{
cl.newGame(NULL, options);
client->newGame(NULL, options);
}
else //load game
{
std::string fname = options->mapname;
boost::algorithm::erase_last(fname,".vlgm1");
cl.loadGame(fname);
client->loadGame(fname);
}
client = &cl;
CGI->musich->stopMusic();
client->run();
LOCPLINT->terminate_cond.waitUntil(true);
client->endGame();
client = NULL;
client->connectionHandler = new boost::thread(&CClient::run, client);
}

View File

@ -40,6 +40,8 @@
#include <cmath>
#include <queue>
#include <sstream>
#include <boost/filesystem.hpp>
#ifdef min
#undef min
#endif
@ -102,12 +104,16 @@ CPlayerInterface::CPlayerInterface(int Player, int serial)
cingconsole = new CInGameConsole;
terminate = false;
terminate_cond.set(false);
firstCall = 1; //if loading will be overwritten in serialize
autosaveCount = 0;
}
CPlayerInterface::~CPlayerInterface()
{
delete pim;
delete showingDialog;
delete mainFPSmng;
if(adventureInt->active & CIntObject::KEYBOARD)
adventureInt->deactivateKeys();
delete adventureInt;
delete cingconsole;
@ -135,90 +141,58 @@ void CPlayerInterface::init(ICallback * CB)
}
void CPlayerInterface::yourTurn()
{
try
LOCPLINT = this;
makingTurn = true;
if(firstCall)
{
LOCPLINT = this;
makingTurn = true;
static bool firstCall = true;
static int autosaveCount = 0;
if(firstCall)
firstCall = false;
else
LOCPLINT->cb->save("Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
autosaveCount %= 5;
for(std::map<int,SDL_Surface*>::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes
SDL_FreeSurface(i->second);
graphics->heroWins.clear();
std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
for(int i=0;i<hh.size();i++)
{
SDL_Surface * pom = infoWin(hh[i]);
graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
}
/* TODO: This isn't quite right. First day in game should play
* NEWDAY. And we don't play NEWMONTH. */
int day = cb->getDate(1);
if (day != 1)
CGI->soundh->playSound(soundBase::newDay);
else
CGI->soundh->playSound(soundBase::newWeek);
adventureInt->infoBar.newDay(day);
//select first hero if available.
//TODO: check if hero is slept
if(wanderingHeroes.size())
adventureInt->select(wanderingHeroes[0]);
else
adventureInt->select(adventureInt->townList.items[0]);
adventureInt->showAll(screen);
autosaveCount = getLastIndex("Autosave_");
GH.pushInt(adventureInt);
adventureInt->activateKeys();
while(makingTurn) // main loop
if(firstCall > 0) //new game, not laoded
{
if (terminate)
break;
pim->lock();
//if there are any waiting dialogs, show them
if(dialogs.size() && !showingDialog->get())
{
showingDialog->set(true);
GH.pushInt(dialogs.front());
dialogs.pop_front();
}
GH.updateTime();
GH.handleEvents();
if(!adventureInt->active && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled
GH.totalRedraw();
else
GH.simpleRedraw();
CGI->curh->draw1();
CSDL_Ext::update(screen);
CGI->curh->draw2();
pim->unlock();
SDL_framerateDelay(mainFPSmng);
int index = getLastIndex("Newgame_Autosave_");
index %= SAVES_COUNT;
cb->save("Newgame_Autosave_" + boost::lexical_cast<std::string>(index + 1));
}
firstCall = 0;
}
else
{
LOCPLINT->cb->save("Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
autosaveCount %= 5;
}
adventureInt->deactivateKeys();
GH.popInt(adventureInt);
for(std::map<int,SDL_Surface*>::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes
SDL_FreeSurface(i->second);
graphics->heroWins.clear();
std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
for(int i=0;i<hh.size();i++)
{
SDL_Surface * pom = infoWin(hh[i]);
graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
}
cb->endTurn();
} HANDLE_EXCEPTION;
/* TODO: This isn't quite right. First day in game should play
* NEWDAY. And we don't play NEWMONTH. */
int day = cb->getDate(1);
if (day != 1)
CGI->soundh->playSound(soundBase::newDay);
else
CGI->soundh->playSound(soundBase::newWeek);
if (terminate)
terminate_cond.set(true);
adventureInt->infoBar.newDay(day);
//select first hero if available.
//TODO: check if hero is slept
if(wanderingHeroes.size())
adventureInt->select(wanderingHeroes[0]);
else
adventureInt->select(adventureInt->townList.items[0]);
adventureInt->showAll(screen);
GH.curInt = this;
}
inline void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const int & hid)
@ -1338,6 +1312,7 @@ void CPlayerInterface::serialize( CISer<CLoadFile> &h, const int version )
{
serializeTempl(h,version);
sysOpts.apply();
firstCall = -1;
}
void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero)
@ -1526,7 +1501,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
LOCPLINT->adventureInt->centerOn (pos);
if(focusTime)
{
bool activeAdv = (GH.topInt() == adventureInt && adventureInt->active);
bool activeAdv = (GH.topInt() == adventureInt && adventureInt->isActive());
if(activeAdv)
adventureInt->deactivate();
@ -1551,6 +1526,64 @@ bool CPlayerInterface::ctrlPressed() const
return SDL_GetKeyState(NULL)[SDLK_LCTRL] || SDL_GetKeyState(NULL)[SDLK_RCTRL];
}
void CPlayerInterface::update()
{
pim->lock();
//if there are any waiting dialogs, show them
if(dialogs.size() && !showingDialog->get())
{
showingDialog->set(true);
GH.pushInt(dialogs.front());
dialogs.pop_front();
}
GH.updateTime();
GH.handleEvents();
if(!adventureInt->isActive() && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled
GH.totalRedraw();
else
GH.simpleRedraw();
CGI->curh->draw1();
CSDL_Ext::update(screen);
CGI->curh->draw2();
pim->unlock();
SDL_framerateDelay(mainFPSmng);
}
int CPlayerInterface::getLastIndex( std::string namePrefix)
{
using namespace boost::filesystem;
using namespace boost::algorithm;
std::map<std::time_t, int> dates; //save number => datestamp
directory_iterator enddir;
for (directory_iterator dir(DATA_DIR "/Games"); dir!=enddir; dir++)
{
if(is_regular(dir->status()))
{
std::string name = dir->path().leaf();
if(starts_with(name, namePrefix) && ends_with(name, ".vlgm1"))
{
char nr = name[namePrefix.size()];
if(std::isdigit(nr))
{
dates[last_write_time(dir->path())] = boost::lexical_cast<int>(nr);
}
}
}
}
if(dates.size())
return (--dates.end())->second; //return latest file number
return 0;
}
void SystemOptions::setMusicVolume( int newVolume )
{
musicVolume = newVolume;

View File

@ -7,6 +7,7 @@
#include <map>
#include <list>
#include <algorithm>
#include "GUIBase.h"
#ifdef __GNUC__
#define sprintf_s snprintf
@ -106,7 +107,7 @@ struct SystemOptions
extern SystemOptions GDefaultOptions; //defined and inited in CMT.cpp, stores default settings loaded with application
class CPlayerInterface : public CGameInterface
class CPlayerInterface : public CGameInterface, public IUpdateable
{
public:
//minor interfaces
@ -114,6 +115,9 @@ public:
boost::recursive_mutex *pim;
bool makingTurn; //if player is already making his turn
int firstCall; // -1 - just loaded game; 1 - just started game; 0 otherwise
int autosaveCount;
static const int SAVES_COUNT = 5;
SystemOptions sysOpts;
@ -131,8 +135,11 @@ public:
std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
void update();
void recreateWanderingHeroes();
const CGHeroInstance *getWHero(int pos); //returns NULL if position is not valid
int getLastIndex(std::string namePrefix);
//overloaded funcs from CGameInterface
void buildChanged(const CGTownInstance *town, int buildingID, int what); //what: 1 - built, 2 - demolished

View File

@ -122,38 +122,11 @@ void CMenuScreen::moveTo( CMenuScreen *next )
GH.pushInt(next);
}
void CGPreGame::run()
{
GH.handleEvents();
while(!terminate)
{
if (GH.listInt.size() == 0)
{
#ifdef _WIN32
CGI->videoh->open("ACREDIT.SMK");
#else
CGI->videoh->open("ACREDIT.SMK", true, false);
#endif
GH.pushInt(scrs[mainMenu]);
}
CGI->curh->draw1();
SDL_Flip(screen);
CGI->curh->draw2();
SDL_Delay(20); //give time for other apps
GH.topInt()->show(screen);
GH.updateTime();
GH.handleEvents();
}
}
CGPreGame::CGPreGame()
{
GH.defActionsDef = 63;
CGP = this;
mainbg = BitmapHandler::loadBitmap("ZPIC1005.bmp");
terminate = false;
for(int i = 0; i < ARRAY_COUNT(scrs); i++)
scrs[i] = new CMenuScreen((EState)i);
@ -193,6 +166,26 @@ void CGPreGame::disposeGraphics()
SDL_FreeSurface(nTown);
}
void CGPreGame::update()
{
if (GH.listInt.size() == 0)
{
#ifdef _WIN32
CGI->videoh->open("ACREDIT.SMK");
#else
CGI->videoh->open("ACREDIT.SMK", true, false);
#endif
GH.pushInt(scrs[mainMenu]);
}
CGI->curh->draw1();
SDL_Flip(screen);
CGI->curh->draw2();
GH.topInt()->show(screen);
GH.updateTime();
GH.handleEvents();
}
CSelectionScreen::CSelectionScreen( EState Type )
{
OBJ_CONSTRUCTION_CAPTURING_ALL;

View File

@ -212,7 +212,7 @@ public:
~CScenarioInfo();
};
class CGPreGame : public CIntObject
class CGPreGame : public CIntObject, public IUpdateable
{
public:
SDL_Surface *mainbg;
@ -222,10 +222,9 @@ public:
CDefHandler *bonuses;
CDefHandler *victory, *loss;
bool terminate;
CGPreGame();
~CGPreGame();
void update();
void run();
void openSel(EState type);
void loadGraphics();

View File

@ -83,6 +83,7 @@ public:
void CClient::init()
{
connectionHandler = NULL;
pathInfo = NULL;
applier = new CCLApplier;
IObjectInterface::cb = this;
@ -124,17 +125,14 @@ void CClient::waitForMoveAndSend(int color)
}HANDLE_EXCEPTION
tlog1 << "We should not be here!" << std::endl;
}
void CClient::run()
{
try
{
CPack *pack;
while(1)
while(!terminate)
{
if (terminate) {
break;
}
//get the package from the server
{
boost::unique_lock<boost::mutex> lock(*serv->rmx);
@ -143,7 +141,8 @@ void CClient::run()
tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
}
if (terminate) {
if (terminate)
{
delete pack;
break;
}
@ -174,6 +173,7 @@ void CClient::stop()
// Tell the network thread and interface thread to reach a stable state
terminate = true;
LOCPLINT->terminate = true;
endGame();
}
void CClient::save(const std::string & fname)
@ -190,6 +190,10 @@ void CClient::save(const std::string & fname)
void CClient::endGame()
{
tlog0 << "\n\nEnding current game!" << std::endl;
GH.curInt = NULL;
GH.topInt()->deactivate();
GH.listInt.clear();
GH.objsToBlit.clear();
delete CGI->mh;
CGI->mh = NULL;
@ -197,6 +201,7 @@ void CClient::endGame()
delete CGI->state;
CGI->state = NULL;
LOCPLINT = NULL;
while (!playerint.empty())
{
delete playerint.begin()->second;
@ -208,7 +213,8 @@ void CClient::endGame()
delete cb;
}
if (serv) {
if (serv)
{
tlog3 << "Connection has been requested to be closed.\n";
boost::unique_lock<boost::mutex>(*serv->wmx);
*serv << &CloseServer();
@ -219,6 +225,10 @@ void CClient::endGame()
serv = NULL;
tlog3 << "Our socket has been closed." << std::endl;
}
connectionHandler->join();
delete connectionHandler;
connectionHandler = NULL;
}
void CClient::loadGame( const std::string & fname )

View File

@ -81,7 +81,8 @@ public:
void run();
void stop();
bool terminate; // tell to terminate
bool terminate; // tell to terminate
boost::thread *connectionHandler; //thread running run() method
//////////////////////////////////////////////////////////////////////////
//from IGameCallback

View File

@ -331,6 +331,32 @@ void CGuiHandler::fakeMouseMove()
handleMoveInterested(sme);
}
void CGuiHandler::run()
{
try
{
while(!terminate)
{
if(curInt)
curInt->update();
SDL_Delay(20); //give time for other apps
}
} HANDLE_EXCEPTION
}
CGuiHandler::CGuiHandler()
:lastClick(-500, -500)
{
curInt = NULL;
current = NULL;
terminate = false;
}
CGuiHandler::~CGuiHandler()
{
}
void CIntObject::activateLClick()
{
GH.lclickable.push_front(this);
@ -462,6 +488,8 @@ CIntObject::CIntObject()
pos.y = parent->pos.y;
}
}
else
parent = NULL;
}
void CIntObject::show( SDL_Surface * to )

View File

@ -287,6 +287,13 @@ public:
virtual ~IShowActivable(){}; //d-tor
};
class IUpdateable
{
public:
virtual void update()=0;
virtual ~IUpdateable(){}; //d-tor
};
class CIntObject : public IShowActivable //interface object
{
public:
@ -440,10 +447,15 @@ public:
std::vector<IShowable*> objsToBlit;
SDL_Event * current; //current event
IUpdateable *curInt;
Point lastClick;
unsigned lastClickTime;
bool terminate;
CGuiHandler();
~CGuiHandler();
void run();
void totalRedraw(); //forces total redraw (using showAll)
void simpleRedraw(); //update only top interface and draw background from buffer
void popInt(IShowActivable *top); //removes given interface from the top and activates next

View File

@ -150,7 +150,18 @@ void RemoveObject::applyCl( CClient *cl )
void TryMoveHero::applyFirstCl( CClient *cl )
{
CGHeroInstance *h = GS(cl)->getHero(id);
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK)
//check if playerint will have the knowledge about movement - if not, directly update maphandler
for(std::map<ui8, CGameInterface*>::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++)
{
if(i->first >= PLAYER_LIMIT)
continue;
PlayerState &p = GS(cl)->players[i->first];
if((p.fogOfWarMap[start.x-1][start.y][start.z] || p.fogOfWarMap[end.x-1][end.y][end.z]) && p.human)
humanKnows = true;
}
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK || !humanKnows)
CGI->mh->removeObject(h);
@ -179,11 +190,17 @@ void TryMoveHero::applyCl( CClient *cl )
for(std::map<ui8, CGameInterface*>::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++)
{
if(i->first >= PLAYER_LIMIT) continue;
if(GS(cl)->players[i->first].fogOfWarMap[start.x-1][start.y][start.z] || GS(cl)->players[i->first].fogOfWarMap[end.x-1][end.y][end.z])
PlayerState &p = GS(cl)->players[i->first];
if(p.fogOfWarMap[start.x-1][start.y][start.z] || p.fogOfWarMap[end.x-1][end.y][end.z])
{
i->second->heroMoved(*this);
}
}
if(!humanKnows) //maphandler didn't get update from playerint, do it now
{ //TODO: restructure nicely
CGI->mh->printObject(h);
}
}
void SetGarrisons::applyCl( CClient *cl )
@ -538,7 +555,7 @@ void PlayerBlocked::applyCl( CClient *cl )
void YourTurn::applyCl( CClient *cl )
{
boost::thread(boost::bind(&CGameInterface::yourTurn,cl->playerint[player]));
INTERFACE_CALL_IF_PRESENT(player,yourTurn);
}
void SaveGame::applyCl(CClient *cl)

View File

@ -187,7 +187,8 @@ void CLodHandler::init(std::string lodFile, std::string dirName)
LOD.open(lodFile.c_str(), std::ios::in | std::ios::binary);
if (!LOD.is_open()) {
if (!LOD.is_open())
{
tlog1 << "Cannot open " << lodFile << std::endl;
return;
}

View File

@ -405,7 +405,7 @@ struct RemoveObject : public CPackForClient //500
};
struct TryMoveHero : public CPackForClient //501
{
TryMoveHero(){type = 501;};
TryMoveHero(){type = 501;humanKnows=false;};
void applyFirstCl(CClient *cl);
void applyCl(CClient *cl);
void applyGs(CGameState *gs);
@ -420,6 +420,8 @@ struct TryMoveHero : public CPackForClient //501
int3 start, end;
std::set<int3> fowRevealed; //revealed tiles
bool humanKnows; //used locally during applying to client
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & result & start & end & movePoints & fowRevealed;