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

* fixed crash on closing application

* unified yes/no and selection dialog interface calls
* VCMI won't anymore be always giving all three stacks in the starting armies
* fix for drawing starting army creatures count
* support for School of Magic
* support for School of War
* support for Pillar of Fire
* minor changes
This commit is contained in:
Michał W. Urbańczyk 2009-04-11 01:32:50 +00:00
parent 7a9e323297
commit d72d988a9c
20 changed files with 362 additions and 248 deletions

View File

@ -63,6 +63,12 @@ void CGeniusAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector
{
callback(rand() % skills.size());
}
void CGeniusAI::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel )
{
m_cb->selectionMade(cancel ? 0 : 1, askID);
}
/**
* occurs AFTER every action taken by any stack or by the hero
*/

View File

@ -190,6 +190,7 @@ public:
virtual void heroMoved(const HeroMoveDetails &);
virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {};
virtual void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel);
virtual void tileRevealed(int3 pos){};
virtual void tileHidden(int3 pos){};
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);

View File

@ -1245,6 +1245,7 @@ endTurn(CGI->generaltexth->zelp[302].first,CGI->generaltexth->zelp[302].second,
heroList(ADVOPT.hlistSize),
townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlistAD)//(5,&genRect(192,48,747,196),747,196,747,372),
{
active = 0;
subInt = NULL;
selection = NULL;
townList.fun = boost::bind(&CAdvMapInt::selectionChanged,this);
@ -1363,6 +1364,10 @@ void CAdvMapInt::fendTurn()
void CAdvMapInt::activate()
{
if(active++)
{
tlog1 << "Error: advmapint already active...\n";
}
if(subInt == heroWindow)
{
heroWindow->activate();
@ -1392,6 +1397,10 @@ void CAdvMapInt::activate()
}
void CAdvMapInt::deactivate()
{
if(--active)
{
tlog1 << "Error: advmapint still active...\n";
}
if(subInt == heroWindow)
{
heroWindow->deactivate();

View File

@ -107,7 +107,7 @@ public:
~CAdvMapInt();
int3 position; //top left corner of visible map part
int player;
int player, active;
std::vector<CDefHandler *> gems;

View File

@ -32,6 +32,7 @@ class ICallback
{
public:
virtual bool moveHero(const CGHeroInstance *h, int3 dst) const =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
virtual void selectionMade(int selection, int asker) =0;
virtual int swapCreatures(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//swaps creatures between two posiibly different garrisons // TODO: AI-unsafe code - fix it!
virtual int mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//joins first stack tothe second (creatures must be same type)
virtual int splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)=0;//split creatures from the first stack

View File

@ -69,8 +69,9 @@ public:
virtual void init(ICallback * CB){};
virtual void receivedResource(int type, int val){};
virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components){};
virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
//virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
virtual void tileHidden(const std::set<int3> &pos){};
virtual void tileRevealed(const std::set<int3> &pos){};
virtual void yourTurn(){};

View File

@ -45,11 +45,14 @@
#if __MINGW32__
#undef main
#endif
std::string NAME = NAME_VER + std::string(" (client)");
SDL_Surface * screen, * screen2;
std::string NAME = NAME_VER + std::string(" (client)"); //application name
SDL_Surface * screen; //main screen surface
std::queue<SDL_Event*> events;
boost::mutex eventsM;
TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
void processCommand(const std::string &message, CClient *&client);
#ifndef __GNUC__
int _tmain(int argc, _TCHAR* argv[])
@ -196,11 +199,11 @@ int main(int argc, char** argv)
SDL_WaitEvent(ev);
if((ev->type==SDL_QUIT) || (ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4 && (ev->key.keysym.mod & KMOD_ALT)))
{
LOCPLINT->pim->lock();
cl.close();
#ifndef __unix__
::console->killConsole(console->native_handle());
#endif
LOCPLINT->pim->lock();
SDL_Delay(750);
tlog0 << "Ending...\n";
exit(EXIT_SUCCESS);

View File

@ -564,16 +564,16 @@ void CGarrisonInt::deactivate()
CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons)
{
ID = -1;
for(int i=0;i<Buttons.size();i++)
{
buttons.push_back(new AdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
if(!Buttons[i].second) //if no function, then by default we'll set it to close
{
buttons[i]->assignedKeys.insert(SDLK_RETURN);
buttons[i]->assignedKeys.insert(SDLK_ESCAPE);
buttons[i]->callback += boost::bind(&CInfoWindow::close,this);
}
buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
}
buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
for(int i=0;i<comps.size();i++)
{
components.push_back(comps[i]);
@ -582,6 +582,7 @@ CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const st
}
CInfoWindow::CInfoWindow()
{
ID = -1;
}
void CInfoWindow::close()
{
@ -906,15 +907,22 @@ void CSelWindow::selectionChange(unsigned to)
blitAt(pom->getImg(),pom->pos.x-pos.x,pom->pos.y-pos.y,bitmap);
}
}
CSelWindow::CSelWindow(std::string text, int player, int charperline, std::vector<CSelectableComponent*> &comps, std::vector<std::pair<std::string,boost::function<void()> > > &Buttons)
CSelWindow::CSelWindow(const std::string &text, int player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, int askID)
{
ID = askID;
for(int i=0;i<Buttons.size();i++)
{
buttons.push_back(new AdventureMapButton("","",(Buttons[i].second)?(Buttons[i].second):(boost::bind(&CInfoWindow::close,this)),0,0,Buttons[i].first));
buttons.push_back(new AdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
if(!i && askID >= 0)
buttons.back()->callback += boost::bind(&CSelWindow::madeChoice,this);
buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
}
if(Buttons.size() == 1) //only one button - assign enter to it
buttons[0]->assignedKeys.insert(SDLK_RETURN);
buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
if(buttons.size() > 1 && askID >= 0) //cancel button functionality
buttons.back()->callback += boost::bind(&ICallback::selectionMade,LOCPLINT->cb,0,askID);
for(int i=0;i<comps.size();i++)
{
@ -928,6 +936,14 @@ CSelWindow::CSelWindow(std::string text, int player, int charperline, std::vecto
void CSelWindow::close()
{
deactivate();
LOCPLINT->showingDialog->setn(false);
delete this;
}
void CSelWindow::madeChoice()
{
if(ID < 0)
return;
int ret = -1;
for (int i=0;i<components.size();i++)
{
@ -936,11 +952,9 @@ void CSelWindow::close()
ret = i;
}
}
LOCPLINT->curint->activate();
LOCPLINT->showingDialog->setn(false);
LOCPLINT->cb->selectionMade(ret,ID);
delete this;
LOCPLINT->cb->selectionMade(ret+1,ID);
}
CButtonBase::CButtonBase()
{
bitmapOffset = 0;
@ -1130,95 +1144,102 @@ void CPlayerInterface::init(ICallback * CB)
}
void CPlayerInterface::yourTurn()
{
LOCPLINT = this;
makingTurn = true;
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++)
try
{
SDL_Surface * pom = infoWin(hh[i]);
graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
}
LOCPLINT = this;
makingTurn = true;
adventureInt->infoBar.newDay(cb->getDate(1));
static int autosaveCount = 0;
LOCPLINT->cb->save("Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
autosaveCount %= 5;
//select first hero if available.
//TODO: check if hero is slept
if(adventureInt->heroList.items.size())
adventureInt->select(adventureInt->heroList.items[0].first);
else
adventureInt->select(adventureInt->townList.items[0]);
adventureInt->activate();
timeHandler th;
th.getDif();
for(;makingTurn;) // main loop
{
updateWater();
pim->lock();
//if there are any waiting dialogs, show them
if(dialogs.size() && !showingDialog->get())
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++)
{
dialogs.front()->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
showingDialog->set(true);
curint->deactivate(); //dezaktywacja starego interfejsu
dialogs.front()->activate();
LOCPLINT->objsToBlit.push_back(dialogs.front());
dialogs.pop_front();
SDL_Surface * pom = infoWin(hh[i]);
graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
}
int tv = th.getDif();
std::list<TimeInterested*> hlp = timeinterested;
for (std::list<TimeInterested*>::iterator i=hlp.begin(); i != hlp.end();i++)
{
if(!vstd::contains(timeinterested,*i)) continue;
if ((*i)->toNextTick>=0)
(*i)->toNextTick-=tv;
if ((*i)->toNextTick<0)
(*i)->tick();
}
LOCPLINT->adventureInt->updateScreen = false;
adventureInt->infoBar.newDay(cb->getDate(1));
while(true)
//select first hero if available.
//TODO: check if hero is slept
if(adventureInt->heroList.items.size())
adventureInt->select(adventureInt->heroList.items[0].first);
else
adventureInt->select(adventureInt->townList.items[0]);
adventureInt->activate();
timeHandler th;
th.getDif();
while(makingTurn) // main loop
{
SDL_Event *ev = NULL;
updateWater();
pim->lock();
//if there are any waiting dialogs, show them
if(dialogs.size() && !showingDialog->get())
{
boost::unique_lock<boost::mutex> lock(eventsM);
if(!events.size())
{
break;
}
else
{
ev = events.front();
events.pop();
}
dialogs.front()->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
showingDialog->set(true);
curint->deactivate(); //dezaktywacja starego interfejsu
dialogs.front()->activate();
LOCPLINT->objsToBlit.push_back(dialogs.front());
dialogs.pop_front();
}
handleEvent(ev);
delete ev;
}
if (curint == adventureInt) //stuff for advMapInt
{
adventureInt->update();
int tv = th.getDif();
std::list<TimeInterested*> hlp = timeinterested;
for (std::list<TimeInterested*>::iterator i=hlp.begin(); i != hlp.end();i++)
{
if(!vstd::contains(timeinterested,*i)) continue;
if ((*i)->toNextTick>=0)
(*i)->toNextTick-=tv;
if ((*i)->toNextTick<0)
(*i)->tick();
}
LOCPLINT->adventureInt->updateScreen = false;
while(true)
{
SDL_Event *ev = NULL;
{
boost::unique_lock<boost::mutex> lock(eventsM);
if(!events.size())
{
break;
}
else
{
ev = events.front();
events.pop();
}
}
handleEvent(ev);
delete ev;
}
if (curint == adventureInt) //stuff for advMapInt
{
adventureInt->update();
}
for(int i=0;i<objsToBlit.size();i++)
objsToBlit[i]->show();
CGI->curh->draw1();
CSDL_Ext::update(screen);
CGI->curh->draw2();
pim->unlock();
SDL_framerateDelay(mainFPSmng);
}
for(int i=0;i<objsToBlit.size();i++)
objsToBlit[i]->show();
CGI->curh->draw1();
CSDL_Ext::update(screen);
CGI->curh->draw2();
pim->unlock();
SDL_framerateDelay(mainFPSmng);
}
adventureInt->deactivate();
cb->endTurn();
adventureInt->deactivate();
cb->endTurn();
} HANDLE_EXCEPTION
}
inline void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const int & hid)
@ -2033,24 +2054,6 @@ void CPlayerInterface::receivedResource(int type, int val)
castleInt->resdatabar->draw();
}
void CPlayerInterface::showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID)
//void CPlayerInterface::showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
LOCPLINT->showingDialog->setn(true);
adventureInt->deactivate(); //dezaktywacja starego interfejsu
std::vector<CSelectableComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new CSelectableComponent(*components[i])); //will be deleted by CSelWindow::close
std::vector<std::pair<std::string,boost::function<void()> > > pom;
pom.push_back(std::pair<std::string,boost::function<void()> >("IOKAY.DEF",0));
CSelWindow * temp = new CSelWindow(text,playerID,35,intComps,pom);
LOCPLINT->objsToBlit.push_back(temp);
temp->activate();
temp->ID = askID;
intComps[0]->clickLeft(true);
}
void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16>& skills, boost::function<void(ui32)> &callback)
{
{
@ -2424,6 +2427,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
dialogs.push_back(temp);
}
}
void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool deactivateCur, bool DelComps)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
@ -2431,8 +2435,8 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto
if(deactivateCur)
curint->deactivate(); //dezaktywacja starego interfejsu
std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",boost::bind(&IActivable::activate,curint)));
pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",boost::bind(&IActivable::activate,curint)));
CInfoWindow * temp = new CInfoWindow(text,playerID,36,components,pom);
temp->delComps = DelComps;
for(int i=0;i<onYes.funcs.size();i++)
@ -2440,37 +2444,46 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto
for(int i=0;i<onNo.funcs.size();i++)
temp->buttons[1]->callback += onNo.funcs[i];
//if(onYes)
// temp->buttons[0]->callback += boost::bind(&CInfoWindow::close,temp);
//if(onNo)
// temp->buttons[1]->callback += boost::bind(&CInfoWindow::close,temp);
temp->activate();
LOCPLINT->objsToBlit.push_back(temp);
}
void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID )
void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel )
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
LOCPLINT->showingDialog->setn(false);
curint->deactivate(); //dezaktywacja starego interfejsu
std::vector<SComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new SComponent(*components[i])); //will be deleted by CSelWindow::close
std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
CInfoWindow * temp = new CInfoWindow(text,playerID,36,intComps,pom);
temp->buttons[0]->callback += boost::bind(&IActivable::activate,curint);
temp->buttons[1]->callback += boost::bind(&IActivable::activate,curint);
temp->buttons[0]->callback += boost::bind(&CCallback::selectionMade,cb,0,askID);
temp->buttons[1]->callback += boost::bind(&CCallback::selectionMade,cb,1,askID);
temp->delComps = true;
if(!selection && cancel) //simple yes/no dialog
{
std::vector<SComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new SComponent(components[i])); //will be deleted by close in window
showYesNoDialog(text,intComps,boost::bind(&CCallback::selectionMade,cb,1,askID),boost::bind(&CCallback::selectionMade,cb,0,askID),true,true);
}
else if(selection)
{
std::vector<CSelectableComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new CSelectableComponent(components[i])); //will be deleted by CSelWindow::close
adventureInt->deactivate(); //dezaktywacja starego interfejsu
std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",boost::bind(&IActivable::activate,curint)));
if(cancel)
{
pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",boost::bind(&IActivable::activate,curint)));
}
CSelWindow * temp = new CSelWindow(text,playerID,35,intComps,pom,askID);
LOCPLINT->objsToBlit.push_back(temp);
temp->activate();
intComps[0]->clickLeft(true);
}
temp->activate();
LOCPLINT->objsToBlit.push_back(temp);
}
void CPlayerInterface::removeObjToBlit(IShowable* obj)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);

