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

Rewrote hero moving code. Seems to be working.

This commit is contained in:
Michał W. Urbańczyk 2008-07-28 12:44:08 +00:00
parent 001868652a
commit 3247a9a4dd
15 changed files with 454 additions and 233 deletions

View File

@ -17,8 +17,16 @@
#include "lib/Connection.h"
#include "client/Client.h"
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include "lib/NetPacks.h"
//LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
extern CSharedCond<std::set<IPack*> > mess;
HeroMoveDetails::HeroMoveDetails(int3 Src, int3 Dst, CGHeroInstance*Ho)
:src(Src),dst(Dst),ho(Ho)
{
owner = ho->getOwner();
};
bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
{
CGHeroInstance * hero = NULL;
@ -69,120 +77,123 @@ bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
return false;
for(int i=ourPath->nodes.size()-1; i>0; i--)
{
int3 stpos, endpos;
stpos = int3(ourPath->nodes[i].coord.x, ourPath->nodes[i].coord.y, hero->pos.z);
endpos = int3(ourPath->nodes[i-1].coord.x, ourPath->nodes[i-1].coord.y, hero->pos.z);
HeroMoveDetails curd;
curd.src = stpos;
curd.dst = endpos;
curd.ho = hero;
curd.owner = hero->getOwner();
/*if(player!=-1)
{
hero->pos = endpos;
}*/
if(hero->movement >= (ourPath->nodes.size()>=2 ? (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist || player==-1)
{ //performing move
hero->movement -= (ourPath->nodes.size()>=2 ? (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist;
ourPath->nodes.pop_back();
std::vector< CGObjectInstance * > vis = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.dst,false));
bool blockvis = false;
for (int pit = 0; pit<vis.size();pit++)
if (vis[pit]->blockVisit)
blockvis = true;
int3 stpos(ourPath->nodes[i].coord.x, ourPath->nodes[i].coord.y, hero->pos.z),
endpos(ourPath->nodes[i-1].coord.x, ourPath->nodes[i-1].coord.y, hero->pos.z);
HeroMoveDetails curd(stpos,endpos,hero);
if (!blockvis)
{
curd.successful = true;
hero->pos = curd.dst;
//inform leaved objects
std::vector< CGObjectInstance * > leave = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.src,false));
for (int iii=0; iii<leave.size(); iii++) //if object is visitable we call onHeroVisit
{
//TODO: allow to handle this in LUA
if(leave[iii]->state) //hard-coded function
leave[iii]->state->onHeroLeave(leave[iii],curd.ho->subID);
}
//reveal fog of war
int heroSight = hero->getSightDistance();
int xbeg = stpos.x - heroSight - 2;
if(xbeg < 0)
xbeg = 0;
int xend = stpos.x + heroSight + 2;
if(xend >= CGI->mh->map->width)
xend = CGI->mh->map->width;
int ybeg = stpos.y - heroSight - 2;
if(ybeg < 0)
ybeg = 0;
int yend = stpos.y + heroSight + 2;
if(yend >= CGI->mh->map->height)
yend = CGI->mh->map->height;
for(int xd=xbeg; xd<xend; ++xd) //revealing part of map around heroes
{
for(int yd=ybeg; yd<yend; ++yd)
{
int deltaX = (hero->getPosition(false).x-xd)*(hero->getPosition(false).x-xd);
int deltaY = (hero->getPosition(false).y-yd)*(hero->getPosition(false).y-yd);
if(deltaX+deltaY<hero->getSightDistance()*hero->getSightDistance())
{
if(gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] == 0)
{
CGI->playerint[gs->players[player].serial]->tileRevealed(int3(xd, yd, hero->getPosition(false).z));
}
gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] = 1;
}
}
}
//notify interfacesabout move
int nn=0; //number of interfece of currently browsed player
for(std::map<ui8, PlayerState>::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing
{
if (j->first > PLAYER_LIMIT)
break;
if(j->second.fogOfWarMap[stpos.x-1][stpos.y][stpos.z] || j->second.fogOfWarMap[endpos.x-1][endpos.y][endpos.z])
{ //player should be notified
CGI->playerint[j->second.serial]->heroMoved(curd);
}
++nn;
}
//call objects if they arevisited
for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
{
if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
if(vis[iii]->state) //hard-coded function
vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
}
}
else //interaction with blocking object (like resources)
{
curd.successful = false;
CGI->playerint[gs->players[hero->getOwner()].serial]->heroMoved(curd);
for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
{
if (vis[iii]->blockVisit)
{
if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
if(vis[iii]->state) //hard-coded function
vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
}
}
*cl->serv << ui16(501) << hero->id << stpos << endpos;
{//wait till there is server answer
boost::unique_lock<boost::mutex> lock(*mess.mx);
while(std::find_if(mess.res->begin(),mess.res->end(),IPack::isType<501>) == mess.res->end())
mess.cv->wait(lock);
std::set<IPack*>::iterator itr = std::find_if(mess.res->begin(),mess.res->end(),IPack::isType<501>);
TryMoveHero tmh = *static_cast<TryMoveHero*>(*itr);
mess.res->erase(itr);
if(!tmh.result)
return false;
}
}
else
return true; //move ended - no more movement points
}
// if(hero->movement >= (ourPath->nodes.size()>=2 ? (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist || player==-1)
// { //performing move
// hero->movement -= (ourPath->nodes.size()>=2 ? (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist;
// ourPath->nodes.pop_back();
//
// std::vector< CGObjectInstance * > vis = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.dst,false));
// bool blockvis = false;
// for (int pit = 0; pit<vis.size();pit++)
// if (vis[pit]->blockVisit)
// blockvis = true;
// if (!blockvis)
// {
// curd.successful = true;
// hero->pos = curd.dst;
// //inform leaved objects
// std::vector< CGObjectInstance * > leave = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.src,false));
// for (int iii=0; iii<leave.size(); iii++) //if object is visitable we call onHeroVisit
// {
// //TODO: allow to handle this in LUA
// if(leave[iii]->state) //hard-coded function
// leave[iii]->state->onHeroLeave(leave[iii],curd.ho->subID);
// }
// //reveal fog of war
// int heroSight = hero->getSightDistance();
// int xbeg = stpos.x - heroSight - 2;
// if(xbeg < 0)
// xbeg = 0;
// int xend = stpos.x + heroSight + 2;
// if(xend >= CGI->mh->map->width)
// xend = CGI->mh->map->width;
// int ybeg = stpos.y - heroSight - 2;
// if(ybeg < 0)
// ybeg = 0;
// int yend = stpos.y + heroSight + 2;
// if(yend >= CGI->mh->map->height)
// yend = CGI->mh->map->height;
// for(int xd=xbeg; xd<xend; ++xd) //revealing part of map around heroes
// {
// for(int yd=ybeg; yd<yend; ++yd)
// {
// int deltaX = (hero->getPosition(false).x-xd)*(hero->getPosition(false).x-xd);
// int deltaY = (hero->getPosition(false).y-yd)*(hero->getPosition(false).y-yd);
// if(deltaX+deltaY<hero->getSightDistance()*hero->getSightDistance())
// {
// if(gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] == 0)
// {
// cl->playerint[player]->tileRevealed(int3(xd, yd, hero->getPosition(false).z));
// }
// gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] = 1;
// }
// }
// }
// //notify interfacesabout move
// int nn=0; //number of interfece of currently browsed player
// for(std::map<ui8, PlayerState>::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing
// {
// if (j->first > PLAYER_LIMIT)
// break;
// if(j->second.fogOfWarMap[stpos.x-1][stpos.y][stpos.z] || j->second.fogOfWarMap[endpos.x-1][endpos.y][endpos.z])
// { //player should be notified
// cl->playerint[j->second.color]->heroMoved(curd);
// }
// ++nn;
// }
// //call objects if they arevisited
// for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
// {
// if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
// gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
// if(vis[iii]->state) //hard-coded function
// vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
// }
// }
// else //interaction with blocking object (like resources)
// {
// curd.successful = false;
// cl->playerint[gs->players[hero->getOwner()].color]->heroMoved(curd);
// for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
// {
// if (vis[iii]->blockVisit)
// {
// if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
// gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
// if(vis[iii]->state) //hard-coded function
// vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
// }
// }
// return false;
// }
// }
//}
return true;
}
@ -254,7 +265,7 @@ void CCallback::recruitCreatures(const CGObjectInstance *obj, int ID, int amount
t->army.slots[slot].first = &CGI->creh->creatures[ID];
t->army.slots[slot].second = amount;
}
CGI->playerint[gs->players[player].serial]->garrisonChanged(obj);
cl->playerint[player]->garrisonChanged(obj);
}
//TODO: recruit from dwellings on the adventure map
@ -267,7 +278,7 @@ bool CCallback::dismissCreature(const CArmedInstance *obj, int stackPos)
return false;
CArmedInstance *ob = const_cast<CArmedInstance*>(obj);
ob->army.slots.erase(stackPos);
CGI->playerint[gs->players[player].serial]->garrisonChanged(obj);
cl->playerint[player]->garrisonChanged(obj);
return true;
}
bool CCallback::upgradeCreature(const CArmedInstance *obj, int stackPos, int newID)
@ -515,27 +526,9 @@ int CCallback::swapCreatures(const CGObjectInstance *s1, const CGObjectInstance
S2->slots.erase(p2);
if(s1->tempOwner<PLAYER_LIMIT)
{
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == s1->tempOwner)
{
CGI->playerint[b]->garrisonChanged(s1);
break;
}
}
}
cl->playerint[s1->tempOwner]->garrisonChanged(s1);
if((s2->tempOwner<PLAYER_LIMIT) && (s2 != s1))
{
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == s2->tempOwner)
{
CGI->playerint[b]->garrisonChanged(s2);
break;
}
}
}
cl->playerint[s2->tempOwner]->garrisonChanged(s2);
return 0;
}
@ -555,27 +548,10 @@ int CCallback::mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s
S1->slots.erase(p1);
if(s1->tempOwner<PLAYER_LIMIT)
{
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == s1->tempOwner)
{
CGI->playerint[b]->garrisonChanged(s1);
break;
}
}
}
cl->playerint[s1->tempOwner]->garrisonChanged(s1);
if((s2->tempOwner<PLAYER_LIMIT) && (s2 != s1))
{
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == s2->tempOwner)
{
CGI->playerint[b]->garrisonChanged(s2);
break;
}
}
}
cl->playerint[s2->tempOwner]->garrisonChanged(s2);
return 0;
}
int CCallback::splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)
@ -597,25 +573,11 @@ int CCallback::splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2
if(s1->tempOwner<PLAYER_LIMIT)
{
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == s1->tempOwner)
{
CGI->playerint[b]->garrisonChanged(s1);
break;
}
}
cl->playerint[s1->tempOwner]->garrisonChanged(s1);
}
if((s2->tempOwner<PLAYER_LIMIT) && (s2 != s1))
{
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == s2->tempOwner)
{
CGI->playerint[b]->garrisonChanged(s2);
break;
}
}
cl->playerint[s2->tempOwner]->garrisonChanged(s2);
}
return 0;
}
@ -686,7 +648,7 @@ bool CCallback::buildBuilding(const CGTownInstance *town, int buildingID)
for(int i=0;i<7;i++)
gs->players[player].resources[i]-=b->resources[i];
t->builded++;
CGI->playerint[CGI->state->players[player].serial]->buildChanged(town,buildingID,1);
cl->playerint[player]->buildChanged(town,buildingID,1);
return true;
}
@ -782,18 +744,11 @@ int3 CScriptCallback::getPos(CGObjectInstance * ob)
}
void CScriptCallback::changePrimSkill(int ID, int which, int val)
{
CGHeroInstance * hero = CGI->state->map->getHero(ID,0);
CGHeroInstance * hero = gs->map->getHero(ID,0);
if (which<PRIMARY_SKILLS)
{
hero->primSkills[which]+=val;
for (int i=0; i<CGI->playerint.size(); i++)
{
if (CGI->playerint[i]->playerID == hero->getOwner())
{
CGI->playerint[i]->heroPrimarySkillChanged(hero, which, val);
break;
}
}
cl->playerint[hero->getOwner()]->heroPrimarySkillChanged(hero, which, val);
}
else if (which==4)
{
@ -830,24 +785,25 @@ void CScriptCallback::showInfoDialog(int player, std::string text, std::vector<S
//TODO: upewniac sie ze mozemy to zrzutowac (przy customowych interfejsach cos moze sie kopnac)
if (player>=0)
{
CGameInterface * temp = CGI->playerint[CGI->state->players[player].serial];
CGameInterface * temp = cl->playerint[player];
if (temp->human)
((CPlayerInterface*)(temp))->showInfoDialog(text,*components);
return;
}
else
{
for (int i=0; i<CGI->playerint.size();i++)
typedef std::pair<const ui8, CGameInterface*> intf;
BOOST_FOREACH(intf & i, cl->playerint)
{
if (CGI->playerint[i]->human)
((CPlayerInterface*)(CGI->playerint[i]))->showInfoDialog(text,*components);
if (i.second->human)
((CPlayerInterface*)(i.second))->showInfoDialog(text,*components);
}
}
}
void CScriptCallback::showSelDialog(int player, std::string text, std::vector<CSelectableComponent*>*components, IChosen * asker)
{
CGameInterface * temp = CGI->playerint[CGI->state->players[player].serial];
CGameInterface * temp = cl->playerint[player];
if (temp->human)
((CPlayerInterface*)(temp))->showSelDialog(text,*components,(int)asker);
return;
@ -891,11 +847,11 @@ int CScriptCallback::getDate(int mode)
void CScriptCallback::giveResource(int player, int which, int val)
{
gs->players[player].resources[which]+=val;
CGI->playerint[gs->players[player].serial]->receivedResource(which,val);
cl->playerint[player]->receivedResource(which,val);
}
void CScriptCallback::showCompInfo(int player, SComponent * comp)
{
CPlayerInterface * i = dynamic_cast<CPlayerInterface*>(CGI->playerint[gs->players[player].serial]);
CPlayerInterface * i = dynamic_cast<CPlayerInterface*>(cl->playerint[player]);
if(i)
i->showComp(*comp);
}
@ -905,15 +861,8 @@ void CScriptCallback::heroVisitCastle(CGObjectInstance * ob, int heroID)
if(n = dynamic_cast<CGTownInstance*>(ob))
{
n->visitingHero = CGI->state->map->getHero(heroID,0);
CGI->state->map->getHero(heroID,0)->visitedTown = n;
for(int b=0; b<CGI->playerint.size(); ++b)
{
if(CGI->playerint[b]->playerID == getHeroOwner(heroID))
{
CGI->playerint[b]->heroVisitsTown(CGI->state->map->getHero(heroID,0),n);
break;
}
}
gs->map->getHero(heroID,0)->visitedTown = n;
cl->playerint[getHeroOwner(heroID)]->heroVisitsTown(CGI->state->map->getHero(heroID,0),n);
}
else
return;

View File

@ -78,6 +78,8 @@ public:
struct HeroMoveDetails
{
HeroMoveDetails(){};
HeroMoveDetails(int3 Src, int3 Dst, CGHeroInstance*Ho);
int3 src, dst; //source and destination points
CGHeroInstance * ho; //object instance of this hero
int owner;
@ -152,8 +154,10 @@ public:
};
class CScriptCallback
{
CScriptCallback(){};
public:
CGameState * gs;
CClient *cl;
//get info
static int3 getPos(CGObjectInstance * ob);
@ -162,7 +166,7 @@ public:
int getDate(int mode=0);
//do sth
static void changePrimSkill(int ID, int which, int val);
void changePrimSkill(int ID, int which, int val);
void showInfoDialog(int player, std::string text, std::vector<SComponent*> * components); //TODO: obslugiwac nulle
void showSelDialog(int player, std::string text, std::vector<CSelectableComponent*>*components, IChosen * asker);
void giveResource(int player, int which, int val);

View File

@ -58,8 +58,6 @@ public:
CPathfinder * pathf;
CCursorHandler * curh;
CScreenHandler * screenh;
int localPlayer;
std::vector<CGameInterface *> playerint;
};
#endif //CGAMEINFO_H

View File

@ -128,6 +128,20 @@ void CGameState::apply(IPack * pack)
if(n->resetBuilded) //reset amount of structures set in this turn in towns
BOOST_FOREACH(CGTownInstance* t, map->towns)
t->builded = 0;
break;
}
case 501://hero try-move
{
TryMoveHero * n = static_cast<TryMoveHero*>(pack);
CGHeroInstance *h = static_cast<CGHeroInstance*>(map->objects[n->id]);
h->movement = n->movePoints;
if(n->result)
h->pos = n->end;
else
h->pos = n->start;
BOOST_FOREACH(int3 t, n->fowRevealed)
players[h->getOwner()].fogOfWarMap[t.x][t.y][t.z] = 1;
break;
}
}
mx->unlock();

View File

@ -340,7 +340,7 @@ void CGarrisonInt::createSlots()
{
sup = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL));
for
(std::map<int,std::pair<CCreature*,int> >::const_iterator i=set1->slots.begin();
(std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=set1->slots.begin();
i!=set1->slots.end(); i++)
{
(*sup)[i->first] =
@ -354,7 +354,7 @@ void CGarrisonInt::createSlots()
{
sdown = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL));
for
(std::map<int,std::pair<CCreature*,int> >::const_iterator i=set2->slots.begin();
(std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=set2->slots.begin();
i!=set2->slots.end(); i++)
{
(*sdown)[i->first] =
@ -902,13 +902,11 @@ CPlayerInterface::CPlayerInterface(int Player, int serial)
LOCPLINT = this;
playerID=Player;
serialID=serial;
CGI->localPlayer = playerID;
human=true;
}
void CPlayerInterface::init(ICallback * CB)
{
cb = dynamic_cast<CCallback*>(CB);
CGI->localPlayer = serialID;
adventureInt = new CAdvMapInt(playerID);
castleInt = NULL;
std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
@ -928,7 +926,6 @@ void CPlayerInterface::yourTurn()
{
LOCPLINT = this;
makingTurn = true;
CGI->localPlayer = serialID;
unsigned char & animVal = LOCPLINT->adventureInt->anim; //for animations handling
unsigned char & heroAnimVal = LOCPLINT->adventureInt->heroAnim;
adventureInt->infoBar.newDay(cb->getDate(1));

View File

@ -11,6 +11,9 @@
#include "../lib/NetPacks.h"
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include "../hch/CObjectHandler.h"
CSharedCond<std::set<IPack*> > mess(new std::set<IPack*>);
CClient::CClient(void)
{
}
@ -58,17 +61,18 @@ CClient::CClient(CConnection *con, StartInfo *si)
for (int i=0; i<CGI->state->scenarioOps->playerInfos.size();i++) //initializing interfaces
{
CCallback *cb = new CCallback(CGI->state,CGI->state->scenarioOps->playerInfos[i].color,this);
if(!CGI->state->scenarioOps->playerInfos[i].human)
CGI->playerint.push_back(static_cast<CGameInterface*>(CAIHandler::getNewAI(cb,"EmptyAI.dll")));
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"));
else
{
CGI->state->currentPlayer=CGI->state->scenarioOps->playerInfos[i].color;
CGI->playerint.push_back(new CPlayerInterface(CGI->state->scenarioOps->playerInfos[i].color,i));
((CPlayerInterface*)(CGI->playerint[i]))->init(cb);
gs->currentPlayer = color;
playerint[color] = new CPlayerInterface(color,i);
playerint[color]->init(cb);
}
}
CGI->consoleh->cb = new CCallback(CGI->state,-1,this);
CGI->consoleh->cb = new CCallback(gs,-1,this);
}
CClient::~CClient(void)
{
@ -82,7 +86,7 @@ void CClient::process(int what)
ui8 player;
*serv >> player;//who?
std::cout << "It's turn of "<<(unsigned)player<<" player."<<std::endl;
boost::thread(boost::bind(&CGameInterface::yourTurn,CGI->playerint[gs->players[player].serial]));
boost::thread(boost::bind(&CGameInterface::yourTurn,playerint[player]));
break;
}
case 101:
@ -94,6 +98,42 @@ void CClient::process(int what)
std::cout << "done!"<<std::endl;
break;
}
case 501: //hero movement response - we have to notify interfaces and callback
{
TryMoveHero *th = new TryMoveHero;
*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;
}
default:
throw std::exception("Not supported server message!");
break;

View File

@ -5,10 +5,37 @@ class CGameState;
class CGameInterface;
class CConnection;
class CCallback;
namespace boost
{
class mutex;
class condition_variable;
}
template <typename T>
struct CSharedCond
{
boost::mutex *mx;
boost::condition_variable *cv;
T *res;
CSharedCond(T*R)
{
res = R;
mx = new boost::mutex;
cv = new boost::condition_variable;
}
~CSharedCond()
{
delete res;
delete mx;
delete cv;
}
};
class CClient
{
CGameState *gs;
std::map<int,CGameInterface *> playerint;
std::map<ui8,CGameInterface *> playerint;
CConnection *serv;
public:
CClient(void);
@ -19,4 +46,5 @@ public:
void run();
friend class CCallback;
friend class CScriptCallback;
};

View File

@ -35,7 +35,7 @@ SDL_Surface * Graphics::drawHeroInfoWin(const CGHeroInstance * curh)
SDL_SetColorKey(ret,SDL_SRCCOLORKEY,SDL_MapRGB(ret->format,0,255,255));
printAt(curh->name,75,15,GEOR13,zwykly,ret);
drawPrimarySkill(curh, ret);
for (std::map<int,std::pair<CCreature*,int> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
for (std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
{
blitAt(graphics->smallImgs[(*i).second.first->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
itoa((*i).second.second,buf,10);
@ -64,7 +64,7 @@ SDL_Surface * Graphics::drawTownInfoWin(const CGTownInstance * curh)
blitAt(halls->ourImages[pom].bitmap,77,42,ret);
itoa(curh->dailyIncome(),buf,10);
printAtMiddle(buf,167,70,GEORM,zwykly,ret);
for (std::map<int,std::pair<CCreature*,int> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
for (std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
{
if(!i->second.first)
continue;

View File

@ -53,7 +53,7 @@ class DLL_EXPORT CGObjectInstance
public:
int3 pos; //h3m pos
int ID, subID; //normal ID (this one from OH3 maps ;]) - eg. town=98; hero=34
int id;//number of object in CObjectHandler's vector
si32 id;//number of object in CObjectHandler's vector
CGDefInfo * defInfo;
CCPPObjectScript * state;
CSpecObjInfo * info;

20
int3.h
View File

@ -5,26 +5,26 @@ class CCreature;
class CCreatureSet //seven combined creatures
{
public:
std::map<int,std::pair<CCreature*,int> > slots;
std::map<si32,std::pair<CCreature*,si32> > slots;
bool formation; //false - wide, true - tight
};
class int3
{
public:
int x,y,z;
si32 x,y,z;
inline int3():x(0),y(0),z(0){}; //c-tor, x/y/z initialized to 0
inline int3(const int & X, const int & Y, const int & Z):x(X),y(Y),z(Z){}; //c-tor
inline int3(const si32 & X, const si32 & Y, const si32 & Z):x(X),y(Y),z(Z){}; //c-tor
inline ~int3(){} // d-tor - does nothing
inline int3 operator+(const int3 & i) const
{return int3(x+i.x,y+i.y,z+i.z);}
inline int3 operator+(const int i) const //increases all components by int
inline int3 operator+(const si32 i) const //increases all components by si32
{return int3(x+i,y+i,z+i);}
inline int3 operator-(const int3 & i) const
{return int3(x-i.x,y-i.y,z-i.z);}
inline int3 operator-(const int i) const
inline int3 operator-(const si32 i) const
{return int3(x-i,y-i,z-i);}
inline int3 operator-() const //increases all components by int
inline int3 operator-() const //increases all components by si32
{return int3(-x,-y,-z);}
inline void operator+=(const int3 & i)
{
@ -32,7 +32,7 @@ public:
y+=i.y;
z+=i.z;
}
inline void operator+=(const int & i)
inline void operator+=(const si32 & i)
{
x+=i;
y+=i;
@ -44,7 +44,7 @@ public:
y-=i.y;
z-=i.z;
}
inline void operator-=(const int & i)
inline void operator-=(const si32 & i)
{
x+=i;
y+=i;
@ -70,6 +70,10 @@ public:
return false;
return false;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & x & y & z;
}
};
inline std::istream & operator>>(std::istream & str, int3 & dest)
{

View File

@ -1,13 +1,28 @@
#include "../global.h"
struct IPack
{
virtual ui16 getType()=0;
virtual ui16 getType()const = 0 ;
//template<ui16 Type>
//static bool isType(const IPack * ip)
//{
// return Type == ip->getType();
//}
template<ui16 Type>
static bool isType(IPack * ip)
{
return Type == ip->getType();
}
//template<ui16 Type>
//static bool isType(const IPack & ip)
//{
// return Type == ip.getType();
//}
};
template <typename T> struct CPack
:public IPack
{
ui16 type;
ui16 getType(){return type;}
ui16 getType() const{return type;}
T* This(){return static_cast<T*>(this);};
};
struct NewTurn : public CPack<NewTurn> //101
@ -43,4 +58,18 @@ struct NewTurn : public CPack<NewTurn> //101
{
h & heroes & res & day & resetBuilded;
}
};
struct TryMoveHero : public CPack<TryMoveHero> //501
{
TryMoveHero(){type = 501;};
ui32 id, movePoints;
ui8 result;
int3 start, end;
std::set<int3> fowRevealed; //revealed tiles
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & result & start & end & movePoints & fowRevealed;
}
};

32
map.cpp
View File

@ -926,6 +926,8 @@ void Mapa::initFromBytes(unsigned char * bufor)
terrain[z][c].malle = (Eroad)bufor[i++];
terrain[z][c].roadDir = bufor[i++];
terrain[z][c].siodmyTajemniczyBajt = bufor[i++];
terrain[z][c].blocked = 0;
terrain[z][c].visitable = 0;
}
}
if (twoLevel) // read underground terrain
@ -941,6 +943,8 @@ void Mapa::initFromBytes(unsigned char * bufor)
undergroungTerrain[z][c].malle = (Eroad)bufor[i++];
undergroungTerrain[z][c].roadDir = bufor[i++];
undergroungTerrain[z][c].siodmyTajemniczyBajt = bufor[i++];
undergroungTerrain[z][c].blocked = 0;
undergroungTerrain[z][c].visitable = 0;
}
}
}
@ -2289,6 +2293,34 @@ borderguardend:
//map readed, bufor no longer needed
delete[] bufor; bufor=NULL;
for(int f=0; f<objects.size(); ++f) //calculationg blocked / visitable positions
{
if(!objects[f]->defInfo)
continue;
CDefHandler * curd = objects[f]->defInfo->handler;
for(int fx=0; fx<8; ++fx)
{
for(int fy=0; fy<6; ++fy)
{
int xVal = objects[f]->pos.x + fx - 7;
int yVal = objects[f]->pos.y + fy - 5;
int zVal = objects[f]->pos.z;
if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
{
TerrainTile & curt = (zVal) ? (undergroungTerrain[xVal][yVal]) : (terrain[xVal][yVal]);
if(((objects[f]->defInfo->visitMap[fy] >> (7 - fx)) & 1))
{
curt.visitableObjects.push_back(objects[f]);
curt.visitable = true;
}
if(!((objects[f]->defInfo->blockMap[fy] >> (7 - fx)) & 1))
curt.blocked = true;
}
}
}
}
}
Mapa::Mapa(std::string filename)

5
map.h
View File

@ -263,6 +263,11 @@ struct DLL_EXPORT TerrainTile
Eroad malle; // type of Eroad (0 if there is no Eriver)
unsigned char roadDir; // direction of Eroad
unsigned char siodmyTajemniczyBajt; //bitfield, info whether this tile is coastal and how to rotate tile graphics
bool visitable; //false = not visitable; true = visitable
bool blocked; //false = free; true = blocked;
std::vector <CGObjectInstance*> visitableObjects; //pointers to objects hero can visit while being on this tile
};
struct DLL_EXPORT SheroName //name of starting hero
{

View File

@ -1325,7 +1325,7 @@ unsigned char CMapHandler::getHeroFrameNum(const unsigned char &dir, const bool
case 8:
return 11;
default:
return -1; //should never happen
throw std::exception("Something very wrong1.");
}
}
else //if(isMoving)
@ -1349,7 +1349,7 @@ unsigned char CMapHandler::getHeroFrameNum(const unsigned char &dir, const bool
case 8:
return 14;
default:
return -1; //should never happen
throw std::exception("Something very wrong2.");
}
}
}

