1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Bugfixes and support for timed events.

This commit is contained in:
Michał W. Urbańczyk 2009-03-09 19:40:43 +00:00
parent 4653ca6b29
commit a7680d3957
11 changed files with 139 additions and 54 deletions

View File

@ -907,6 +907,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
std::pair<int,PlayerState> ins(scenarioOps->playerInfos[i].color,PlayerState());
ins.second.color=ins.first;
ins.second.serial=i;
ins.second.human = scenarioOps->playerInfos[i].human;
players.insert(ins);
}
/******************RESOURCES****************************************************/

View File

@ -50,6 +50,7 @@ struct DLL_EXPORT PlayerState
{
public:
ui8 color, serial;
ui8 human; //true if human controlled player, false for AI
ui32 currentSelection; //id of hero/town, 0xffffffff if none
std::vector<std::vector<std::vector<ui8> > > fogOfWarMap; //true - visible, false - hidden
std::vector<si32> resources;
@ -59,7 +60,7 @@ public:
PlayerState():color(-1),currentSelection(0xffffffff){};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & color & serial & currentSelection & fogOfWarMap & resources;
h & color & serial & human & currentSelection & fogOfWarMap & resources;
ui32 size;
if(h.saving) //write subids of available heroes

View File

@ -1049,9 +1049,11 @@ void TimeInterested::deactivate()
CPlayerInterface::CPlayerInterface(int Player, int serial)
{
LOCPLINT = this;
curint = NULL;
playerID=Player;
serialID=serial;
human=true;
castleInt = NULL;
adventureInt = NULL;
pim = new boost::recursive_mutex;
showingDialog = new CondSh<bool>(false);
@ -1079,7 +1081,6 @@ void CPlayerInterface::init(ICallback * CB)
{
cb = dynamic_cast<CCallback*>(CB);
adventureInt = new CAdvMapInt(playerID);
castleInt = NULL;
std::vector<const CGTownInstance*> tt = cb->getTownsInfo(false);
for(int i=0;i<tt.size();i++)
{
@ -1112,12 +1113,27 @@ void CPlayerInterface::yourTurn()
adventureInt->select(adventureInt->townList.items[0]);
adventureInt->activate();
timeHandler th;
th.getDif();
for(;makingTurn;) // main loop
{
updateWater();
pim->lock();
//if there are any waiting dialogs, show them
if(dialogs.size())
{
dialogs.front()->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
showingDialog->set(true);
curint->deactivate(); //dezaktywacja starego interfejsu
dialogs.front()->activate();
LOCPLINT->objsToBlit.push_back(dialogs.front());
dialogs.pop_front();
}
int tv = th.getDif();
std::list<TimeInterested*> hlp = timeinterested;
for (std::list<TimeInterested*>::iterator i=hlp.begin(); i != hlp.end();i++)
@ -2279,19 +2295,27 @@ void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<Compo
intComps.push_back(new SComponent(*components[i]));
showInfoDialog(text,intComps);
}
void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<SComponent*> & components)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
showingDialog->set(true);
curint->deactivate(); //dezaktywacja starego interfejsu
std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
CInfoWindow * temp = new CInfoWindow(text,playerID,32,components,pom);
temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
temp->activate();
LOCPLINT->objsToBlit.push_back(temp);
if(makingTurn && curint)
{
temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
showingDialog->set(true);
curint->deactivate(); //dezaktywacja starego interfejsu
temp->activate();
LOCPLINT->objsToBlit.push_back(temp);
}
else
{
dialogs.push_back(temp);
}
}
void CPlayerInterface::showYesNoDialog(std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool deactivateCur, bool DelComps)
{

View File

@ -451,6 +451,8 @@ public:
CCallback * cb;
const BattleAction *curAction;
std::list<CInfoWindow *> dialogs;
//GUI elements
std::list<ClickableL*> lclickable;
std::list<ClickableR*> rclickable;

View File

@ -102,7 +102,7 @@ void CClient::waitForMoveAndSend(int color)
try
{
BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
*serv << ui16(3002) << ba;
*serv << &MakeAction(ba);
return;
}HANDLE_EXCEPTION
tlog1 << "We should not be here!" << std::endl;
@ -113,17 +113,18 @@ void CClient::run()
while(1)
{
*serv >> pack;
tlog5 << "Received server message of type " << typeid(*pack).name() << std::endl;
CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
if(apply)
{
apply->applyOnClBefore(this,pack);
gs->apply(pack);
apply->applyOnClAfter(this,pack);
tlog5 << "Applied server message of type " << typeid(*pack).name() << std::endl;
tlog5 << "Message successfully applied!\n";
}
else
{
tlog1 << "Unknown server message. Type: " << pack->type << ". Typeinfo: " << typeid(*pack).name() << std::endl;
tlog5 << "Message cannot be applied, cannot find applier!\n";
}
delete pack;
pack = NULL;

View File

@ -472,7 +472,8 @@ struct NewTurn : public CPackForClient //101
struct Component : public CPack //2002 helper for object scrips informations
{
ui16 id, subtype; //ids: 0 - primskill; 1 - secskill; 2 - resource; 3 - creature; 4 - artifact; 5 - experience (sub==0 exp points; sub==1 levels)
enum {PRIM_SKILL,SEC_SKILL,RESOURCE,CREATURE,ARTIFACT,EXPERIENCE};
ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels)
si32 val; // + give; - take
si16 when; // 0 - now; +x - within x days; -x - per x days
@ -1008,7 +1009,7 @@ struct QueryReply : public CPackForServer
struct MakeAction : public CPackForServer
{
MakeAction(){};
MakeAction(const BattleAction &BA):ba(ba){};
MakeAction(const BattleAction &BA):ba(BA){};
BattleAction ba;
void applyGh(CGameHandler *gh);

28
map.cpp
View File

@ -567,6 +567,8 @@ Mapa::~Mapa()
}
delete [] terrain;
}
for(std::list<CMapEvent*>::iterator i = events.begin(); i != events.end(); i++)
delete *i;
}
CGHeroInstance * Mapa::getHero(int ID, int mode)
@ -1833,34 +1835,34 @@ void Mapa::readEvents( unsigned char * bufor, int &i )
int numberOfEvents = readNormalNr(bufor,i); i+=4;
for(int yyoo=0; yyoo<numberOfEvents; ++yyoo)
{
CMapEvent ne;
ne.name = std::string();
ne.message = std::string();
CMapEvent *ne = new CMapEvent();
ne->name = std::string();
ne->message = std::string();
int nameLen = readNormalNr(bufor,i); i+=4;
for(int qq=0; qq<nameLen; ++qq)
{
ne.name += bufor[i]; ++i;
ne->name += bufor[i]; ++i;
}
int messLen = readNormalNr(bufor,i); i+=4;
for(int qq=0; qq<messLen; ++qq)
{
ne.message +=bufor[i]; ++i;
ne->message +=bufor[i]; ++i;
}
ne.resources.resize(RESOURCE_QUANTITY);
ne->resources.resize(RESOURCE_QUANTITY);
for(int k=0; k < 7; k++)
{
ne.resources[k] = readNormalNr(bufor,i); i+=4;
ne->resources[k] = readNormalNr(bufor,i); i+=4;
}
ne.players = bufor[i]; ++i;
ne->players = bufor[i]; ++i;
if(version>AB)
{
ne.humanAffected = bufor[i]; ++i;
ne->humanAffected = bufor[i]; ++i;
}
else
ne.humanAffected = true;
ne.computerAffected = bufor[i]; ++i;
ne.firstOccurence = bufor[i]; ++i;
ne.nextOccurence = bufor[i]; ++i;
ne->humanAffected = true;
ne->computerAffected = bufor[i]; ++i;
ne->firstOccurence = bufor[i]; ++i;
ne->nextOccurence = bufor[i]; ++i;
i+=18;
events.push_back(ne);
}

23
map.h
View File

@ -53,23 +53,6 @@ public:
unsigned char player; //owner
unsigned char minLevel, maxLevel; //minimal and maximal level of creature in dwelling: <0, 6>
};
struct DLL_EXPORT Sresource
{
std::string resName; //name of this resource
int amount; //it can be greater and lesser than 0
};
struct DLL_EXPORT TimeEvent
{
std::string eventName;
std::string message;
std::vector<Sresource> decIncRes; //decreases / increases of resources
unsigned int whichPlayers; //which players are affected by this event (+1 - first, +2 - second, +4 - third, +8 - fourth etc.)
bool areHumansAffected;
bool areCompsAffected;
int firstAfterNDays; //how many days after appears this event
int nextAfterNDays; //how many days after the epperance before appaers this event
};
struct DLL_EXPORT TerrainTile
{
EterrainType tertype; // type of terrain
@ -197,6 +180,10 @@ public:
h & name & message & resources
& players & humanAffected & computerAffected & firstOccurence & nextOccurence;
}
bool operator<(const CMapEvent &b) const
{
return firstOccurence < b.firstOccurence;
}
};
class DLL_EXPORT CMapHeader
{
@ -297,7 +284,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
std::vector<ui8> allowedArtifact; //allowedArtifact[artifact_ID] - if the artifact is allowed
std::vector<ui8> allowedAbilities; //allowedAbilities[ability_ID] - if the ability is allowed
std::vector<ui8> allowedHeroes; //allowedHeroes[hero_ID] - if the hero is allowed
std::list<CMapEvent> events;
std::list<CMapEvent*> events;
int3 grailPos;
int grailRadious;

View File

@ -52,14 +52,15 @@ std::map<ui32, CFunctionList<void(ui32)> > callbacks; //question id => callback
class CBaseForGHApply
{
public:
virtual void applyOnGH(CGameHandler *gh, void *pack) const =0;
virtual void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0;
};
template <typename T> class CApplyOnGH : public CBaseForGHApply
{
public:
void applyOnGH(CGameHandler *gh, void *pack) const
void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const
{
T *ptr = static_cast<T*>(pack);
ptr->c = c;
ptr->applyGh(gh);
}
};
@ -495,22 +496,22 @@ void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
}
void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
CPackForServer *pack = NULL;
CPack *pack = NULL;
try
{
while(!end2)
{
c >> pack;
tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl;
CBaseForGHApply *apply = applier->apps[typeList.getTypeID(pack)];
if(apply)
{
pack->c = &c;
apply->applyOnGH(this,pack);
tlog5 << "Applied client message of type " << typeid(*pack).name() << std::endl;
apply->applyOnGH(this,&c,pack);
tlog5 << "Message successfully applied!\n";
}
else
{
tlog1 << "Unknown client message. Type: " << pack->type << ". Typeinfo: " << typeid(*pack).name() << std::endl;
tlog5 << "Message cannot be applied, cannot find applier!\n";
}
delete pack;
pack = NULL;
@ -638,6 +639,11 @@ void CGameHandler::init(StartInfo *si, int Seed)
states.addPlayer(i->first);
}
bool evntCmp(const CMapEvent *a, const CMapEvent *b)
{
return *a < *b;
}
void CGameHandler::newTurn()
{
tlog5 << "Turn " << gs->day+1 << std::endl;
@ -724,6 +730,10 @@ void CGameHandler::newTurn()
}
sendAndApply(&n);
tlog5 << "Info about turn " << n.day << "has been sent!" << std::endl;
handleTimeEvents();
//call objects
for(size_t i = 0; i<gs->map->objects.size(); i++)
if(gs->map->objects[i])
gs->map->objects[i]->newTurn();
@ -2382,4 +2392,59 @@ if(getSchoolLevel(h,s) < 3) /*not expert */ \
sendAndApply(&EndAction());
}
}
}
void CGameHandler::handleTimeEvents()
{
while(gs->map->events.size() && gs->map->events.front()->firstOccurence+1 == gs->day)
{
CMapEvent *ev = gs->map->events.front();
for(int player = 0; player < PLAYER_LIMIT; player++)
{
PlayerState *pinfo = gs->getPlayer(player);
if( pinfo //player exists
&& (ev->players & 1<<player) //event is enabled to this player
&& ((ev->computerAffected && !pinfo->human)
|| (ev->humanAffected && pinfo->human)
)
)
{
//give resources
SetResources sr;
sr.player = player;
sr.res = pinfo->resources;
//prepare dialog
InfoWindow iw;
iw.player = player;
iw.text << ev->message;
for (int i=0; i<ev->resources.size(); i++)
{
if(ev->resources[i]) //if resource is changed, we add it to the dialog
{
iw.components.push_back(Component(Component::RESOURCE,i,ev->resources[i],0));
sr.res[i] += ev->resources[i];
}
}
if (iw.components.size())
{
sendAndApply(&sr); //update player resources if changed
}
sendAndApply(&iw); //show dialog
}
} //PLAYERS LOOP
if(ev->nextOccurence)
{
ev->firstOccurence += ev->nextOccurence;
gs->map->events.sort(evntCmp);
}
else
{
delete ev;
gs->map->events.pop_front();
}
}
}

View File

@ -132,6 +132,7 @@ public:
void arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val );
void save(const std::string &fname);
void close();
void handleTimeEvents();
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -3,7 +3,7 @@
#define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
#define ERROR_AND_RETURN {if(c) *c << &SystemMessage("You don't own this object!"); \
#define ERROR_AND_RETURN {if(c) *c << &SystemMessage("You are not allowed to perform this action!"); \
tlog1<<"Player is not allowed to perform this action!\n"; \
return;}
#define ERROR_IF_NOT_OWNS(id) if(!PLAYER_OWNS(id)) ERROR_AND_RETURN
@ -117,13 +117,13 @@ void QueryReply::applyGh( CGameHandler *gh )
void MakeAction::applyGh( CGameHandler *gh )
{
if(gh->getPlayerAt(c) != GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner) ERROR_AND_RETURN;
if(gh->connections[GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner] != c) ERROR_AND_RETURN;
gh->makeBattleAction(ba);
}
void MakeCustomAction::applyGh( CGameHandler *gh )
{
if(gh->getPlayerAt(c) != GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner) ERROR_AND_RETURN;
if(gh->connections[GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner] != c) ERROR_AND_RETURN;
gh->makeCustomAction(ba);
}