View File

@ -358,7 +358,8 @@ class CSelWindow : public CInfoWindow //component selection window
public:
void selectionChange(unsigned to);
void close();
CSelWindow(std::string text, int player, int charperline, std::vector<CSelectableComponent*> &comps, std::vector<std::pair<std::string,boost::function<void()> > > &Buttons); //c-tor
void madeChoice(); //looks for selected component and calls callback
CSelWindow(const std::string& text, int player, int charperline ,const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, int askID); //c-tor
CSelWindow(){}; //c-tor
//notification - this class inherits important destructor from CInfoWindow
};
@ -544,8 +545,9 @@ public:
void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
void receivedResource(int type, int val);
void showInfoDialog(const std::string &text, const std::vector<Component*> &components);
void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
//void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
//void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
void tileHidden(const std::set<int3> &pos);
void tileRevealed(const std::set<int3> &pos);
void yourTurn();

View File

@ -109,29 +109,32 @@ void CClient::waitForMoveAndSend(int color)
}
void CClient::run()
{
CPack *pack;
while(1)
try
{
tlog5 << "Listening... ";
*serv >> pack;
tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
if(apply)
CPack *pack;
while(1)
{
apply->applyOnClBefore(this,pack);
tlog5 << "\tMade first apply on cl\n";
gs->apply(pack);
tlog5 << "\tApplied on gs\n";
apply->applyOnClAfter(this,pack);
tlog5 << "\tMade second apply on cl\n";
tlog5 << "Listening... ";
*serv >> pack;
tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
if(apply)
{
apply->applyOnClBefore(this,pack);
tlog5 << "\tMade first apply on cl\n";
gs->apply(pack);
tlog5 << "\tApplied on gs\n";
apply->applyOnClAfter(this,pack);
tlog5 << "\tMade second apply on cl\n";
}
else
{
tlog5 << "Message cannot be applied, cannot find applier!\n";
}
delete pack;
pack = NULL;
}
else
{
tlog5 << "Message cannot be applied, cannot find applier!\n";
}
delete pack;
pack = NULL;
}
} HANDLE_EXCEPTION(tlog1 << "Lost connection to server, ending listening thread!\n");
}
void CClient::close()

