2008-07-25 20:28:28 +03:00
|
|
|
#include "Client.h"
|
|
|
|
#include "../lib/Connection.h"
|
|
|
|
#include "../StartInfo.h"
|
|
|
|
#include "../map.h"
|
|
|
|
#include "../CGameState.h"
|
|
|
|
#include "../CGameInfo.h"
|
|
|
|
#include "../mapHandler.h"
|
|
|
|
#include "../CCallback.h"
|
|
|
|
#include "../CPlayerInterface.h"
|
|
|
|
#include "../CConsoleHandler.h"
|
2008-07-26 16:57:32 +03:00
|
|
|
#include "../lib/NetPacks.h"
|
2008-07-27 20:07:37 +03:00
|
|
|
#include <boost/bind.hpp>
|
|
|
|
#include <boost/thread.hpp>
|
2008-08-01 14:21:15 +03:00
|
|
|
#include <boost/foreach.hpp>
|
2008-07-28 15:44:08 +03:00
|
|
|
#include "../hch/CObjectHandler.h"
|
2008-07-30 20:51:19 +03:00
|
|
|
#include "../hch/CGeneralTextHandler.h"
|
|
|
|
#include "../hch/CArtHandler.h"
|
|
|
|
#include <boost/thread/shared_mutex.hpp>
|
2008-08-04 18:56:36 +03:00
|
|
|
#include "../lib/VCMI_Lib.h"
|
2008-07-28 15:44:08 +03:00
|
|
|
CSharedCond<std::set<IPack*> > mess(new std::set<IPack*>);
|
|
|
|
|
2008-07-30 20:51:19 +03:00
|
|
|
std::string toString(MetaString &ms)
|
|
|
|
{
|
|
|
|
std::string ret;
|
|
|
|
for(int i=0;i<ms.message.size();i++)
|
|
|
|
{
|
|
|
|
if(ms.message[i]>0)
|
|
|
|
{
|
|
|
|
ret += ms.strings[ms.message[i]-1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::vector<std::string> *vec;
|
2008-07-31 00:27:15 +03:00
|
|
|
int type = ms.texts[-ms.message[i]-1].first,
|
|
|
|
ser = ms.texts[-ms.message[i]-1].second;
|
2008-07-30 20:51:19 +03:00
|
|
|
if(type == 5)
|
|
|
|
{
|
2008-07-31 00:27:15 +03:00
|
|
|
ret += CGI->arth->artifacts[ser].name;
|
2008-07-30 20:51:19 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if(type == 7)
|
|
|
|
{
|
2008-07-31 00:27:15 +03:00
|
|
|
ret += CGI->creh->creatures[ser].namePl;
|
2008-07-30 20:51:19 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if(type == 9)
|
|
|
|
{
|
2008-07-31 00:27:15 +03:00
|
|
|
ret += CGI->objh->mines[ser].first;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if(type == 10)
|
|
|
|
{
|
|
|
|
ret += CGI->objh->mines[ser].second;
|
2008-07-30 20:51:19 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
vec = &CGI->generaltexth->allTexts;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
vec = &CGI->objh->xtrainfo;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
vec = &CGI->objh->names;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
vec = &CGI->objh->restypes;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
vec = &CGI->generaltexth->arraytxt;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
vec = &CGI->objh->creGens;
|
|
|
|
break;
|
2008-07-31 13:35:22 +03:00
|
|
|
case 11:
|
|
|
|
vec = &CGI->objh->advobtxt;
|
2008-07-30 20:51:19 +03:00
|
|
|
}
|
2008-07-31 00:27:15 +03:00
|
|
|
ret += (*vec)[ser];
|
2008-07-30 20:51:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-02 13:25:58 +03:00
|
|
|
for(int i=0;i<ms.replacements.size();i++)
|
|
|
|
{
|
|
|
|
ret.replace(ret.find("%s"),2,ms.replacements[i]);
|
|
|
|
}
|
2008-07-30 20:51:19 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-07-25 20:28:28 +03:00
|
|
|
CClient::CClient(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
CClient::CClient(CConnection *con, StartInfo *si)
|
|
|
|
:serv(con)
|
2008-07-27 20:07:37 +03:00
|
|
|
{
|
2008-07-26 09:39:44 +03:00
|
|
|
timeHandler tmh;
|
2008-07-27 20:07:37 +03:00
|
|
|
CGI->state = new CGameState();
|
|
|
|
THC std::cout<<"\tGamestate: "<<tmh.getDif()<<std::endl;
|
2008-07-25 20:28:28 +03:00
|
|
|
CConnection &c(*con);
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
ui8 pom8;
|
2008-07-26 09:39:44 +03:00
|
|
|
c << ui8(2) << ui8(1); //new game; one client
|
2008-07-25 20:28:28 +03:00
|
|
|
c << *si;
|
|
|
|
c >> pom8;
|
|
|
|
if(pom8) throw "Server cannot open the map!";
|
|
|
|
c << ui8(si->playerInfos.size());
|
|
|
|
for(int i=0;i<si->playerInfos.size();i++)
|
|
|
|
c << ui8(si->playerInfos[i].color);
|
|
|
|
|
|
|
|
ui32 seed, sum;
|
|
|
|
std::string mapname;
|
|
|
|
c >> mapname >> sum >> seed;
|
|
|
|
THC std::cout<<"\tSending/Getting info to/from the server: "<<tmh.getDif()<<std::endl;
|
|
|
|
|
|
|
|
Mapa * mapa = new Mapa(mapname);
|
|
|
|
THC std::cout<<"Reading and detecting map file (together): "<<tmh.getDif()<<std::endl;
|
|
|
|
std::cout << "\tServer checksum for "<<mapname <<": "<<sum << std::endl;
|
|
|
|
std::cout << "\tOur checksum for the map: "<< mapa->checksum << std::endl;
|
|
|
|
|
|
|
|
if(mapa->checksum != sum)
|
2008-07-31 16:21:42 +03:00
|
|
|
{
|
2008-08-04 12:05:52 +03:00
|
|
|
#ifndef __GNUC__
|
2008-07-31 16:21:42 +03:00
|
|
|
throw std::exception("Wrong checksum");
|
2008-08-04 12:05:52 +03:00
|
|
|
#else
|
|
|
|
throw std::exception();
|
|
|
|
#endif
|
2008-07-25 20:28:28 +03:00
|
|
|
exit(-1);
|
2008-07-31 16:21:42 +03:00
|
|
|
}
|
2008-07-25 20:28:28 +03:00
|
|
|
std::cout << "\tUsing random seed: "<<seed << std::endl;
|
|
|
|
|
|
|
|
gs = CGI->state;
|
|
|
|
gs->scenarioOps = si;
|
|
|
|
gs->init(si,mapa,seed);
|
|
|
|
|
|
|
|
CGI->mh = new CMapHandler();
|
|
|
|
THC std::cout<<"Initializing GameState (together): "<<tmh.getDif()<<std::endl;
|
|
|
|
CGI->mh->map = mapa;
|
|
|
|
THC std::cout<<"Creating mapHandler: "<<tmh.getDif()<<std::endl;
|
|
|
|
CGI->mh->init();
|
|
|
|
THC std::cout<<"Initializing mapHandler (together): "<<tmh.getDif()<<std::endl;
|
|
|
|
|
|
|
|
for (int i=0; i<CGI->state->scenarioOps->playerInfos.size();i++) //initializing interfaces
|
|
|
|
{
|
2008-07-28 15:44:08 +03:00
|
|
|
ui8 color = gs->scenarioOps->playerInfos[i].color;
|
|
|
|
CCallback *cb = new CCallback(gs,color,this);
|
|
|
|
if(!gs->scenarioOps->playerInfos[i].human)
|
|
|
|
playerint[color] = static_cast<CGameInterface*>(CAIHandler::getNewAI(cb,"EmptyAI.dll"));
|
2008-07-25 20:28:28 +03:00
|
|
|
else
|
|
|
|
{
|
2008-07-28 15:44:08 +03:00
|
|
|
gs->currentPlayer = color;
|
|
|
|
playerint[color] = new CPlayerInterface(color,i);
|
|
|
|
playerint[color]->init(cb);
|
2008-07-25 20:28:28 +03:00
|
|
|
}
|
|
|
|
}
|
2008-07-28 15:44:08 +03:00
|
|
|
CGI->consoleh->cb = new CCallback(gs,-1,this);
|
2008-07-25 20:28:28 +03:00
|
|
|
}
|
|
|
|
CClient::~CClient(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void CClient::process(int what)
|
|
|
|
{
|
|
|
|
switch (what)
|
|
|
|
{
|
|
|
|
case 100: //one of our interaces has turn
|
2008-07-26 16:57:32 +03:00
|
|
|
{
|
|
|
|
ui8 player;
|
|
|
|
*serv >> player;//who?
|
|
|
|
std::cout << "It's turn of "<<(unsigned)player<<" player."<<std::endl;
|
2008-07-28 15:44:08 +03:00
|
|
|
boost::thread(boost::bind(&CGameInterface::yourTurn,playerint[player]));
|
2008-07-26 16:57:32 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 101:
|
|
|
|
{
|
|
|
|
NewTurn n;
|
|
|
|
*serv >> n;
|
|
|
|
std::cout << "New day: "<<(unsigned)n.day<<". Applying changes... ";
|
|
|
|
gs->apply(&n);
|
|
|
|
std::cout << "done!"<<std::endl;
|
|
|
|
break;
|
|
|
|
}
|
2008-07-31 00:27:15 +03:00
|
|
|
case 102: //set resource amount
|
|
|
|
{
|
|
|
|
SetResource sr;
|
|
|
|
*serv >> sr;
|
|
|
|
std::cout << "Set amount of "<<CGI->objh->restypes[sr.resid]
|
|
|
|
<< " of player "<<(unsigned)sr.player <<" to "<<sr.val<<std::endl;
|
|
|
|
gs->apply(&sr);
|
|
|
|
playerint[sr.player]->receivedResource(sr.resid,sr.val);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 103: //show info dialog
|
|
|
|
{
|
|
|
|
InfoWindow iw;
|
|
|
|
*serv >> iw;
|
2008-07-31 13:35:22 +03:00
|
|
|
std::vector<Component*> comps;
|
|
|
|
for(int i=0;i<iw.components.size();i++)
|
|
|
|
comps.push_back(&iw.components[i]);
|
|
|
|
playerint[iw.player]->showInfoDialog(toString(iw.text),comps);
|
|
|
|
break;
|
2008-07-31 00:27:15 +03:00
|
|
|
}
|
2008-08-01 14:21:15 +03:00
|
|
|
case 104:
|
|
|
|
{
|
|
|
|
SetResources sr;
|
|
|
|
*serv >> sr;
|
|
|
|
std::cout << "Set amount of resources of player "<<(unsigned)sr.player<<std::endl;
|
|
|
|
gs->apply(&sr);
|
|
|
|
playerint[sr.player]->receivedResource(-1,-1);
|
|
|
|
break;
|
|
|
|
}
|
2008-08-04 18:56:36 +03:00
|
|
|
case 105:
|
|
|
|
{
|
|
|
|
SetPrimSkill sps;
|
|
|
|
*serv >> sps;
|
|
|
|
std::cout << "Changing hero primary skill"<<std::endl;
|
|
|
|
gs->apply(&sps);
|
|
|
|
playerint[gs->getHero(sps.id)->tempOwner]->heroPrimarySkillChanged(gs->getHero(sps.id),sps.which,sps.val);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 107:
|
|
|
|
{
|
|
|
|
ShowInInfobox sii;
|
|
|
|
*serv >> sii;
|
|
|
|
SComponent sc(sii.c);
|
|
|
|
sc.description = toString(sii.text);
|
|
|
|
if(playerint[sii.player]->human)
|
|
|
|
static_cast<CPlayerInterface*>(playerint[sii.player])->showComp(sc);
|
|
|
|
break;
|
|
|
|
}
|
2008-08-02 00:41:38 +03:00
|
|
|
case 500:
|
|
|
|
{
|
|
|
|
RemoveHero rh;
|
|
|
|
*serv >> rh;
|
|
|
|
CGHeroInstance *h = static_cast<CGHeroInstance*>(gs->map->objects[rh.id]);
|
|
|
|
std::cout << "Removing hero with id = "<<(unsigned)rh.id<<std::endl;
|
|
|
|
CGI->mh->removeObject(h);
|
|
|
|
gs->apply(&rh);
|
|
|
|
playerint[h->tempOwner]->heroKilled(h);
|
|
|
|
break;
|
|
|
|
}
|
2008-07-28 15:44:08 +03:00
|
|
|
case 501: //hero movement response - we have to notify interfaces and callback
|
|
|
|
{
|
2008-07-30 20:51:19 +03:00
|
|
|
TryMoveHero *th = new TryMoveHero; //will be deleted by callback after processing
|
2008-07-28 15:44:08 +03:00
|
|
|
*serv >> *th;
|
|
|
|
std::cout << "HeroMove: id="<<th->id<<"\tResult: "<<(unsigned)th->result<<"\tPosition "<<th->end<<std::endl;
|
|
|
|
|
|
|
|
gs->apply(th);
|
|
|
|
int player = gs->map->objects[th->id]->getOwner();
|
|
|
|
|
|
|
|
if(playerint[player])
|
|
|
|
{
|
|
|
|
for(std::set<int3>::iterator i=th->fowRevealed.begin(); i != th->fowRevealed.end(); i++)
|
|
|
|
playerint[player]->tileRevealed(*i);
|
|
|
|
//boost::function<void(int3)> tr = boost::bind(&CGameInterface::tileRevealed,playerint[player]);
|
|
|
|
//std::for_each(th->fowRevealed.begin(),th->fowRevealed.end(),tr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//notify interfacesabout move
|
|
|
|
int nn=0; //number of interfece of currently browsed player
|
|
|
|
for(std::map<ui8, CGameInterface*>::iterator i=playerint.begin();i!=playerint.end();i++)
|
|
|
|
{
|
|
|
|
if(gs->players[i->first].fogOfWarMap[th->start.x-1][th->start.y][th->start.z] || gs->players[i->first].fogOfWarMap[th->end.x-1][th->end.y][th->end.z])
|
|
|
|
{
|
|
|
|
HeroMoveDetails hmd(th->start,th->end,static_cast<CGHeroInstance*>(gs->map->objects[th->id]));
|
|
|
|
hmd.successful = th->result;
|
|
|
|
i->second->heroMoved(hmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//add info for callback
|
|
|
|
mess.mx->lock();
|
|
|
|
mess.res->insert(th);
|
|
|
|
mess.mx->unlock();
|
|
|
|
mess.cv->notify_all();
|
|
|
|
break;
|
|
|
|
}
|
2008-07-31 16:21:42 +03:00
|
|
|
case 502:
|
|
|
|
{
|
|
|
|
SetGarrisons sg;
|
|
|
|
*serv >> sg;
|
|
|
|
gs->apply(&sg);
|
|
|
|
for(std::map<ui32,CCreatureSet>::iterator i = sg.garrs.begin(); i!=sg.garrs.end(); i++)
|
|
|
|
playerint[gs->map->objects[i->first]->tempOwner]->garrisonChanged(gs->map->objects[i->first]);
|
|
|
|
break;
|
|
|
|
}
|
2008-08-01 14:21:15 +03:00
|
|
|
case 503:
|
|
|
|
{
|
|
|
|
SetStrInfo ssi;
|
|
|
|
*serv >> ssi;
|
|
|
|
gs->apply(&ssi);
|
|
|
|
//TODO: notify interfaces
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 504:
|
|
|
|
{
|
|
|
|
NewStructures ns;
|
|
|
|
*serv >> ns;
|
|
|
|
gs->apply(&ns);
|
|
|
|
BOOST_FOREACH(si32 bid, ns.bid)
|
|
|
|
playerint[gs->map->objects[ns.tid]->tempOwner]->buildChanged(static_cast<CGTownInstance*>(gs->map->objects[ns.tid]),bid,1);
|
|
|
|
break;
|
|
|
|
}
|
2008-07-30 20:51:19 +03:00
|
|
|
case 1001:
|
|
|
|
{
|
|
|
|
SetObjectProperty sop;
|
|
|
|
*serv >> sop;
|
|
|
|
std::cout << "Setting " << (unsigned)sop.what << " property of " << sop.id <<" object to "<<sop.val<<std::endl;
|
|
|
|
gs->apply(&sop);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1002:
|
|
|
|
{
|
|
|
|
SetHoverName shn;
|
|
|
|
*serv >> shn;
|
|
|
|
std::cout << "Setting a name of " << shn.id <<" object to "<< toString(shn.name) <<std::endl;
|
|
|
|
gs->mx->lock();
|
|
|
|
gs->map->objects[shn.id]->hoverName = toString(shn.name);
|
|
|
|
gs->mx->unlock();
|
2008-08-04 18:56:36 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3000:
|
|
|
|
{
|
|
|
|
BattleStart bs;
|
|
|
|
*serv >> bs; //uses new to allocate memory for battleInfo - must be deleted when battle is over
|
|
|
|
std::cout << "Starting battle!" <<std::endl;
|
|
|
|
gs->apply(&bs);
|
|
|
|
|
|
|
|
if(playerint.find(gs->curB->side1) != playerint.end())
|
|
|
|
playerint[gs->curB->side1]->battleStart(&gs->curB->army1, &gs->curB->army2, gs->curB->tile, gs->getHero(gs->curB->hero1), gs->getHero(gs->curB->hero2), 0);
|
|
|
|
if(playerint.find(gs->curB->side2) != playerint.end())
|
|
|
|
playerint[gs->curB->side2]->battleStart(&gs->curB->army1, &gs->curB->army2, gs->curB->tile, gs->getHero(gs->curB->hero1), gs->getHero(gs->curB->hero2), 1);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3001:
|
|
|
|
{
|
|
|
|
BattleNextRound bnr;
|
|
|
|
*serv >> bnr;
|
|
|
|
std::cout << "Round nr " << bnr.round <<std::endl;
|
|
|
|
gs->apply(&bnr);
|
|
|
|
|
|
|
|
//tell players about next round
|
|
|
|
if(playerint.find(gs->curB->side1) != playerint.end())
|
|
|
|
playerint[gs->curB->side1]->battleNewRound(bnr.round);
|
|
|
|
if(playerint.find(gs->curB->side2) != playerint.end())
|
|
|
|
playerint[gs->curB->side2]->battleNewRound(bnr.round);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3002:
|
|
|
|
{
|
|
|
|
BattleSetActiveStack sas;
|
|
|
|
*serv >> sas;
|
|
|
|
std::cout << "Active stack: " << sas.stack <<std::endl;
|
|
|
|
gs->apply(&sas);
|
2008-08-05 02:04:15 +03:00
|
|
|
boost::thread(boost::bind(&CClient::waitForMoveAndSend,this,gs->curB->getStack(sas.stack)->owner));
|
2008-08-04 18:56:36 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3003:
|
|
|
|
{
|
|
|
|
BattleResult br;
|
|
|
|
*serv >> br;
|
|
|
|
std::cout << "Battle ends. Winner: " << (unsigned)br.winner<< ". Type of end: "<< (unsigned)br.result <<std::endl;
|
|
|
|
|
|
|
|
if(playerint.find(gs->curB->side1) != playerint.end())
|
|
|
|
playerint[gs->curB->side1]->battleEnd(&br);
|
|
|
|
if(playerint.find(gs->curB->side2) != playerint.end())
|
|
|
|
playerint[gs->curB->side2]->battleEnd(&br);
|
|
|
|
|
|
|
|
gs->apply(&br);
|
2008-08-05 02:04:15 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3004:
|
|
|
|
{
|
|
|
|
BattleStackMoved br;
|
|
|
|
*serv >> br;
|
|
|
|
std::cout << "Stack "<<br.stack <<" moves to the tile "<<br.tile<<std::endl;
|
|
|
|
if(playerint.find(gs->curB->side1) != playerint.end())
|
|
|
|
playerint[gs->curB->side1]->battleStackMoved(br.stack,br.tile,br.flags&1,br.flags&2);
|
|
|
|
if(playerint.find(gs->curB->side2) != playerint.end())
|
|
|
|
playerint[gs->curB->side2]->battleStackMoved(br.stack,br.tile,br.flags&1,br.flags&2);
|
|
|
|
gs->apply(&br);
|
2008-07-30 20:51:19 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 9999:
|
|
|
|
break;
|
2008-07-25 20:28:28 +03:00
|
|
|
default:
|
2008-08-04 12:05:52 +03:00
|
|
|
#ifndef __GNUC__
|
2008-07-25 20:28:28 +03:00
|
|
|
throw std::exception("Not supported server message!");
|
2008-08-04 12:05:52 +03:00
|
|
|
#else
|
|
|
|
throw std::exception();
|
|
|
|
#endif
|
2008-07-25 20:28:28 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-08-04 18:56:36 +03:00
|
|
|
void CClient::waitForMoveAndSend(int color)
|
|
|
|
{
|
|
|
|
BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
|
|
|
|
*serv << ui16(3002) << ba;
|
|
|
|
}
|
2008-07-25 20:28:28 +03:00
|
|
|
void CClient::run()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ui16 typ;
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
*serv >> typ;
|
|
|
|
process(typ);
|
|
|
|
}
|
|
|
|
} HANDLE_EXCEPTION
|
2008-08-04 12:05:52 +03:00
|
|
|
}
|
|
|
|
|