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:
parent
4653ca6b29
commit
a7680d3957
@ -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****************************************************/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -451,6 +451,8 @@ public:
|
||||
CCallback * cb;
|
||||
const BattleAction *curAction;
|
||||
|
||||
std::list<CInfoWindow *> dialogs;
|
||||
|
||||
//GUI elements
|
||||
std::list<ClickableL*> lclickable;
|
||||
std::list<ClickableR*> rclickable;
|
||||
|
@ -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;
|
||||
|
@ -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
28
map.cpp
@ -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
23
map.h
@ -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;
|
||||
|
@ -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();
|
||||
@ -2383,3 +2393,58 @@ if(getSchoolLevel(h,s) < 3) /*not expert */ \
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user