View File

@ -77,8 +77,8 @@ public:
void changePrimSkill(int ID, int which, int val, bool abs=false){};
void changeSecSkill(int ID, int which, int val, bool abs=false){};
void showInfoDialog(InfoWindow *iw){};
void showYesNoDialog(YesNoDialog *iw, const CFunctionList<void(ui32)> &callback){};
void showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback){}; //returns question id
void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback){};
ui32 showBlockingDialog(BlockingDialog *iw){return 0;}; //synchronous version of above
void giveResource(int player, int which, int val){};
void showCompInfo(ShowInInfobox * comp){};
void heroVisitCastle(int obj, int heroID){};

View File

@ -282,28 +282,11 @@ void HeroLevelUp::applyCl( CClient *cl )
}
}
void SelectionDialog::applyCl( CClient *cl )
void BlockingDialog::applyCl( CClient *cl )
{
std::vector<Component*> comps;
for(size_t i=0; i < components.size(); ++i) {
comps.push_back(&components[i]);
}
std::string str = toString(text);
if(vstd::contains(cl->playerint,player))
cl->playerint[player]->showSelDialog(str,comps,id);
else
tlog2 << "We received SelectionDialog for not our player...\n";
}
void YesNoDialog::applyCl( CClient *cl )
{
std::vector<Component*> comps;
for(size_t i=0; i < components.size(); ++i) {
comps.push_back(&components[i]);
}
std::string str = toString(text);
if(vstd::contains(cl->playerint,player))
cl->playerint[player]->showYesNoDialog(str,comps,id);
cl->playerint[player]->showBlockingDialog(str,components,id,selection(),cancel());
else
tlog2 << "We received YesNoDialog for not our player...\n";
}
@ -417,7 +400,7 @@ void EndAction::applyCl( CClient *cl )
void SystemMessage::applyCl( CClient *cl )
{
std::ostringstream str;
str << "System message from server: " << text;
str << "System message: " << text;
tlog4 << str.str() << std::endl;
if(LOCPLINT)

View File

@ -511,6 +511,16 @@ void CGHeroInstance::initHero()
if (!army.slots.size()) //standard army//initial army
{
int pom, pom2=0;
int x = 0; //how many stacks will hero receives <1 - 3>
pom = ran()%100;
if(pom < 5)
x = 1;
else if(pom < 67)
x = 2;
else
x = 3;
for(int x=0;x<3;x++)
{
pom = (VLC->creh->nameToID[type->refTypeStack[x]]);
@ -529,10 +539,8 @@ void CGHeroInstance::initHero()
continue;
}
army.slots[x-pom2].first = pom;
if((pom = (type->highStack[x]-type->lowStack[x])) > 0)
army.slots[x-pom2].second = (ran()%pom)+type->lowStack[x];
else
army.slots[x-pom2].second = +type->lowStack[x];
pom = type->highStack[x] - type->lowStack[x];
army.slots[x-pom2].second = ran()%(pom+1) + type->lowStack[x];
army.formation = false;
}
}
@ -540,7 +548,7 @@ void CGHeroInstance::initHero()
boost::algorithm::replace_first(hoverName,"%s",name);
boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name);
//clear all bonuses from artifacts and give those from artifacts
//clear all bonuses from artifacts (if present) and give them again
std::remove_if(bonuses.begin(), bonuses.end(), boost::bind(HeroBonus::IsFrom,_1,HeroBonus::ARTIFACT,0xffffff));
for (std::map<ui16,ui32>::iterator ari = artifWorn.begin(); ari != artifWorn.end(); ari++)
{
@ -928,8 +936,18 @@ void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
if(visitors.find(h->id)==visitors.end())
{
onNAHeroVisit(h->id, false);
if(ID != 102 && ID!=4 && ID!=41) //not tree nor arena nor library of enlightenment
switch(ID)
{
case 102: //tree
case 4: //arena
case 41://library
case 47: //School of Magic
case 107://School of War
break;
default:
cb->setObjProperty(id,4,h->id); //add to the visitors
break;
}
}
else
{
@ -947,7 +965,7 @@ void CGVisitableOPH::initObj()
void CGVisitableOPH::treeSelected( int heroID, int resType, int resVal, int expVal, ui32 result ) const
{
if(result==0) //player agreed to give res for exp
if(result) //player agreed to give res for exp
{
cb->giveResource(cb->getOwner(heroID),resType,-resVal); //take resource
cb->changePrimSkill(heroID,4,expVal); //give exp
@ -992,6 +1010,12 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
case 41:
ot = 66;
break;
case 47: //School of Magic
ot = 71;
break;
case 107://School of War
ot = 158;
break;
}
if (!alreadyVisited)
{
@ -999,12 +1023,12 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
{
case 4: //arena
{
SelectionDialog sd;
BlockingDialog sd(false,true);
sd.text << std::pair<ui8,ui32>(11,ot);
sd.components.push_back(Component(0,0,2,0));
sd.components.push_back(Component(0,1,2,0));
sd.player = cb->getOwner(heroID);
cb->showSelectionDialog(&sd,boost::bind(&CGVisitableOPH::arenaSelected,this,heroID,_1));
cb->showBlockingDialog(&sd,boost::bind(&CGVisitableOPH::arenaSelected,this,heroID,_1));
return;
}
case 51:
@ -1030,7 +1054,7 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
cb->changePrimSkill(heroID,4,val);
break;
}
case 102:
case 102://tree
{
const CGHeroInstance *h = cb->getHero(heroID);
val = VLC->heroh->reqExp(h->level+val) - VLC->heroh->reqExp(h->level);
@ -1071,15 +1095,15 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
return;
}
YesNoDialog sd;
BlockingDialog sd(true,false);
sd.player = cb->getOwner(heroID);
sd.text << std::pair<ui8,ui32>(11,ot);
sd.components.push_back(Component(id,subid,val,0));
cb->showYesNoDialog(&sd,boost::bind(&CGVisitableOPH::treeSelected,this,heroID,res,resval,val,_1));
cb->showBlockingDialog(&sd,boost::bind(&CGVisitableOPH::treeSelected,this,heroID,res,resval,val,_1));
}
break;
}
case 41:
case 41://library of enlightenment
{
const CGHeroInstance *h = cb->getHero(heroID);
if(h->level < 10 - 2*h->getSecSkillLevel(4)) //not enough level
@ -1103,6 +1127,28 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
}
break;
}
case 47: //School of Magic
case 107://School of War
{
int skill = (ID==47 ? 2 : 0);
if(cb->getResource(cb->getOwner(heroID),6) < 1000) //not enough resources
{
InfoWindow iw;
iw.player = cb->getOwner(heroID);
iw.text << std::pair<ui8,ui32>(MetaString::ADVOB_TXT,ot+2);
cb->showInfoDialog(&iw);
}
else
{
BlockingDialog sd(true,true);
sd.player = cb->getOwner(heroID);
sd.text << std::pair<ui8,ui32>(11,ot);
sd.components.push_back(Component(Component::PRIM_SKILL, skill, +1, 0));
sd.components.push_back(Component(Component::PRIM_SKILL, skill+1, +1, 0));
cb->showBlockingDialog(&sd,boost::bind(&CGVisitableOPH::schoolSelected,this,heroID,_1));
}
}
break;
}
}
else
@ -1143,6 +1189,12 @@ const std::string & CGVisitableOPH::getHoverText() const
break;
case 41:
break;
case 47: //School of Magic
pom = 9;
break;
case 107://School of War
pom = 10;
break;
default:
throw std::string("Wrong CGVisitableOPH object ID!\n");
}
@ -1163,7 +1215,7 @@ const std::string & CGVisitableOPH::getHoverText() const
void CGVisitableOPH::arenaSelected( int heroID, int primSkill ) const
{
cb->setObjProperty(id,4,heroID); //add to the visitors
cb->changePrimSkill(heroID,primSkill,2);
cb->changePrimSkill(heroID,primSkill-1,2);
}
void CGVisitableOPH::setPropertyDer( ui8 what, ui32 val )
@ -1172,6 +1224,17 @@ void CGVisitableOPH::setPropertyDer( ui8 what, ui32 val )
visitors.insert(val);
}
void CGVisitableOPH::schoolSelected(int heroID, ui32 which) const
{
if(!which) //player refused to pay
return;
int base = (ID == 47 ? 2 : 0);
cb->setObjProperty(id,4,heroID); //add to the visitors
cb->giveResource(cb->getOwner(heroID),6,-1000); //take 1000 gold
cb->changePrimSkill(heroID, base + which-1, +1); //give appropriate skill
}
bool CArmedInstance::needsLastStack() const
{
return false;
@ -1302,10 +1365,10 @@ void CGResource::onHeroVisit( const CGHeroInstance * h ) const
{
if(message.size())
{
YesNoDialog ynd;
BlockingDialog ynd(true,false);
ynd.player = h->getOwner();
ynd.text << message;
cb->showYesNoDialog(&ynd,boost::bind(&CGResource::fightForRes,this,_1,h));
cb->showBlockingDialog(&ynd,boost::bind(&CGResource::fightForRes,this,_1,h));
}
else
{
@ -1337,9 +1400,9 @@ void CGResource::collectRes( int player ) const
cb->removeObject(id);
}
void CGResource::fightForRes(ui32 refusedFight, const CGHeroInstance *h) const
void CGResource::fightForRes(ui32 agreed, const CGHeroInstance *h) const
{
if(!refusedFight)
if(agreed)
cb->startBattleI(h->id,army,pos,boost::bind(&CGResource::endBattle,this,_1,h));
}
@ -1519,10 +1582,10 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
{
if(message.size())
{
YesNoDialog ynd;
BlockingDialog ynd(true,false);
ynd.player = h->getOwner();
ynd.text << message;
cb->showYesNoDialog(&ynd,boost::bind(&CGArtifact::fightForArt,this,_1,h));
cb->showBlockingDialog(&ynd,boost::bind(&CGArtifact::fightForArt,this,_1,h));
}
else
{
@ -1544,9 +1607,9 @@ void CGArtifact::pick(const CGHeroInstance * h) const
cb->removeObject(id);
}
void CGArtifact::fightForArt( ui32 refusedFight, const CGHeroInstance *h ) const
void CGArtifact::fightForArt( ui32 agreed, const CGHeroInstance *h ) const
{
if(!refusedFight)
if(agreed)
cb->startBattleI(h->id,army,pos,boost::bind(&CGArtifact::endBattle,this,_1,h));
}
@ -1632,13 +1695,13 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
}
else
{
SelectionDialog sd;
BlockingDialog sd(false,true);
sd.player = h->tempOwner;
sd.text << std::pair<ui8,ui32>(11,146);
sd.components.push_back(Component(2,6,val1,0));
sd.components.push_back(Component(5,0,val2,0));
boost::function<void(ui32)> fun = boost::bind(&CGPickable::chosen,this,_1,h->id);
cb->showSelectionDialog(&sd,fun);
cb->showBlockingDialog(&sd,fun);
return;
}
}
@ -1650,10 +1713,10 @@ void CGPickable::chosen( int which, int heroID ) const
{
switch(which)
{
case 0: //player pick gold
case 1: //player pick gold
cb->giveResource(cb->getOwner(heroID),6,val1);
break;
case 1: //player pick exp
case 2: //player pick exp
cb->changePrimSkill(heroID, 4, val2);
break;
default:
@ -1930,7 +1993,7 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
InfoWindow iw;
iw.player = h->tempOwner;
iw.text.addTxt(MetaString::ADVOB_TXT,98);
iw.text.addTxt(MetaString::ADVOB_TXT,98 + (ID==60));
cb->showInfoDialog(&iw);
}

View File

@ -352,6 +352,7 @@ public:
void onNAHeroVisit(int heroID, bool alreadyVisited) const;
void initObj();
void treeSelected(int heroID, int resType, int resVal, int expVal, ui32 result) const; //handle player's anwer to the Tree of Knowledge dialog
void schoolSelected(int heroID, ui32 which) const;
void arenaSelected(int heroID, int primSkill) const;
template <typename Handler> void serialize(Handler &h, const int version)
@ -498,7 +499,7 @@ public:
std::string message;
ui32 spell; //if it's spell scroll
void onHeroVisit(const CGHeroInstance * h) const;
void fightForArt(ui32 refusedFight, const CGHeroInstance *h) const;
void fightForArt(ui32 agreed, const CGHeroInstance *h) const;
void endBattle(BattleResult *result, const CGHeroInstance *h) const;
void pick( const CGHeroInstance * h ) const;
void initObj();
@ -519,7 +520,7 @@ public:
void onHeroVisit(const CGHeroInstance * h) const;
void collectRes(int player) const;
void initObj();
void fightForRes(ui32 refusedFight, const CGHeroInstance *h) const;
void fightForRes(ui32 agreed, const CGHeroInstance *h) const;
void endBattle(BattleResult *result, const CGHeroInstance *h) const;
template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -11,8 +11,7 @@ struct GiveBonus;
class CGObjectInstance;
class CGTownInstance;
class CGHeroInstance;
struct SelectionDialog;
struct YesNoDialog;
struct BlockingDialog;
struct InfoWindow;
struct MetaString;
struct ShowInInfobox;
@ -52,8 +51,8 @@ public:
virtual void changePrimSkill(int ID, int which, int val, bool abs=false)=0;
virtual void changeSecSkill(int ID, int which, int val, bool abs=false)=0;
virtual void showInfoDialog(InfoWindow *iw)=0;
virtual void showYesNoDialog(YesNoDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
virtual void showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback)=0; //returns question id
virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
virtual ui32 showBlockingDialog(BlockingDialog *iw) =0; //synchronous version of above
virtual void giveResource(int player, int which, int val)=0;
virtual void showCompInfo(ShowInInfobox * comp)=0;
virtual void heroVisitCastle(int obj, int heroID)=0;

View File

@ -555,35 +555,43 @@ struct HeroLevelUp : public Query//2000
}
};
struct SelectionDialog : public Query//2001
//A dialog that requires making decision by player - it may contain components to choose between or has yes/no options
//Client responds with QueryReply, where answer: 0 - cancel pressed, choice doesn't matter; 1/2/... - first/second/... component selected and OK pressed
//Until sending reply player won't be allowed to take any actions
struct BlockingDialog : public Query//2003
{
enum {ALLOW_CANCEL = 1, SELECTION = 2};
void applyCl(CClient *cl);
MetaString text;
std::vector<Component> components;
ui8 player;
ui8 flags;
SelectionDialog(){type = 2001;};
template <typename Handler> void serialize(Handler &h, const int version)
bool cancel() const
{
h & id & text & components & player;
return flags & ALLOW_CANCEL;
}
bool selection() const
{
return flags & SELECTION;
}
};
struct YesNoDialog : public Query//2002
{
void applyCl(CClient *cl);
MetaString text;
std::vector<Component> components;
ui8 player;
YesNoDialog(){type = 2002;};
BlockingDialog(bool yesno, bool Selection)
{
type = 2003;
if(yesno) flags |= ALLOW_CANCEL;
if(Selection) flags |= SELECTION;
}
BlockingDialog()
{
type = 2003;
};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & text & components & player;
h & id & text & components & player & flags;
}
};