View File

@ -3,6 +3,7 @@
#include <boost/thread/shared_mutex.hpp>
#include <boost/bind.hpp>
#include "CGameHandler.h"
#include "../CLua.h"
#include "../CGameState.h"
#include "../StartInfo.h"
#include "../map.h"
@ -19,6 +20,11 @@ boost::condition_variable cTurn;
boost::mutex mTurn;
boost::shared_mutex gsm;
double neighbours(int3 a, int3 b)
{
return std::sqrt( (double)(a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
try
@ -29,12 +35,126 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
c >> pom;
switch(pom)
{
case 100: //my interface end its turn
mTurn.lock();
makingTurn = false;
mTurn.unlock();
cTurn.notify_all();
break;
case 100: //my interface ended its turn
{
mTurn.lock();
makingTurn = false;
mTurn.unlock();
cTurn.notify_all();
break;
}
case 501://interface wants to move hero
{
int3 start, end;
si32 id;
c >> id >> start >> end;
int3 hmpos = end + int3(-1,0,0);
TerrainTile t = (hmpos.z) ? (gs->map->undergroungTerrain[hmpos.x][hmpos.y]) : (gs->map->terrain[hmpos.x][hmpos.y]);
CGHeroInstance *h = static_cast<CGHeroInstance *>(gs->map->objects[id]);
int cost = (double)h->getTileCost(t.tertype,t.malle,t.nuine) * neighbours(start,end);
TryMoveHero tmh;
tmh.id = id;
tmh.start = tmh.end = start;
tmh.end = end;
tmh.result = 0;
tmh.movePoints = h->movement;
if((h->getOwner() != gs->currentPlayer) || //not turn of that hero
(neighbours(start,end)>=1.5) || //tiles are not neighouring
(h->movement < cost) || //lack of movement points
(t.tertype == rock) || //rock
(!h->canWalkOnSea() && t.tertype == water) ||
(t.blocked && !t.visitable) ) //tile is blocked andnot visitable
goto fail;
//we start moving
bool blockvis = false;
tmh.movePoints = h->movement = (h->movement-cost); //take move points
BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
{
if(obj->blockVisit)
{
blockvis = true;
break;
}
}
if(blockvis)//interaction with blocking object (like resources)
{
gs->apply(&tmh);
sendToAllClients(&tmh);
BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
{
if (obj->blockVisit)
{
if(gs->checkFunc(obj->ID,"heroVisit")) //script function
gs->objscr[obj->ID]["heroVisit"]->onHeroVisit(obj,h->subID);
if(obj->state) //hard-coded function
obj->state->onHeroVisit(obj,h->subID);
}
}
break;
}
else //normal move
{
tmh.result = 1;
BOOST_FOREACH(CGObjectInstance *obj, ((start.z) ? (gs->map->undergroungTerrain[start.x][start.y]) : (gs->map->terrain[start.x][start.y])).visitableObjects)
{
//TODO: allow to handle this in script-languages
if(obj->state) //hard-coded function
obj->state->onHeroLeave(obj,h->subID);
}
//reveal fog of war
int heroSight = h->getSightDistance();
int xbeg = start.x - heroSight - 2;
if(xbeg < 0)
xbeg = 0;
int xend = start.x + heroSight + 2;
if(xend >= gs->map->width)
xend = gs->map->width;
int ybeg = start.y - heroSight - 2;
if(ybeg < 0)
ybeg = 0;
int yend = start.y + heroSight + 2;
if(yend >= gs->map->height)
yend = gs->map->height;
for(int xd=xbeg; xd<xend; ++xd) //revealing part of map around heroes
{
for(int yd=ybeg; yd<yend; ++yd)
{
int deltaX = (hmpos.x-xd)*(hmpos.x-xd);
int deltaY = (hmpos.y-yd)*(hmpos.y-yd);
if(deltaX+deltaY<h->getSightDistance()*h->getSightDistance())
{
if(gs->players[h->getOwner()].fogOfWarMap[xd][yd][hmpos.z] == 0)
{
tmh.fowRevealed.insert(int3(xd,yd,hmpos.z));
}
}
}
}
gs->apply(&tmh);
sendToAllClients(&tmh);
//call objects if they arevisited
BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
{
if(gs->checkFunc(obj->ID,"heroVisit")) //script function
gs->objscr[obj->ID]["heroVisit"]->onHeroVisit(obj,h->subID);
if(obj->state) //hard-coded function
obj->state->onHeroVisit(obj,h->subID);
}
}
break;
fail:
gs->apply(&tmh);
sendToAllClients(&tmh);
break;
}
default:
throw std::exception("Not supported client message!");
break;
@ -79,7 +199,7 @@ void CGameHandler::init(StartInfo *si, int Seed)
}
int lowestSpeed(CGHeroInstance * chi)
{
std::map<int,std::pair<CCreature*,int> >::iterator i = chi->army.slots.begin();
std::map<si32,std::pair<CCreature*,si32> >::iterator i = chi->army.slots.begin();
int ret = (*i++).second.first->speed;
for (;i!=chi->army.slots.end();i++)
{
@ -174,6 +294,7 @@ void CGameHandler::run()
{
if((i->second.towns.size()==0 && i->second.heroes.size()==0) || i->second.color<0) continue; //players has not towns/castle - loser
makingTurn = true;
gs->currentPlayer = i->first;
*connections[i->first] << ui16(100) << i->first;
//wait till turn is done
boost::unique_lock<boost::mutex> lock(mTurn);