1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-05-13 22:06:58 +02:00

* counterattacks

* spells learning
* no tooltips for objects under FoW
* working resource silo
* new system for simple unit abilities/states
* neutral monster army disappears when defeated
* synchronization between client and server processes
* fixed battle ending
This commit is contained in:
Michał W. Urbańczyk 2008-09-12 08:51:46 +00:00
parent 3b16d67b2e
commit e71b40ccc5
26 changed files with 309 additions and 83 deletions

View File

@ -320,13 +320,13 @@ void CBattleInterface::show(SDL_Surface * to)
//double loop because dead stacks should be printed first //double loop because dead stacks should be printed first
for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j) for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
{ {
if(j->second.alive) if(j->second.alive())
stackAliveByHex[j->second.position].push_back(j->second.ID); stackAliveByHex[j->second.position].push_back(j->second.ID);
} }
std::vector<int> stackDeadByHex[187]; std::vector<int> stackDeadByHex[187];
for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j) for(std::map<int, CStack>::iterator j=stacks.begin(); j!=stacks.end(); ++j)
{ {
if(!j->second.alive) if(!j->second.alive())
stackDeadByHex[j->second.position].push_back(j->second.ID); stackDeadByHex[j->second.position].push_back(j->second.ID);
} }
@ -336,7 +336,7 @@ void CBattleInterface::show(SDL_Surface * to)
{ {
for(int v=0; v<stackDeadByHex[b].size(); ++v) for(int v=0; v<stackDeadByHex[b].size(); ++v)
{ {
creAnims[stackDeadByHex[b][v]]->nextFrame(to, creAnims[stackDeadByHex[b][v]]->pos.x, creAnims[stackDeadByHex[b][v]]->pos.y, creDir[stackDeadByHex[b][v]], (animCount%4==0 || creAnims[stackDeadByHex[b][v]]->getType()!=2) && stacks[stackDeadByHex[b][v]].alive, stackDeadByHex[b][v]==activeStack); //increment always when moving, never if stack died creAnims[stackDeadByHex[b][v]]->nextFrame(to, creAnims[stackDeadByHex[b][v]]->pos.x, creAnims[stackDeadByHex[b][v]]->pos.y, creDir[stackDeadByHex[b][v]], (animCount%4==0 || creAnims[stackDeadByHex[b][v]]->getType()!=2) && stacks[stackDeadByHex[b][v]].alive(), stackDeadByHex[b][v]==activeStack); //increment always when moving, never if stack died
//printing amount //printing amount
if(stacks[stackDeadByHex[b][v]].amount > 0) //don't print if stack is not alive if(stacks[stackDeadByHex[b][v]].amount > 0) //don't print if stack is not alive
{ {
@ -353,7 +353,7 @@ void CBattleInterface::show(SDL_Surface * to)
{ {
for(int v=0; v<stackAliveByHex[b].size(); ++v) for(int v=0; v<stackAliveByHex[b].size(); ++v)
{ {
creAnims[stackAliveByHex[b][v]]->nextFrame(to, creAnims[stackAliveByHex[b][v]]->pos.x, creAnims[stackAliveByHex[b][v]]->pos.y, creDir[stackAliveByHex[b][v]], (animCount%4==0) && stacks[stackAliveByHex[b][v]].alive, stackAliveByHex[b][v]==activeStack); //increment always when moving, never if stack died creAnims[stackAliveByHex[b][v]]->nextFrame(to, creAnims[stackAliveByHex[b][v]]->pos.x, creAnims[stackAliveByHex[b][v]]->pos.y, creDir[stackAliveByHex[b][v]], (animCount%4==0) && stacks[stackAliveByHex[b][v]].alive(), stackAliveByHex[b][v]==activeStack); //increment always when moving, never if stack died
//printing amount //printing amount
if(stacks[stackAliveByHex[b][v]].amount > 0) //don't print if stack is not alive if(stacks[stackAliveByHex[b][v]].amount > 0) //don't print if stack is not alive
{ {
@ -847,7 +847,7 @@ void CBattleInterface::hexLclicked(int whichOne)
return; //we are not permit to do anything return; //we are not permit to do anything
CStack* dest = LOCPLINT->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one CStack* dest = LOCPLINT->cb->battleGetStackByPos(whichOne); //creature at destination tile; -1 if there is no one
if(!dest || !dest->alive) //no creature at that tile if(!dest || !dest->alive()) //no creature at that tile
{ {
if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range
giveCommand(2,whichOne,activeStack); giveCommand(2,whichOne,activeStack);
@ -1321,7 +1321,7 @@ void CBattleHex::mouseMoved(SDL_MouseMotionEvent &sEvent)
{ {
if(myInterface->console->alterTxt.size() == 0 && LOCPLINT->cb->battleGetStack(myNumber) != -1 && if(myInterface->console->alterTxt.size() == 0 && LOCPLINT->cb->battleGetStack(myNumber) != -1 &&
LOCPLINT->cb->battleGetStackByPos(myNumber)->owner != LOCPLINT->playerID && LOCPLINT->cb->battleGetStackByPos(myNumber)->owner != LOCPLINT->playerID &&
LOCPLINT->cb->battleGetStackByPos(myNumber)->alive) LOCPLINT->cb->battleGetStackByPos(myNumber)->alive())
{ {
char tabh[160]; char tabh[160];
CStack attackedStack = *LOCPLINT->cb->battleGetStackByPos(myNumber); CStack attackedStack = *LOCPLINT->cb->battleGetStackByPos(myNumber);
@ -1352,7 +1352,7 @@ void CBattleHex::clickRight(boost::logic::tribool down)
if(hovered && strictHovered && stID!=-1) if(hovered && strictHovered && stID!=-1)
{ {
CStack myst = *LOCPLINT->cb->battleGetStackByID(stID); //stack info CStack myst = *LOCPLINT->cb->battleGetStackByID(stID); //stack info
if(!myst.alive) return; if(!myst.alive()) return;
StackState *pom = NULL; StackState *pom = NULL;
if(down) if(down)
{ {

View File

@ -234,6 +234,8 @@ std::vector < std::string > CCallback::getObjDescriptions(int3 pos)
{ {
boost::shared_lock<boost::shared_mutex> lock(*gs->mx); boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
std::vector<std::string> ret; std::vector<std::string> ret;
if(!isVisible(pos,player))
return ret;
BOOST_FOREACH(const CGObjectInstance * obj, gs->map->terrain[pos.x][pos.y][pos.z].blockingObjects) BOOST_FOREACH(const CGObjectInstance * obj, gs->map->terrain[pos.x][pos.y][pos.z].blockingObjects)
ret.push_back(obj->hoverName); ret.push_back(obj->hoverName);
return ret; return ret;
@ -521,7 +523,7 @@ bool CCallback::battleCanShoot(int ID, int dest) //TODO: finish
if(battleGetStackByID(ID)->creature->isShooting() if(battleGetStackByID(ID)->creature->isShooting()
&& battleGetStack(dest) != -1 && battleGetStack(dest) != -1
&& battleGetStackByPos(dest)->owner != battleGetStackByID(ID)->owner && battleGetStackByPos(dest)->owner != battleGetStackByID(ID)->owner
&& battleGetStackByPos(dest)->alive) && battleGetStackByPos(dest)->alive())
return true; return true;
return false; return false;
} }

View File

@ -522,6 +522,11 @@ void CCastleInterface::buildingClicked(int building)
cmw->activate(); cmw->activate();
break; break;
} }
case 15:
{
LOCPLINT->showInfoDialog(CGI->buildh->buildings[town->subID][15]->description,std::vector<SComponent*>());
break;
}
case 16: case 16:
{ {
const CGHeroInstance *hero = town->visitingHero; const CGHeroInstance *hero = town->visitingHero;
@ -1432,8 +1437,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner)
blitAt(view,332,76,bg); blitAt(view,332,76,bg);
for(int i=0; i<owner->town->town->mageLevel; i++) for(int i=0; i<owner->town->town->mageLevel; i++)
{ {
int sp = 5 - i; //how many spells are available at this level int sp = owner->town->spellsAtLevel(i+1,false);
if(owner->town->subID==2 && vstd::contains(owner->town->builtBuildings,22)) sp++; //magic library in tower
for(int j=0; j<sp; j++) for(int j=0; j<sp; j++)
{ {
if(i < owner->town->mageGuildLevel()) if(i < owner->town->mageGuildLevel())

View File

@ -28,7 +28,6 @@ public:
void clickRight (tribool down); void clickRight (tribool down);
void mouseMoved (SDL_MouseMotionEvent & sEvent); void mouseMoved (SDL_MouseMotionEvent & sEvent);
}; };
class CHeroGSlot : public ClickableL, public ClickableR, public Hoverable class CHeroGSlot : public ClickableL, public ClickableR, public Hoverable
{ {
public: public:

View File

@ -112,7 +112,7 @@ CStack * BattleInfo::getStackT(int tileID)
|| (stacks[g]->creature->isDoubleWide() && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID) || (stacks[g]->creature->isDoubleWide() && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID)
|| (stacks[g]->creature->isDoubleWide() && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID)) || (stacks[g]->creature->isDoubleWide() && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID))
{ {
if(stacks[g]->alive) if(stacks[g]->alive())
{ {
return stacks[g]; return stacks[g];
} }
@ -125,7 +125,7 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, int stackToOmmit)
memset(accessibility,1,187); //initialize array with trues memset(accessibility,1,187); //initialize array with trues
for(int g=0; g<stacks.size(); ++g) for(int g=0; g<stacks.size(); ++g)
{ {
if(!stacks[g]->alive || stacks[g]->ID==stackToOmmit) //we don't want to lock position of this stack if(!stacks[g]->alive() || stacks[g]->ID==stackToOmmit) //we don't want to lock position of this stack
continue; continue;
accessibility[stacks[g]->position] = false; accessibility[stacks[g]->position] = false;
@ -254,8 +254,9 @@ std::vector<int> BattleInfo::getPath(int start, int dest, bool*accessibility)
} }
CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S) CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S)
:creature(C),amount(A), baseAmount(A), owner(O), alive(true), position(-1), ID(I), attackerOwned(AO), firstHPleft(C->hitPoints), slot(S) :creature(C),amount(A), baseAmount(A), owner(O), position(-1), ID(I), attackerOwned(AO), firstHPleft(C->hitPoints), slot(S), counterAttacks(0)
{ {
state.insert(ALIVE);
} }
void CGameState::applyNL(IPack * pack) void CGameState::applyNL(IPack * pack)
{ {
@ -372,6 +373,18 @@ void CGameState::applyNL(IPack * pack)
} }
break; break;
} }
case 109:
{
ChangeSpells *rh = static_cast<ChangeSpells*>(pack);
CGHeroInstance *hero = getHero(rh->hid);
if(rh->learn)
BOOST_FOREACH(ui32 sid, rh->spells)
hero->spells.insert(sid);
else
BOOST_FOREACH(ui32 sid, rh->spells)
hero->spells.erase(sid);
break;
}
case 500: case 500:
{ {
RemoveObject *rh = static_cast<RemoveObject*>(pack); RemoveObject *rh = static_cast<RemoveObject*>(pack);
@ -519,6 +532,8 @@ void CGameState::applyNL(IPack * pack)
{ {
BattleNextRound *ns = static_cast<BattleNextRound*>(pack); BattleNextRound *ns = static_cast<BattleNextRound*>(pack);
curB->round = ns->round; curB->round = ns->round;
for(int i=0; i<curB->stacks.size();i++)
curB->stacks[i]->counterAttacks = 0;
break; break;
} }
case 3002: case 3002:
@ -551,12 +566,15 @@ void CGameState::applyNL(IPack * pack)
CStack * at = curB->getStack(br->stackAttacked); CStack * at = curB->getStack(br->stackAttacked);
at->amount = br->newAmount; at->amount = br->newAmount;
at->firstHPleft = br->newHP; at->firstHPleft = br->newHP;
at->alive = !br->killed(); if(br->killed())
at->state -= ALIVE;
break; break;
} }
case 3006: case 3006:
{ {
BattleAttack *br = static_cast<BattleAttack*>(pack); BattleAttack *br = static_cast<BattleAttack*>(pack);
if(br->counter())
curB->getStack(br->stackAttacking)->counterAttacks++;
applyNL(&br->bsa); applyNL(&br->bsa);
break; break;
} }
@ -1325,7 +1343,7 @@ void BattleInfo::calculateCasualties( std::set<std::pair<ui32,si32> > *casualtie
{ {
for(int i=0; i<stacks.size();i++)//setting casualties for(int i=0; i<stacks.size();i++)//setting casualties
{ {
if(!stacks[i]->alive) if(!stacks[i]->alive())
{ {
casualties[!stacks[i]->attackerOwned].insert(std::pair<ui32,si32>(stacks[i]->creature->idNumber,stacks[i]->baseAmount)); casualties[!stacks[i]->attackerOwned].insert(std::pair<ui32,si32>(stacks[i]->creature->idNumber,stacks[i]->baseAmount));
} }
@ -1334,24 +1352,4 @@ void BattleInfo::calculateCasualties( std::set<std::pair<ui32,si32> > *casualtie
casualties[!stacks[i]->attackerOwned].insert(std::pair<ui32,si32>(stacks[i]->creature->idNumber,stacks[i]->baseAmount - stacks[i]->amount)); casualties[!stacks[i]->attackerOwned].insert(std::pair<ui32,si32>(stacks[i]->creature->idNumber,stacks[i]->baseAmount - stacks[i]->amount));
} }
} }
//if(br->killedAmount>0)
//{
// bool found = false;
// for(std::set<std::pair<ui32,si32> >::iterator it = curB->cas[1 - at->attackerOwned].begin(); it!=curB->cas[1 - at->attackerOwned].end(); ++it)
// {
// if(it->first == at->creature->idNumber)
// {
// found = true;
// std::pair<ui32,si32> mod = *it;
// mod.second += br->killedAmount;
// curB->cas[1 - at->attackerOwned].insert(it, mod);
// curB->cas[1 - at->attackerOwned].erase(it);
// }
// }
// if(!found)
// {
// curB->cas[1 - at->attackerOwned].insert(std::make_pair(at->creature->idNumber, br->killedAmount));
// }
//}
} }

View File

@ -78,19 +78,22 @@ struct DLL_EXPORT BattleInfo
}; };
class DLL_EXPORT CStack class DLL_EXPORT CStack
{ {
public: public:
ui32 ID; //unique ID of stack ui32 ID; //unique ID of stack
CCreature * creature; CCreature * creature;
ui32 amount, baseAmount; ui32 amount, baseAmount;
ui32 firstHPleft; //HP of first creature in stack ui32 firstHPleft; //HP of first creature in stack
ui8 owner, slot; //owner - player colour (255 for neutrals), slot - position in garrison (255 for neutrals/called creatures) ui8 owner, slot; //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle) ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
ui16 position; //position on battlefield ui16 position; //position on battlefield
ui8 alive; //true if it is alive ui8 counterAttacks; //how many counter attacks has this stack perfomed in current round
std::set<EAbilities> abilities;
std::set<ECombatInfo> state;
CStack(CCreature * C, int A, int O, int I, bool AO, int S); CStack(CCreature * C, int A, int O, int I, bool AO, int S);
CStack() : creature(NULL),amount(-1),owner(255), alive(true), position(-1), ID(-1), attackerOwned(true), firstHPleft(-1), slot(255), baseAmount(-1){}; CStack() : creature(NULL),amount(-1),owner(255), position(-1), ID(-1), attackerOwned(true), firstHPleft(-1), slot(255), baseAmount(-1), counterAttacks(0){};
template <typename Handler> void save(Handler &h, const int version) template <typename Handler> void save(Handler &h, const int version)
{ {
@ -101,15 +104,20 @@ public:
ui32 id; ui32 id;
h & id; h & id;
creature = &VLC->creh->creatures[id]; creature = &VLC->creh->creatures[id];
abilities = creature->abilities;
} }
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & ID & amount & baseAmount & firstHPleft & owner & attackerOwned & position & alive; h & ID & amount & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks;
if(h.saving) if(h.saving)
save(h,version); save(h,version);
else else
load(h,version); load(h,version);
} }
bool alive()
{
return vstd::contains(state,ALIVE);
}
}; };
struct UpgradeInfo struct UpgradeInfo

View File

@ -720,7 +720,7 @@ std::vector<int> CPickable::yourObjects() //returns IDs of objects which are han
void CTownScript::onHeroVisit(int objid, int heroID) void CTownScript::onHeroVisit(int objid, int heroID)
{ {
DEFOS;
if(cb->getOwner(objid)!=cb->getOwner(heroID)) if(cb->getOwner(objid)!=cb->getOwner(heroID))
{ {
return; return;
@ -774,7 +774,8 @@ void CHeroScript::onHeroVisit(int objid, int heroID)
&vis->army, &vis->army,
my->pos, my->pos,
my, my,
vis); vis,
0);
} }
} }
std::vector<int> CHeroScript::yourObjects() //returns IDs of objects which are handled by script std::vector<int> CHeroScript::yourObjects() //returns IDs of objects which are handled by script
@ -834,7 +835,7 @@ void CMonsterS::onHeroVisit(int objid, int heroID)
CCreatureSet set; CCreatureSet set;
//TODO: zrobic secik w sposob wyrafinowany //TODO: zrobic secik w sposob wyrafinowany
set.slots[0] = std::pair<ui32,si32>(os->subID,amounts[objid]); set.slots[0] = std::pair<ui32,si32>(os->subID,amounts[objid]);
cb->startBattle(heroID,set,os->pos); cb->startBattle(heroID,set,os->pos,boost::bind(&CMonsterS::endBattleWith,this,os,_1));
} }
std::vector<int> CMonsterS::yourObjects() //returns IDs of objects which are handled by script std::vector<int> CMonsterS::yourObjects() //returns IDs of objects which are handled by script
{ {
@ -843,6 +844,17 @@ std::vector<int> CMonsterS::yourObjects() //returns IDs of objects which are han
return ret; return ret;
} }
void CMonsterS::endBattleWith(const CGObjectInstance *monster, BattleResult *result )
{
if(result->winner==0)
{
cb->removeObject(monster->id);
}
else
{
//TODO: remove casualties
}
}
void CCreatureGen::newObject(int objid) void CCreatureGen::newObject(int objid)
{ {

2
CLua.h
View File

@ -25,6 +25,7 @@ class CSelectableComponent;
class CGameState; class CGameState;
struct Mapa; struct Mapa;
struct lua_State; struct lua_State;
struct BattleResult;
enum ESLan{UNDEF=-1,CPP,ERM,LUA}; enum ESLan{UNDEF=-1,CPP,ERM,LUA};
class CObjectScript class CObjectScript
{ {
@ -175,6 +176,7 @@ public:
void newObject(int objid); void newObject(int objid);
void onHeroVisit(int objid, int heroID); void onHeroVisit(int objid, int heroID);
std::vector<int> yourObjects(); //returns IDs of objects which are handled by script std::vector<int> yourObjects(); //returns IDs of objects which are handled by script
void endBattleWith(const CGObjectInstance *monster, BattleResult *result);
}; };
class CCreatureGen : public CCPPObjectScript class CCreatureGen : public CCPPObjectScript

30
CMT.cpp
View File

@ -6,6 +6,8 @@
#include <vector> #include <vector>
#include <queue> #include <queue>
#include <cmath> #include <cmath>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "SDL_ttf.h" #include "SDL_ttf.h"
#include "SDL_mixer.h" #include "SDL_mixer.h"
@ -37,6 +39,7 @@
#include "client/Graphics.h" #include "client/Graphics.h"
#include "client/Client.h" #include "client/Client.h"
#include "lib/Connection.h" #include "lib/Connection.h"
#include "lib/Interprocess.h"
#include "lib/VCMI_Lib.h" #include "lib/VCMI_Lib.h"
std::string NAME = NAME_VER + std::string(" (client)"); std::string NAME = NAME_VER + std::string(" (client)");
DLL_EXPORT void initDLL(CLodHandler *b); DLL_EXPORT void initDLL(CLodHandler *b);
@ -45,6 +48,7 @@ extern SDL_Surface * CSDL_Ext::std32bppSurface;
std::queue<SDL_Event> events; std::queue<SDL_Event> events;
boost::mutex eventsM; boost::mutex eventsM;
TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16; TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
namespace intpr = boost::interprocess;
#ifndef __GNUC__ #ifndef __GNUC__
int _tmain(int argc, _TCHAR* argv[]) int _tmain(int argc, _TCHAR* argv[])
#else #else
@ -149,16 +153,23 @@ int main(int argc, char** argv)
THC std::cout<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl; THC std::cout<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
THC std::cout<<"Initialization of VCMI (togeter): "<<total.getDif()<<std::endl; THC std::cout<<"Initialization of VCMI (togeter): "<<total.getDif()<<std::endl;
cpg->mush = mush; cpg->mush = mush;
StartInfo *options = new StartInfo(cpg->runLoop()); StartInfo *options = new StartInfo(cpg->runLoop());
/////////////////////////////////////////////////////////////////////////////////////// tmh.getDif();
////////////////////////SERVER STARTING/////////////////////////////////////////////////
char portc[10]; SDL_itoa(port,portc,10); char portc[10]; SDL_itoa(port,portc,10);
intpr::shared_memory_object smo(intpr::open_or_create,"vcmi_memory",intpr::read_write);
smo.truncate(sizeof(ServerReady));
intpr::mapped_region mr(smo,intpr::read_write);
ServerReady *sr = new(mr.get_address())ServerReady();
std::string comm = std::string(SERVER_NAME) + " " + portc + " > server_log.txt"; std::string comm = std::string(SERVER_NAME) + " " + portc + " > server_log.txt";
boost::thread servthr(boost::bind(system,comm.c_str())); //runs server executable; boost::thread servthr(boost::bind(system,comm.c_str())); //runs server executable; //TODO: will it work on non-windows platforms?
//TODO: will it work on non-windows platforms? THC std::cout<<"Preparing shared memory and starting server: "<<tmh.getDif()<<std::endl;
///////////////////////////////////////////////////////////////////////////////////////
THC tmh.getDif();pomtime.getDif();//reset timers THC tmh.getDif();pomtime.getDif();//reset timers
cgi->pathf = new CPathfinder(); cgi->pathf = new CPathfinder();
THC std::cout<<"\tPathfinder: "<<pomtime.getDif()<<std::endl; THC std::cout<<"\tPathfinder: "<<pomtime.getDif()<<std::endl;
if(argc>1) if(argc>2)
{ {
std::cout << "Special mode without support for console!" << std::endl; std::cout << "Special mode without support for console!" << std::endl;
} }
@ -171,6 +182,17 @@ int main(int argc, char** argv)
std::ofstream lll("client_log.txt"); std::ofstream lll("client_log.txt");
CConnection *c=NULL; CConnection *c=NULL;
//wait until server is ready
std::cout<<"Waiting for server... " << std::flush;
{
intpr::scoped_lock<intpr::interprocess_mutex> slock(sr->mutex);
while(!sr->ready)
{
sr->cond.wait(slock);
}
}
intpr::shared_memory_object::remove("vcmi_memory");
std::cout << tmh.getDif()<<std::endl;
while(!c) while(!c)
{ {
try try

View File

@ -1,11 +1,11 @@
#include "CSpellWindow.h" #include "CSpellWindow.h"
#include "client/Graphics.h" #include "Graphics.h"
#include "hch/CDefHandler.h" #include "../hch/CDefHandler.h"
#include "hch/CObjectHandler.h" #include "../hch/CObjectHandler.h"
#include "hch/CPreGameTextHandler.h" #include "../hch/CPreGameTextHandler.h"
#include "CAdvmapInterface.h" #include "../CAdvmapInterface.h"
#include "CGameInfo.h" #include "../CGameInfo.h"
#include "SDL_Extensions.h" #include "../SDL_Extensions.h"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <sstream> #include <sstream>

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "global.h" #include "../global.h"
#include "CPlayerInterface.h" #include "../CPlayerInterface.h"
struct SDL_Surface; struct SDL_Surface;
class CDefHandler; class CDefHandler;

View File

@ -255,6 +255,14 @@ void CClient::process(int what)
} }
break; break;
} }
case 109:
{
ChangeSpells vc;
*serv >> vc;
std::cout << "Changing spells of hero "<<vc.hid<<std::endl;
gs->apply(&vc);
break;
}
case 500: case 500:
{ {
RemoveObject rh; RemoveObject rh;

View File

@ -365,6 +365,10 @@
RelativePath="..\hch\CSndHandler.cpp" RelativePath="..\hch\CSndHandler.cpp"
> >
</File> </File>
<File
RelativePath=".\CSpellWindow.cpp"
>
</File>
<File <File
RelativePath="..\CThreadHelper.cpp" RelativePath="..\CThreadHelper.cpp"
> >
@ -511,6 +515,10 @@
RelativePath="..\hch\CSndHandler.h" RelativePath="..\hch\CSndHandler.h"
> >
</File> </File>
<File
RelativePath=".\CSpellWindow.h"
>
</File>
<File <File
RelativePath="..\CThreadHelper.h" RelativePath="..\CThreadHelper.h"
> >

View File

@ -40,6 +40,12 @@ enum ElossCon {lossCastle, lossHero, timeExpires, lossStandard=255};
enum EHeroClasses {HERO_KNIGHT, HERO_CLERIC, HERO_RANGER, HERO_DRUID, HERO_ALCHEMIST, HERO_WIZARD, enum EHeroClasses {HERO_KNIGHT, HERO_CLERIC, HERO_RANGER, HERO_DRUID, HERO_ALCHEMIST, HERO_WIZARD,
HERO_DEMONIAC, HERO_HERETIC, HERO_DEATHKNIGHT, HERO_NECROMANCER, HERO_WARLOCK, HERO_OVERLORD, HERO_DEMONIAC, HERO_HERETIC, HERO_DEATHKNIGHT, HERO_NECROMANCER, HERO_WARLOCK, HERO_OVERLORD,
HERO_BARBARIAN, HERO_BATTLEMAGE, HERO_BEASTMASTER, HERO_WITCH, HERO_PLANESWALKER, HERO_ELEMENTALIST}; HERO_BARBARIAN, HERO_BATTLEMAGE, HERO_BEASTMASTER, HERO_WITCH, HERO_PLANESWALKER, HERO_ELEMENTALIST};
enum EAbilities {DOUBLE_WIDE, FLYING, SHOOTER, TWO_HEX_ATTACK, SIEGE_ABILITY, SIEGE_WEAPON,
KING1, KING2, KING3, MIND_IMMUNITY, NO_OBSTACLE_PENALTY, NO_CLOSE_COMBAT_PENALTY,
JOUSTING, FIRE_IMMUNITY, TWICE_ATTACK, NO_ENEMY_RETALIATION, NO_MORAL_PENALTY,
UNDEAD, MULTI_HEAD_ATTACK, EXTENDED_RADIOUS_SHOOTER, GHOST, RAISES_MORALE,
LOWERS_MORALE, DRAGON, STRIKE_AND_RETURN, FEARLESS, REBIRTH}; //some flags are used only for battles
enum ECombatInfo{ALIVE = REBIRTH+1, SUMMONED, CLONED, HAD_MORALE, WAITING, MOVED, DEFENDING};
class CGameInfo; class CGameInfo;
extern CGameInfo* CGI; extern CGameInfo* CGI;
@ -111,8 +117,8 @@ namespace vstd
{ {
return std::find(c.begin(),c.end(),i) != c.end(); return std::find(c.begin(),c.end(),i) != c.end();
} }
template <typename V, typename Item> template <typename V, typename Item, typename Item2>
bool contains(const std::map<Item,V> & c, const Item &i) bool contains(const std::map<Item,V> & c, const Item2 &i)
{ {
return c.find(i)!=c.end(); return c.find(i)!=c.end();
} }

View File

@ -40,16 +40,16 @@ int CCreature::getQuantityID(int quantity)
bool CCreature::isDoubleWide() bool CCreature::isDoubleWide()
{ {
return boost::algorithm::find_first(abilityRefs, "DOUBLE_WIDE"); return vstd::contains(abilities,DOUBLE_WIDE);
} }
bool CCreature::isFlying() bool CCreature::isFlying()
{ {
return boost::algorithm::find_first(abilityRefs, "FLYING_ARMY"); return vstd::contains(abilities,FLYING);
} }
bool CCreature::isShooting() bool CCreature::isShooting()
{ {
return boost::algorithm::find_first(abilityRefs, "SHOOTING_ARMY"); return vstd::contains(abilities,SHOOTER);
} }
si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatures can be bought si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatures can be bought
{ {
@ -306,6 +306,12 @@ void CCreatureHandler::loadCreatures()
} }
ncre.abilityRefs = buf.substr(befi, i-befi); ncre.abilityRefs = buf.substr(befi, i-befi);
i+=2; i+=2;
if(boost::algorithm::find_first(ncre.abilityRefs, "DOUBLE_WIDE"))
ncre.abilities.insert(DOUBLE_WIDE);
if(boost::algorithm::find_first(ncre.abilityRefs, "FLYING_ARMY"))
ncre.abilities.insert(FLYING);
if(boost::algorithm::find_first(ncre.abilityRefs, "SHOOTING_ARMY"))
ncre.abilities.insert(SHOOTER);
if(ncre.nameSing!=std::string("") && ncre.namePl!=std::string("")) if(ncre.nameSing!=std::string("") && ncre.namePl!=std::string(""))
{ {
ncre.idNumber = creatures.size(); ncre.idNumber = creatures.size();
@ -443,8 +449,10 @@ void CCreatureHandler::loadCreatures()
} }
inp2.close(); inp2.close();
creatures[122].abilityRefs += "DOUBLE_WIDE"; //water elemental should be treated as double-wide
creatures[123].abilityRefs += "DOUBLE_WIDE"; //ice elemental should be treated as double-wide
creatures[122].abilities.insert(DOUBLE_WIDE);//water elemental should be treated as double-wide
creatures[123].abilities.insert(DOUBLE_WIDE);//ice elemental should be treated as double-wide
} }
void CCreatureHandler::loadAnimationInfo() void CCreatureHandler::loadAnimationInfo()

View File

@ -22,6 +22,7 @@ public:
std::string abilityRefs; //references to abilities, in textformat std::string abilityRefs; //references to abilities, in textformat
std::string animDefName; std::string animDefName;
ui32 idNumber; ui32 idNumber;
std::set<EAbilities> abilities;
int faction; //-1 = neutral int faction; //-1 = neutral
///animation info ///animation info

View File

@ -412,6 +412,16 @@ CGHeroInstance::~CGHeroInstance()
CGTownInstance::~CGTownInstance() CGTownInstance::~CGTownInstance()
{} {}
int CGTownInstance::spellsAtLevel(int level, bool checkGuild) const
{
if(checkGuild && mageGuildLevel() < level)
return 0;
int ret = 6 - level; //how many spells are available at this level
if(subID == 2 && vstd::contains(builtBuildings,22)) //magic library in Tower
ret++;
return ret;
}
CGObjectInstance::CGObjectInstance(const CGObjectInstance & right) CGObjectInstance::CGObjectInstance(const CGObjectInstance & right)
{ {
pos = right.pos; pos = right.pos;

View File

@ -168,6 +168,7 @@ public:
bool hasFort() const; bool hasFort() const;
bool hasCapitol() const; bool hasCapitol() const;
int dailyIncome() const; int dailyIncome() const;
int spellsAtLevel(int level, bool checkGuild) const; //levels are counted from 1 (1 - 5)
CGTownInstance(); CGTownInstance();
virtual ~CGTownInstance(); virtual ~CGTownInstance();

22
lib/Interprocess.h Normal file
View File

@ -0,0 +1,22 @@
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
struct ServerReady
{
bool ready;
boost::interprocess::interprocess_mutex mutex;
boost::interprocess::interprocess_condition cond;
ServerReady()
{
ready = false;
}
void setToTrueAndNotify()
{
mutex.lock();
ready = true;
mutex.unlock();
cond.notify_all();
}
};

View File

@ -96,6 +96,18 @@ struct HeroVisitCastle : public CPack<HeroVisitCastle> //108
h & flags & tid & hid; h & flags & tid & hid;
} }
}; };
struct ChangeSpells : public CPack<ChangeSpells> //109
{
ChangeSpells(){type = 109;};
ui8 learn; //1 - gives spell, 0 - takes
ui32 hid;
std::set<ui32> spells;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & learn & hid & spells;
}
};
struct RemoveObject : public CPack<RemoveObject> //500 struct RemoveObject : public CPack<RemoveObject> //500
{ {
RemoveObject(){type = 500;}; RemoveObject(){type = 500;};
@ -442,6 +454,10 @@ struct BattleAttack : public CPack<BattleAttack>//3006
{ {
return flags & 1; return flags & 1;
} }
bool counter()//is it counterattack?
{
return flags & 2;
}
bool killed() //if target stack was killed bool killed() //if target stack was killed
{ {
return bsa.killed(); return bsa.killed();

View File

@ -372,6 +372,10 @@
RelativePath="..\hch\CTownHandler.h" RelativePath="..\hch\CTownHandler.h"
> >
</File> </File>
<File
RelativePath=".\Interprocess.h"
>
</File>
<File <File
RelativePath="..\map.h" RelativePath="..\map.h"
> >

View File

@ -240,11 +240,12 @@ void CGameHandler::changePrimSkill(int ID, int which, int val, bool abs)
} }
} }
void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2) void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb)
{ {
BattleInfo *curB = new BattleInfo; BattleInfo *curB = new BattleInfo;
setupBattle(curB, tile, army1, army2, hero1, hero2); //battle start setupBattle(curB, tile, army1, army2, hero1, hero2); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
NEW_ROUND; NEW_ROUND;
//TODO: pre-tactic stuff, call scripts etc.
//tactic round //tactic round
@ -267,15 +268,15 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
//stack loop //stack loop
for(unsigned i=0;i<stacks.size() && !battleResult.get();i++) for(unsigned i=0;i<stacks.size() && !battleResult.get();i++)
{ {
if(!stacks[i]->alive) continue;//indicates imposiibility of making action for this dead unit if(!stacks[i]->alive()) continue;//indicates imposiibility of making action for this dead unit
BattleSetActiveStack sas; BattleSetActiveStack sas;
sas.stack = stacks[i]->ID; sas.stack = stacks[i]->ID;
sendAndApply(&sas); sendAndApply(&sas);
boost::unique_lock<boost::mutex> lock(battleMadeAction.mx); boost::unique_lock<boost::mutex> lock(battleMadeAction.mx);
while(!battleMadeAction.data) while(!battleMadeAction.data && !battleResult.get()) //active stack hasn't made its action and battle is still going
battleMadeAction.cond.wait(lock); battleMadeAction.cond.wait(lock);
battleMadeAction.data = false; battleMadeAction.data = false;
checkForBattleEnd(stacks); checkForBattleEnd(stacks); //check if this action ended the battle
} }
} }
@ -287,6 +288,8 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
//end battle, remove all info, free memory //end battle, remove all info, free memory
sendAndApply(battleResult.data); sendAndApply(battleResult.data);
if(cb)
cb(battleResult.data);
delete battleResult.data; delete battleResult.data;
//for(int i=0;i<stacks.size();i++) //for(int i=0;i<stacks.size();i++)
// delete stacks[i]; // delete stacks[i];
@ -565,6 +568,14 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
sr.res[i]-=b->resources[i]; sr.res[i]-=b->resources[i];
sendAndApply(&sr); sendAndApply(&sr);
if(bid<5) //it's mage guild
{
if(t->visitingHero)
giveSpells(t,t->visitingHero);
if(t->garrisonHero)
giveSpells(t,t->garrisonHero);
}
break; break;
} }
case 506: //recruit creature case 506: //recruit creature
@ -770,7 +781,7 @@ upgend:
c >> hid >> aid; c >> hid >> aid;
CGHeroInstance *hero = gs->getHero(hid); CGHeroInstance *hero = gs->getHero(hid);
CGTownInstance *town = hero->visitedTown; CGTownInstance *town = hero->visitedTown;
if(aid==0) if(aid==0) //spellbok
{ {
if(!vstd::contains(town->builtBuildings,si32(0))) if(!vstd::contains(town->builtBuildings,si32(0)))
break; break;
@ -786,6 +797,8 @@ upgend:
sha.artifWorn = hero->artifWorn; sha.artifWorn = hero->artifWorn;
sha.artifWorn[17] = 0; sha.artifWorn[17] = 0;
sendAndApply(&sha); sendAndApply(&sha);
giveSpells(town,hero);
} }
else if(aid < 7 && aid > 3) //war machine else if(aid < 7 && aid > 3) //war machine
{ {
@ -883,6 +896,14 @@ upgend:
BattleAttack bat; BattleAttack bat;
prepareAttack(bat,curStack,stackAtEnd); prepareAttack(bat,curStack,stackAtEnd);
sendAndApply(&bat); sendAndApply(&bat);
//counterattack
if(!vstd::contains(curStack->abilities,NO_ENEMY_RETALIATION)
&& !stackAtEnd->counterAttacks ) //TODO: support for multiple retaliatons per turn
{
prepareAttack(bat,stackAtEnd,curStack);
bat.flags |= 2;
sendAndApply(&bat);
}
break; break;
} }
case 7: //shoot case 7: //shoot
@ -942,7 +963,7 @@ void CGameHandler::moveStack(int stack, int dest)
else else
gs->curB->getAccessibilityMap(accessibility,curStack->ID); gs->curB->getAccessibilityMap(accessibility,curStack->ID);
if((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive) || !accessibility[dest]) if((stackAtEnd && stackAtEnd!=curStack && stackAtEnd->alive()) || !accessibility[dest])
return; return;
//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex //if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
@ -1050,6 +1071,18 @@ void CGameHandler::newTurn()
} }
for(std::vector<CGTownInstance *>::iterator j=i->second.towns.begin();j!=i->second.towns.end();j++)//handle towns for(std::vector<CGTownInstance *>::iterator j=i->second.towns.begin();j!=i->second.towns.end();j++)//handle towns
{ {
if(vstd::contains((**j).builtBuildings,15)) //there is resource silo
{
if((**j).town->primaryRes == 127) //we'll give wood and ore
{
r.res[0] += 1;
r.res[2] += 1;
}
else
{
r.res[(**j).town->primaryRes] += 1;
}
}
if(gs->getDate(1)==7) //first day of week if(gs->getDate(1)==7) //first day of week
{ {
SetAvailableCreatures sac; SetAvailableCreatures sac;
@ -1318,17 +1351,36 @@ void CGameHandler::checkForBattleEnd( std::vector<CStack*> &stacks )
hasStack[0] = hasStack[1] = false; hasStack[0] = hasStack[1] = false;
for(int b = 0; b<stacks.size(); ++b) for(int b = 0; b<stacks.size(); ++b)
{ {
if(stacks[b]->alive) if(stacks[b]->alive())
{ {
hasStack[1-stacks[b]->attackerOwned] = true; hasStack[1-stacks[b]->attackerOwned] = true;
} }
} }
if(!hasStack[0] || !hasStack[1]) //somebody has won if(!hasStack[0] || !hasStack[1]) //somebody has won
{ {
BattleResult *br = new BattleResult; BattleResult *br = new BattleResult; //will be deleted at the end of startBattle(...)
br->result = 0; br->result = 0;
br->winner = hasStack[1]; //fleeing side loses br->winner = hasStack[1]; //fleeing side loses
gs->curB->calculateCasualties(br->casualties); gs->curB->calculateCasualties(br->casualties);
battleResult.set(br); battleResult.set(br);
} }
}
void CGameHandler::giveSpells( const CGTownInstance *t, const CGHeroInstance *h )
{
if(!vstd::contains(h->artifWorn,17))
return; //hero hasn't spellbok
ChangeSpells cs;
cs.hid = h->id;
cs.learn = true;
for(int i=0; i<std::min(t->mageGuildLevel(),h->getSecSkillLevel(7)+4);i++)
{
for(int j=0; j<t->spellsAtLevel(i+1,true); j++)
{
if(!vstd::contains(h->spells,t->spells[i][j]))
cs.spells.insert(t->spells[i][j]);
}
}
if(cs.spells.size())
sendAndApply(&cs);
} }

View File

@ -11,6 +11,7 @@ class CGameState;
struct StartInfo; struct StartInfo;
class CCPPObjectScript; class CCPPObjectScript;
class CScriptCallback; class CScriptCallback;
struct BattleResult;
template <typename T> struct CPack; template <typename T> struct CPack;
template <typename T> struct Query; template <typename T> struct Query;
class CGHeroInstance; class CGHeroInstance;
@ -52,8 +53,9 @@ class CGameHandler
void handleCPPObjS(std::map<int,CCPPObjectScript*> * mapa, CCPPObjectScript * script); void handleCPPObjS(std::map<int,CCPPObjectScript*> * mapa, CCPPObjectScript * script);
void changePrimSkill(int ID, int which, int val, bool abs=false); void changePrimSkill(int ID, int which, int val, bool abs=false);
void changeSecSkill(int ID, ui16 which, int val, bool abs=false); void changeSecSkill(int ID, ui16 which, int val, bool abs=false);
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
void moveStack(int stack, int dest); void moveStack(int stack, int dest);
void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2); //use hero=NULL for no hero void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
void checkForBattleEnd( std::vector<CStack*> &stacks ); void checkForBattleEnd( std::vector<CStack*> &stacks );
void setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 ); void setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 );

View File

@ -117,6 +117,7 @@ void CScriptCallback::heroVisitCastle(int obj, int heroID)
vc.tid = obj; vc.tid = obj;
vc.flags |= 1; vc.flags |= 1;
gh->sendAndApply(&vc); gh->sendAndApply(&vc);
gh->giveSpells(getTown(obj),getHero(heroID));
} }
void CScriptCallback::stopHeroVisitCastle(int obj, int heroID) void CScriptCallback::stopHeroVisitCastle(int obj, int heroID)
@ -144,16 +145,25 @@ void CScriptCallback::giveHeroArtifact(int artid, int hid, int position) //pos==
gh->sendAndApply(&sha); gh->sendAndApply(&sha);
} }
void CScriptCallback::startBattle(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) //use hero=NULL for no hero void CScriptCallback::startBattle(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb) //use hero=NULL for no hero
{ {
boost::thread(boost::bind(&CGameHandler::startBattle,gh,*(CCreatureSet *)army1,*(CCreatureSet *)army2,tile,(CGHeroInstance *)hero1,(CGHeroInstance *)hero2)); boost::thread(boost::bind(&CGameHandler::startBattle,gh,*(CCreatureSet *)army1,*(CCreatureSet *)army2,tile,(CGHeroInstance *)hero1,(CGHeroInstance *)hero2,cb));
} }
void CScriptCallback::startBattle(int heroID, CCreatureSet army, int3 tile) //for hero<=>neutral army void CScriptCallback::startBattle(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) //for hero<=>neutral army
{ {
CGHeroInstance* h = const_cast<CGHeroInstance*>(getHero(heroID)); CGHeroInstance* h = const_cast<CGHeroInstance*>(getHero(heroID));
startBattle(&h->army,&army,tile,h,NULL); startBattle(&h->army,&army,tile,h,NULL,cb);
//gh->gs->battle(&h->army,army,tile,h,NULL); //gh->gs->battle(&h->army,army,tile,h,NULL);
} }
void CScriptCallback::changeSpells( int hid, bool give, const std::set<ui32> &spells )
{
ChangeSpells cs;
cs.hid = hid;
cs.spells = spells;
cs.learn = give;
gh->sendAndApply(&cs);
}
void CLuaCallback::registerFuncs(lua_State * L) void CLuaCallback::registerFuncs(lua_State * L)
{ {
// lua_newtable(L); // lua_newtable(L);

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "../global.h" #include "../global.h"
#include <vector> #include <vector>
#include <set>
#include "../client/FunctionList.h" #include "../client/FunctionList.h"
class CVCMIServer; class CVCMIServer;
class CGameHandler; class CGameHandler;
@ -19,6 +20,7 @@ struct InfoWindow;
struct ShowInInfobox; struct ShowInInfobox;
struct SelectionDialog; struct SelectionDialog;
struct YesNoDialog; struct YesNoDialog;
struct BattleResult;
class CScriptCallback class CScriptCallback
{ {
CScriptCallback(void); CScriptCallback(void);
@ -37,6 +39,7 @@ public:
const CGTownInstance* getTown(int objid); const CGTownInstance* getTown(int objid);
//do sth //do sth
void changeSpells(int hid, bool give, const std::set<ui32> &spells);
void removeObject(int objid); void removeObject(int objid);
void setBlockVis(int objid, bool bv); void setBlockVis(int objid, bool bv);
void setOwner(int objid, ui8 owner); void setOwner(int objid, ui8 owner);
@ -50,8 +53,8 @@ public:
void heroVisitCastle(int obj, int heroID); void heroVisitCastle(int obj, int heroID);
void stopHeroVisitCastle(int obj, int heroID); void stopHeroVisitCastle(int obj, int heroID);
void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack
void startBattle(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2); //use hero=NULL for no hero void startBattle(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
void startBattle(int heroID, CCreatureSet army, int3 tile); //for hero<=>neutral army void startBattle(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
//friends //friends
friend class CGameHandler; friend class CGameHandler;

View File

@ -9,21 +9,28 @@
#endif #endif
#include "CVCMIServer.h" #include "CVCMIServer.h"
#include <boost/crc.hpp> #include <boost/crc.hpp>
#include <boost/serialization/split_member.hpp> #include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include "../StartInfo.h" #include "../StartInfo.h"
#include "../map.h" #include "../map.h"
#include "../hch/CLodHandler.h" #include "../hch/CLodHandler.h"
#include "../lib/Interprocess.h"
#include "../lib/VCMI_Lib.h" #include "../lib/VCMI_Lib.h"
#include "CGameHandler.h" #include "CGameHandler.h"
std::string NAME = NAME_VER + std::string(" (server)"); std::string NAME = NAME_VER + std::string(" (server)");
using boost::asio::ip::tcp;
using namespace boost; using namespace boost;
using namespace boost::asio; using namespace boost::asio;
using namespace boost::asio::ip; using namespace boost::asio::ip;
namespace intpr = boost::interprocess;
bool end2 = false; bool end2 = false;
int port = 3030; int port = 3030;
void vaccept(tcp::acceptor *ac, tcp::socket *s, boost::system::error_code *error)
{
ac->accept(*s,*error);
}
CVCMIServer::CVCMIServer() CVCMIServer::CVCMIServer()
: io(new io_service()), acceptor(new tcp::acceptor(*io, tcp::endpoint(tcp::v4(), port))) : io(new io_service()), acceptor(new tcp::acceptor(*io, tcp::endpoint(tcp::v4(), port)))
{ {
@ -90,10 +97,29 @@ void CVCMIServer::newGame(CConnection *c)
} }
void CVCMIServer::start() void CVCMIServer::start()
{ {
ServerReady *sr = NULL;
intpr::mapped_region *mr;
try
{
intpr::shared_memory_object smo(intpr::open_only,"vcmi_memory",intpr::read_write);
mr = new intpr::mapped_region(smo,intpr::read_write);
sr = (ServerReady*)mr->get_address();
}
catch(...)
{
intpr::shared_memory_object smo(intpr::create_only,"vcmi_memory",intpr::read_write);
smo.truncate(sizeof(ServerReady));
mr = new intpr::mapped_region(smo,intpr::read_write);
sr = new(mr->get_address())ServerReady();
}
boost::system::error_code error; boost::system::error_code error;
std::cout<<"Listening for connections at port " << acceptor->local_endpoint().port() << std::endl; std::cout<<"Listening for connections at port " << acceptor->local_endpoint().port() << std::endl;
tcp::socket * s = new tcp::socket(acceptor->io_service()); tcp::socket * s = new tcp::socket(acceptor->io_service());
acceptor->accept(*s,error); boost::thread acc(boost::bind(vaccept,acceptor,s,&error));
sr->setToTrueAndNotify();
delete mr;
acc.join();
if (error) if (error)
{ {
std::cout<<"Got connection but there is an error " << std::endl << error; std::cout<<"Got connection but there is an error " << std::endl << error;
@ -147,7 +173,9 @@ int main(int argc, char** argv)
io_service io_service; io_service io_service;
CVCMIServer server; CVCMIServer server;
while(!end2) while(!end2)
{
server.start(); server.start();
}
io_service.run(); io_service.run();
} HANDLE_EXCEPTION } HANDLE_EXCEPTION
return 0; return 0;