View File

@ -67,8 +67,7 @@ void registerTypes2(Serializer &s)
s.template registerType<SetObjectProperty>();
s.template registerType<SetHoverName>();
s.template registerType<HeroLevelUp>();
s.template registerType<SelectionDialog>();
s.template registerType<YesNoDialog>();
s.template registerType<BlockingDialog>();
s.template registerType<BattleStart>();
s.template registerType<BattleNextRound>();
s.template registerType<BattleSetActiveStack>();

View File

@ -1413,7 +1413,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
loadHero(nobj, bufor, i);
break;
}
case 4: //arena
case 4: //Arena
case 51: //Mercenary Camp
case 23: //Marletto Tower
case 61: // Star Axis
@ -1421,6 +1421,8 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
case 100: //Learning Stone
case 102: //Tree of Knowledge
case 41: //Library of Enlightenment
case 47: //School of Magic
case 107: //School of War
{
nobj = new CGVisitableOPH();
break;
@ -1784,6 +1786,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
break;
}
case 58: //Redwood Observatory
case 60: //Pillar of Fire
{
nobj = new CGObservatory();
break;

View File

@ -1208,14 +1208,27 @@ void CGameHandler::showInfoDialog(InfoWindow *iw)
{
sendToAllClients(iw);
}
void CGameHandler::showYesNoDialog( YesNoDialog *iw, const CFunctionList<void(ui32)> &callback )
void CGameHandler::showBlockingDialog( BlockingDialog *iw, const CFunctionList<void(ui32)> &callback )
{
ask(iw,iw->player,callback);
}
void CGameHandler::showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback)
ui32 CGameHandler::showBlockingDialog( BlockingDialog *iw )
{
ask(iw,iw->player,callback);
//TODO
//gsm.lock();
//int query = QID++;
//states.addQuery(player,query);
//sendToAllClients(iw);
//gsm.unlock();
//ui32 ret = getQueryResult(iw->player, query);
//gsm.lock();
//states.removeQuery(player, query);
//gsm.unlock();
return 0;
}
int CGameHandler::getCurrentPlayer()
{
return gs->currentPlayer;
@ -1439,8 +1452,11 @@ void CGameHandler::save( const std::string &fname )
void CGameHandler::close()
{
tlog0 << "We have been requested to close.\n";
exit(0);
tlog0 << "We have been requested to close.\n";
//BOOST_FOREACH(CConnection *cc, conns)
// if(cc && cc->socket && cc->socket->is_open())
// cc->socket->close();
//exit(0);
}
void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val)
@ -2300,8 +2316,9 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
case 52: //misfortune
case 53: //haste
case 54: //slow
case 61: //forgetfulness
{
SPELL_CAST_TEMPLATE_1(ba.additionalInfo, h->getPrimSkillLevel(2))
SPELL_CAST_TEMPLATE_1(ba.additionalInfo, h->getPrimSkillLevel(2) + h->valOfBonuses(HeroBonus::SPELL_DURATION) )
break;
}
case 56: //frenzy
@ -2309,11 +2326,6 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
SPELL_CAST_TEMPLATE_1(ba.additionalInfo, 1)
break;
}
case 61: //forgetfulness
{
SPELL_CAST_TEMPLATE_1(ba.additionalInfo, h->getPrimSkillLevel(2))
break;
}
}
sendAndApply(&EndAction());
}
@ -2380,4 +2392,10 @@ bool CGameHandler::complain( const std::string &problem )
sendMessageToAll("Server encountered a problem: " + problem);
tlog1 << problem << std::endl;
return true;
}
ui32 CGameHandler::getQueryResult( ui8 player, int queryID )
{
//TODO: write
return 0;
}

View File

@ -93,8 +93,8 @@ public:
void changePrimSkill(int ID, int which, int val, bool abs=false);
void changeSecSkill(int ID, int which, int val, bool abs=false);
void showInfoDialog(InfoWindow *iw);
void showYesNoDialog(YesNoDialog *iw, const CFunctionList<void(ui32)> &callback);
void showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback); //returns question id
void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback);
ui32 showBlockingDialog(BlockingDialog *iw); //synchronous version of above
void giveResource(int player, int which, int val);
void showCompInfo(ShowInInfobox * comp);
void heroVisitCastle(int obj, int heroID);
@ -142,6 +142,7 @@ public:
h & QID & states;
}
ui32 getQueryResult(ui8 player, int queryID);
void sendMessageToAll(const std::string &message);
void sendMessageTo(CConnection &c, const std::string &message);
void applyAndAsk(Query * sel, ui8 player, boost::function<void(ui32)> &callback);