mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
First part of support for victory & loss conditions.
Implemented and tested are victory: Defeat hero Capture town Defeat monster Flag dwellings Flag mines Lose: Loss hero Time expire ** Some others may work but not has been tested yet. I've added a new page in VCMI Status spreadsheet with status of various victory/loss conditions.
This commit is contained in:
parent
8447e58c39
commit
5279e2e9fc
@ -103,6 +103,7 @@ public:
|
||||
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
|
||||
virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
|
||||
virtual void playerBlocked(int reason){}; //reason: 0 - upcoming battle
|
||||
virtual void gameOver(ui8 player, bool victory){}; //player lost or won the game
|
||||
virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
|
||||
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
|
||||
|
||||
|
@ -169,6 +169,7 @@ int _tmain(int argc, _TCHAR* argv[])
|
||||
int main(int argc, char** argv)
|
||||
#endif
|
||||
{
|
||||
//Set environment vars to make window centered. Sometimes work, sometimes not. :/
|
||||
putenv("SDL_VIDEO_WINDOW_POS");
|
||||
putenv("SDL_VIDEO_CENTERED=1");
|
||||
|
||||
@ -504,6 +505,9 @@ static void listenForEvents()
|
||||
else if (ev->type == SDL_USEREVENT && ev->user.code == 2) //something want to quit to main menu
|
||||
{
|
||||
client->stop();
|
||||
delete client;
|
||||
client = NULL;
|
||||
|
||||
delete ev;
|
||||
|
||||
GH.curInt = CGP;
|
||||
|
@ -746,7 +746,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
|
||||
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
|
||||
CInfoWindow * temp = new CInfoWindow(text,playerID,0,components,pom,false);
|
||||
|
||||
if(makingTurn && GH.listInt.size())
|
||||
if(/*makingTurn && */GH.listInt.size())
|
||||
{
|
||||
CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
|
||||
showingDialog->set(true);
|
||||
@ -1590,6 +1590,26 @@ void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &h
|
||||
std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
|
||||
std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
|
||||
}
|
||||
|
||||
void CPlayerInterface::gameOver(ui8 player, bool victory )
|
||||
{
|
||||
if(player == playerID)
|
||||
{
|
||||
if(!victory)
|
||||
showInfoDialog(CGI->generaltexth->allTexts[95]);
|
||||
// else
|
||||
// showInfoDialog("Placeholder message: you won!");
|
||||
|
||||
waitWhileDialog();
|
||||
|
||||
//return to main menu
|
||||
SDL_Event event;
|
||||
event.type = SDL_USEREVENT;
|
||||
event.user.code = 2;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemOptions::setMusicVolume( int newVolume )
|
||||
{
|
||||
musicVolume = newVolume;
|
||||
|
@ -170,6 +170,7 @@ public:
|
||||
void centerView (int3 pos, int focusTime);
|
||||
void objectPropertyChanged(const SetObjectProperty * sop);
|
||||
void objectRemoved(const CGObjectInstance *obj);
|
||||
void gameOver(ui8 player, bool victory);
|
||||
void serialize(COSer<CSaveFile> &h, const int version); //saving
|
||||
void serialize(CISer<CLoadFile> &h, const int version); //loading
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "../hch/CLodHandler.h"
|
||||
#include "../hch/CTownHandler.h"
|
||||
#include "../hch/CHeroHandler.h"
|
||||
#include "../hch/CObjectHandler.h"
|
||||
#include <cmath>
|
||||
#include "Graphics.h"
|
||||
//#include <boost/thread.hpp>
|
||||
|
@ -153,7 +153,17 @@ void CClient::run()
|
||||
handlePack(pack);
|
||||
pack = NULL;
|
||||
}
|
||||
} HANDLE_EXCEPTION(tlog1 << "Lost connection to server, ending listening thread!\n");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
tlog3 << "Lost connection to server, ending listening thread!\n";
|
||||
tlog1 << e.what() << std::endl;
|
||||
if(!terminate) //rethrow (-> boom!) only if closing connection was unexpected
|
||||
{
|
||||
tlog1 << "Something wrong, lost connection while game is still ongoing...\n";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::stop()
|
||||
|
@ -628,6 +628,7 @@ void CGarrisonInt::deactivate()
|
||||
|
||||
CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, bool delComps)
|
||||
{
|
||||
slider = NULL;
|
||||
ID = -1;
|
||||
this->delComps = delComps;
|
||||
for(int i=0;i<Buttons.size();i++)
|
||||
|
@ -127,6 +127,12 @@ void ChangeObjPos::applyCl( CClient *cl )
|
||||
CGI->mh->printObject(obj);
|
||||
}
|
||||
|
||||
void PlayerEndsGame::applyCl( CClient *cl )
|
||||
{
|
||||
for(std::map<ui8, CGameInterface*>::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++)
|
||||
i->second->gameOver(player, victory);
|
||||
}
|
||||
|
||||
void RemoveObject::applyFirstCl( CClient *cl )
|
||||
{
|
||||
const CGObjectInstance *o = cl->getObj(id);
|
||||
|
@ -325,6 +325,10 @@
|
||||
RelativePath=".\CHeroWindow.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CKingdomInterface.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Client.cpp"
|
||||
>
|
||||
@ -471,6 +475,10 @@
|
||||
RelativePath=".\CHeroWindow.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CKingdomInterface.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Client.h"
|
||||
>
|
||||
|
2
global.h
2
global.h
@ -20,7 +20,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
|
||||
#define THC
|
||||
#endif
|
||||
|
||||
#define NAME_VER ("VCMI 0.75")
|
||||
#define NAME_VER ("VCMI 0.75b")
|
||||
extern std::string NAME; //full name
|
||||
extern std::string NAME_AFFIX; //client / server
|
||||
#define CONSOLE_LOGGING_LEVEL 5
|
||||
|
@ -1234,6 +1234,17 @@ void CGHeroInstance::recreateArtBonuses()
|
||||
}
|
||||
}
|
||||
|
||||
bool CGHeroInstance::hasArt( ui32 aid ) const
|
||||
{
|
||||
if(vstd::contains(artifacts, aid))
|
||||
return true;
|
||||
for(std::map<ui16,ui32>::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++)
|
||||
if(i->second == aid)
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CGDwelling::initObj()
|
||||
{
|
||||
switch(ID)
|
||||
|
@ -298,10 +298,12 @@ public:
|
||||
int getPrimSkillLevel(int id) const;
|
||||
ui8 getSecSkillLevel(const int & ID) const; //0 - no skill
|
||||
int maxMovePoints(bool onLand) const;
|
||||
|
||||
ui32 getArtAtPos(ui16 pos) const; //-1 - no artifact
|
||||
const CArtifact * getArt(int pos) const;
|
||||
si32 getArtPos(int aid) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
|
||||
void giveArtifact (ui32 aid);
|
||||
bool hasArt(ui32 aid) const; //checks if hero possess artifact of given id (either in backack or worn)
|
||||
|
||||
int getSpellSecLevel(int spell) const; //returns level of secondary ability (fire, water, earth, air magic) known to this hero and applicable to given spell; -1 if error
|
||||
static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
|
||||
double getHeroStrength() const;
|
||||
@ -316,7 +318,9 @@ public:
|
||||
void initHero();
|
||||
void initHero(int SUBID);
|
||||
void recreateArtBonuses();
|
||||
void giveArtifact (ui32 aid);
|
||||
void initHeroDefInfo();
|
||||
|
||||
CGHeroInstance();
|
||||
virtual ~CGHeroInstance();
|
||||
|
||||
@ -605,7 +609,7 @@ public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this) & static_cast<CQuest&>(*this);
|
||||
h & rewardType & rID & rVal & textOption & seerName;
|
||||
h & rewardType & rID & rVal & textOption;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -966,12 +966,24 @@ CGHeroInstance *CGameState::getHero(int objid)
|
||||
return NULL;
|
||||
return static_cast<CGHeroInstance *>(map->objects[objid]);
|
||||
}
|
||||
|
||||
const CGHeroInstance * CGameState::getHero( int objid ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getHero(objid);
|
||||
}
|
||||
|
||||
CGTownInstance *CGameState::getTown(int objid)
|
||||
{
|
||||
if(objid<0 || objid>=map->objects.size())
|
||||
return NULL;
|
||||
return static_cast<CGTownInstance *>(map->objects[objid]);
|
||||
}
|
||||
|
||||
const CGTownInstance * CGameState::getTown( int objid ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getTown(objid);
|
||||
}
|
||||
|
||||
std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj)
|
||||
{
|
||||
switch(obj->ID)
|
||||
@ -1162,6 +1174,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
|
||||
if(cur->ID==TOWNI_TYPE) //town - set def
|
||||
{
|
||||
CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur);
|
||||
t->town = &VLC->townh->towns[t->subID];
|
||||
if(t->hasCapitol())
|
||||
t->defInfo = capitols[t->subID];
|
||||
else if(t->hasFort())
|
||||
@ -1937,6 +1950,11 @@ PlayerState * CGameState::getPlayer( ui8 color )
|
||||
}
|
||||
}
|
||||
|
||||
const PlayerState * CGameState::getPlayer( ui8 color ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getPlayer(color);
|
||||
}
|
||||
|
||||
bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret)
|
||||
{
|
||||
if(!map->isInTheMap(src) || !map->isInTheMap(dest)) //check input
|
||||
@ -2916,6 +2934,191 @@ bool CGameState::battleCanShoot(int ID, int dest)
|
||||
return false;
|
||||
}
|
||||
|
||||
int CGameState::victoryCheck( ui8 player ) const
|
||||
{
|
||||
const PlayerState *p = getPlayer(player);
|
||||
if(map->victoryCondition.condition == winStandard || map->victoryCondition.allowNormalVictory)
|
||||
if(player == checkForStandardWin())
|
||||
return -1;
|
||||
|
||||
if(p->human || map->victoryCondition.appliesToAI)
|
||||
{
|
||||
switch(map->victoryCondition.condition)
|
||||
{
|
||||
case artifact:
|
||||
//check if any hero has winning artifact
|
||||
for(size_t i = 0; i < p->heroes.size(); i++)
|
||||
if(p->heroes[i]->hasArt(map->victoryCondition.ID))
|
||||
return 1;
|
||||
|
||||
break;
|
||||
|
||||
case gatherTroop:
|
||||
{
|
||||
//check if in players armies there is enough creatures
|
||||
int total = 0; //creature counter
|
||||
for(size_t i = 0; i < map->objects.size(); i++)
|
||||
{
|
||||
const CArmedInstance *ai = NULL;
|
||||
if(map->objects[i]
|
||||
&& map->objects[i]->tempOwner //object controlled by player
|
||||
&& (ai = dynamic_cast<const CArmedInstance*>(map->objects[i]))) //contains army
|
||||
{
|
||||
for(TSlots::const_iterator i=ai->army.slots.begin(); i!=ai->army.slots.end(); ++i) //iterate through army
|
||||
if(i->second.first == map->victoryCondition.ID) //it's searched creature
|
||||
total += i->second.second;
|
||||
}
|
||||
}
|
||||
|
||||
if(total >= map->victoryCondition.count)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case gatherResource:
|
||||
if(p->resources[map->victoryCondition.ID] >= map->victoryCondition.count)
|
||||
return 1;
|
||||
|
||||
break;
|
||||
|
||||
case buildCity:
|
||||
for(size_t i = 0; i < map->towns.size(); i++)
|
||||
if(map->towns[i]->pos == map->victoryCondition.pos
|
||||
&& map->towns[i]->tempOwner == player
|
||||
&& map->towns[i]->hallLevel() >= map->victoryCondition.ID)
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case buildGrail:
|
||||
for(size_t i = 0; i < map->towns.size(); i++)
|
||||
if(map->towns[i]->pos == map->victoryCondition.pos
|
||||
&& map->towns[i]->tempOwner == player
|
||||
&& vstd::contains(map->towns[i]->builtBuildings, 26))
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case beatHero:
|
||||
if(map->victoryCondition.obj->tempOwner >= PLAYER_LIMIT) //target hero not present on map
|
||||
return 1;
|
||||
break;
|
||||
case captureCity:
|
||||
{
|
||||
if(map->victoryCondition.obj->tempOwner == player)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case beatMonster:
|
||||
if(!map->objects[map->victoryCondition.obj->id]) //target monster not present on map
|
||||
return 1;
|
||||
break;
|
||||
case takeDwellings:
|
||||
for(size_t i = 0; i < map->objects.size(); i++)
|
||||
{
|
||||
if(map->objects[i] && map->objects[i]->tempOwner != player) //check not flagged objs
|
||||
{
|
||||
switch(map->objects[i]->ID)
|
||||
{
|
||||
case 17: case 18: case 19: case 20: //dwellings
|
||||
case 216: case 217: case 218:
|
||||
return 0; //found not flagged dwelling - player not won
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
case takeMines:
|
||||
for(size_t i = 0; i < map->objects.size(); i++)
|
||||
{
|
||||
if(map->objects[i] && map->objects[i]->tempOwner != player) //check not flagged objs
|
||||
{
|
||||
switch(map->objects[i]->ID)
|
||||
{
|
||||
case 53: case 220:
|
||||
return 0; //found not flagged mine - player not won
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
case transportItem:
|
||||
//TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ui8 CGameState::checkForStandardWin() const
|
||||
{
|
||||
//std victory condition is:
|
||||
//all enemies lost
|
||||
ui8 supposedWinner = 255, winnerTeam = 255;
|
||||
for(std::map<ui8,PlayerState>::const_iterator i = players.begin(); i != players.end(); i++)
|
||||
{
|
||||
if(i->second.status == PlayerState::INGAME)
|
||||
{
|
||||
if(supposedWinner == 255)
|
||||
{
|
||||
//first player remaining ingame - candidate for victory
|
||||
supposedWinner = i->second.color;
|
||||
winnerTeam = map->players[supposedWinner].team;
|
||||
}
|
||||
else if(winnerTeam != map->players[i->second.color].team)
|
||||
{
|
||||
//current candidate has enemy remaining in game -> no vicotry
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return supposedWinner;
|
||||
}
|
||||
|
||||
bool CGameState::checkForStandardLoss( ui8 player ) const
|
||||
{
|
||||
//std loss condition is: player lost all towns and heroes
|
||||
const PlayerState &p = *getPlayer(player);
|
||||
return p.heroes.size() || p.towns.size();
|
||||
}
|
||||
|
||||
int CGameState::lossCheck( ui8 player ) const
|
||||
{
|
||||
const PlayerState *p = getPlayer(player);
|
||||
if(map->lossCondition.typeOfLossCon == lossStandard)
|
||||
if(checkForStandardLoss(player))
|
||||
return -1;
|
||||
|
||||
if(p->human) //special loss condition applies only to human player
|
||||
{
|
||||
switch(map->lossCondition.typeOfLossCon)
|
||||
{
|
||||
case lossCastle:
|
||||
{
|
||||
const CGTownInstance *t = dynamic_cast<const CGTownInstance *>(map->lossCondition.obj);
|
||||
assert(t);
|
||||
if(t->tempOwner != player)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case lossHero:
|
||||
{
|
||||
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(map->lossCondition.obj);
|
||||
assert(h);
|
||||
if(h->tempOwner != player)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case timeExpires:
|
||||
if(map->lossCondition.timeLimit < day)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const CStack * BattleInfo::getNextStack() const
|
||||
{
|
||||
std::vector<const CStack *> hlp;
|
||||
@ -3205,7 +3408,7 @@ CMP_stack::CMP_stack( int Phase /*= 1*/, int Turn )
|
||||
}
|
||||
|
||||
PlayerState::PlayerState()
|
||||
: color(-1), currentSelection(0xffffffff)
|
||||
: color(-1), currentSelection(0xffffffff), status(INGAME), daysWithoutCastle(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
126
lib/CGameState.h
126
lib/CGameState.h
@ -60,6 +60,7 @@ namespace boost
|
||||
struct DLL_EXPORT PlayerState
|
||||
{
|
||||
public:
|
||||
enum EStatus {INGAME, LOSER, WINNER};
|
||||
ui8 color, serial;
|
||||
ui8 human; //true if human controlled player, false for AI
|
||||
ui32 currentSelection; //id of hero/town, 0xffffffff if none
|
||||
@ -70,42 +71,46 @@ public:
|
||||
std::vector<CGHeroInstance *> availableHeroes; //heroes available in taverns
|
||||
std::vector<CGDwelling *> dwellings; //used for town growth
|
||||
|
||||
ui8 status; //0 - in game, 1 - loser, 2 - winner <- uses EStatus enum
|
||||
ui8 daysWithoutCastle;
|
||||
|
||||
PlayerState();
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & color & serial & human & currentSelection & fogOfWarMap & resources;
|
||||
h & color & serial & human & currentSelection & fogOfWarMap & resources & status;
|
||||
h & heroes & towns & availableHeroes & dwellings & status & daysWithoutCastle;
|
||||
|
||||
ui32 size;
|
||||
if(h.saving) //write subids of available heroes
|
||||
{
|
||||
size = availableHeroes.size();
|
||||
h & size;
|
||||
for(size_t i=0; i < size; i++)
|
||||
{
|
||||
if(availableHeroes[i])
|
||||
{
|
||||
h & availableHeroes[i]->subID;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui32 none = 0xffffffff;
|
||||
h & none;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui32 hid;
|
||||
h & size;
|
||||
for(size_t i=0; i < size; i++)
|
||||
{
|
||||
//fill availableHeroes with dummy hero instances, holding subids
|
||||
h & hid;
|
||||
availableHeroes.push_back(new CGHeroInstance);
|
||||
availableHeroes[availableHeroes.size()-1]->subID = hid;
|
||||
}
|
||||
}
|
||||
// ui32 size;
|
||||
// if(h.saving) //write subids of available heroes
|
||||
// {
|
||||
// size = availableHeroes.size();
|
||||
// h & size;
|
||||
// for(size_t i=0; i < size; i++)
|
||||
// {
|
||||
// if(availableHeroes[i])
|
||||
// {
|
||||
// h & availableHeroes[i]->subID;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ui32 none = 0xffffffff;
|
||||
// h & none;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ui32 hid;
|
||||
// h & size;
|
||||
// for(size_t i=0; i < size; i++)
|
||||
// {
|
||||
// //fill availableHeroes with dummy hero instances, holding subids
|
||||
// h & hid;
|
||||
// availableHeroes.push_back(new CGHeroInstance);
|
||||
// availableHeroes[availableHeroes.size()-1]->subID = hid;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
@ -334,7 +339,7 @@ public:
|
||||
BattleInfo *curB; //current battle
|
||||
ui32 day; //total number of days in game
|
||||
Mapa * map;
|
||||
std::map<ui8,PlayerState> players; //ID <-> player state
|
||||
std::map<ui8, PlayerState> players; //ID <-> player state
|
||||
std::map<int, CGDefInfo*> villages, forts, capitols; //def-info for town graphics
|
||||
std::vector<ui32> resVals; //default values of resources in gold
|
||||
|
||||
@ -354,6 +359,7 @@ public:
|
||||
boost::shared_mutex *mx;
|
||||
|
||||
PlayerState *getPlayer(ui8 color);
|
||||
const PlayerState *getPlayer(ui8 color) const;
|
||||
void init(StartInfo * si, Mapa * map, int Seed);
|
||||
void loadTownDInfos();
|
||||
void randomizeObject(CGObjectInstance *cur);
|
||||
@ -362,6 +368,8 @@ public:
|
||||
void apply(CPack *pack);
|
||||
CGHeroInstance *getHero(int objid);
|
||||
CGTownInstance *getTown(int objid);
|
||||
const CGHeroInstance *getHero(int objid) const;
|
||||
const CGTownInstance *getTown(int objid) const;
|
||||
bool battleMoveCreatureStack(int ID, int dest);
|
||||
bool battleAttackCreatureStack(int ID, int dest);
|
||||
bool battleShootCreatureStack(int ID, int dest);
|
||||
@ -379,6 +387,10 @@ public:
|
||||
bool checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst) const; //check if src tile is visitable from dst tile
|
||||
bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
|
||||
void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1); //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or NULL if path does not exists
|
||||
int victoryCheck(ui8 player) const; //checks if given player is winner; -1 if std victory, 1 if special victory, 0 else
|
||||
int lossCheck(ui8 player) const; //checks if given player is loser; -1 if std loss, 1 if special, 0 else
|
||||
ui8 checkForStandardWin() const; //returns color of player that accomplished standard victory conditions or 255 if no winner
|
||||
bool checkForStandardLoss(ui8 player) const; //checks if given player lost the game
|
||||
|
||||
bool isVisible(int3 pos, int player);
|
||||
bool isVisible(const CGObjectInstance *obj, int player);
|
||||
@ -395,31 +407,31 @@ public:
|
||||
{
|
||||
loadTownDInfos();
|
||||
|
||||
//recreating towns/heroes vectors in players entries
|
||||
for(int i=0; i<map->towns.size(); i++)
|
||||
if(map->towns[i]->tempOwner < PLAYER_LIMIT)
|
||||
getPlayer(map->towns[i]->tempOwner)->towns.push_back(map->towns[i]);
|
||||
for(int i=0; i<map->heroes.size(); i++)
|
||||
if(map->heroes[i]->tempOwner < PLAYER_LIMIT)
|
||||
getPlayer(map->heroes[i]->tempOwner)->heroes.push_back(map->heroes[i]);
|
||||
//recreating available heroes
|
||||
for(std::map<ui8,PlayerState>::iterator i=players.begin(); i!=players.end(); i++)
|
||||
{
|
||||
for(size_t j=0; j < i->second.availableHeroes.size(); j++)
|
||||
{
|
||||
ui32 hlp = i->second.availableHeroes[j]->subID;
|
||||
delete i->second.availableHeroes[j];
|
||||
if(hlp != 0xffffffff)
|
||||
{
|
||||
assert(vstd::contains(hpool.heroesPool, hlp));
|
||||
i->second.availableHeroes[j] = hpool.heroesPool[hlp];
|
||||
}
|
||||
else
|
||||
{
|
||||
i->second.availableHeroes[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// //recreating towns/heroes vectors in players entries
|
||||
// for(int i=0; i<map->towns.size(); i++)
|
||||
// if(map->towns[i]->tempOwner < PLAYER_LIMIT)
|
||||
// getPlayer(map->towns[i]->tempOwner)->towns.push_back(map->towns[i]);
|
||||
// for(int i=0; i<map->heroes.size(); i++)
|
||||
// if(map->heroes[i]->tempOwner < PLAYER_LIMIT)
|
||||
// getPlayer(map->heroes[i]->tempOwner)->heroes.push_back(map->heroes[i]);
|
||||
// //recreating available heroes
|
||||
// for(std::map<ui8,PlayerState>::iterator i=players.begin(); i!=players.end(); i++)
|
||||
// {
|
||||
// for(size_t j=0; j < i->second.availableHeroes.size(); j++)
|
||||
// {
|
||||
// ui32 hlp = i->second.availableHeroes[j]->subID;
|
||||
// delete i->second.availableHeroes[j];
|
||||
// if(hlp != 0xffffffff)
|
||||
// {
|
||||
// assert(vstd::contains(hpool.heroesPool, hlp));
|
||||
// i->second.availableHeroes[j] = hpool.heroesPool[hlp];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// i->second.availableHeroes[j] = NULL;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,22 +147,40 @@ CConnection::CConnection(boost::asio::basic_socket_acceptor<boost::asio::ip::tcp
|
||||
int CConnection::write(const void * data, unsigned size)
|
||||
{
|
||||
//LOG("Sending " << size << " byte(s) of data" <<std::endl);
|
||||
int ret;
|
||||
ret = asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size)));
|
||||
return ret;
|
||||
try
|
||||
{
|
||||
int ret;
|
||||
ret = asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size)));
|
||||
return ret;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//connection has been lost
|
||||
connected = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
int CConnection::read(void * data, unsigned size)
|
||||
{
|
||||
//LOG("Receiving " << size << " byte(s) of data" <<std::endl);
|
||||
int ret = asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size)));
|
||||
return ret;
|
||||
try
|
||||
{
|
||||
int ret = asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size)));
|
||||
return ret;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//connection has been lost
|
||||
connected = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
CConnection::~CConnection(void)
|
||||
{
|
||||
close();
|
||||
delete io_service;
|
||||
delete wmx;
|
||||
delete rmx;
|
||||
delete io_service;
|
||||
delete wmx;
|
||||
delete rmx;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@ -205,6 +223,11 @@ void CConnection::setGS( CGameState *state )
|
||||
gs = state;
|
||||
}
|
||||
|
||||
bool CConnection::isOpen() const
|
||||
{
|
||||
return socket && connected;
|
||||
}
|
||||
|
||||
CSaveFile::CSaveFile( const std::string &fname )
|
||||
:sfile(new std::ofstream(fname.c_str(),std::ios::binary))
|
||||
{
|
||||
|
@ -11,16 +11,17 @@
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/equal_to.hpp>
|
||||
#include <boost/mpl/int.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
const ui32 version = 714;
|
||||
const ui32 version = 716;
|
||||
class CConnection;
|
||||
class CGObjectInstance;
|
||||
class CGameState;
|
||||
@ -542,11 +543,11 @@ public:
|
||||
template <typename T>
|
||||
void loadSerializable(T &data)
|
||||
{
|
||||
////that const cast would be evil because it allows to implicitly overwrite const objects when deserializing
|
||||
//typedef typename boost::remove_const<T>::type nonConstT;
|
||||
//nonConstT &hlp = const_cast<nonConstT&>(data);
|
||||
//hlp.serialize(*this,myVersion);
|
||||
data.serialize(*this,myVersion);
|
||||
////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
|
||||
typedef typename boost::remove_const<T>::type nonConstT;
|
||||
nonConstT &hlp = const_cast<nonConstT&>(data);
|
||||
hlp.serialize(*this,myVersion);
|
||||
//data.serialize(*this,myVersion);
|
||||
}
|
||||
template <typename T>
|
||||
void loadArray(T &data)
|
||||
@ -587,7 +588,7 @@ public:
|
||||
This()->loadPointerHlp(tid, data);
|
||||
|
||||
if(smartPointerSerialization && i == loadedPointers.end())
|
||||
loadedPointers[pid] = data; //add loaded pointer to our lookup map
|
||||
loadedPointers[pid] = (void*)data; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
|
||||
}
|
||||
|
||||
//that part of ptr deserialization was extracted to allow customization of its behavior in derived classes
|
||||
@ -597,7 +598,8 @@ public:
|
||||
if(!tid)
|
||||
{
|
||||
typedef typename boost::remove_pointer<T>::type npT;
|
||||
data = new npT;
|
||||
typedef typename boost::remove_const<npT>::type ncpT;
|
||||
data = new ncpT;
|
||||
*this >> *data;
|
||||
}
|
||||
else
|
||||
@ -723,8 +725,8 @@ public:
|
||||
std::string Name); //use immediately after accepting connection into socket
|
||||
int write(const void * data, unsigned size);
|
||||
int read(void * data, unsigned size);
|
||||
int readLine(void * data, unsigned maxSize);
|
||||
void close();
|
||||
bool isOpen() const;
|
||||
template<class T>
|
||||
CConnection &operator&(const T&);
|
||||
~CConnection(void);
|
||||
|
@ -388,6 +388,26 @@ struct ChangeObjPos : public CPackForClient //116
|
||||
}
|
||||
};
|
||||
|
||||
struct PlayerEndsGame : public CPackForClient //117
|
||||
{
|
||||
PlayerEndsGame()
|
||||
{
|
||||
type = 117;
|
||||
}
|
||||
|
||||
void applyCl(CClient *cl);
|
||||
DLL_EXPORT void applyGs(CGameState *gs);
|
||||
|
||||
ui8 player;
|
||||
ui8 victory;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & player & victory;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct RemoveObject : public CPackForClient //500
|
||||
{
|
||||
RemoveObject(){type = 500;};
|
||||
|
@ -219,6 +219,12 @@ DLL_EXPORT void ChangeObjPos::applyGs( CGameState *gs )
|
||||
gs->map->addBlockVisTiles(obj);
|
||||
}
|
||||
|
||||
DLL_EXPORT void PlayerEndsGame::applyGs( CGameState *gs )
|
||||
{
|
||||
PlayerState *p = gs->getPlayer(player);
|
||||
p->status = victory ? 2 : 1;
|
||||
}
|
||||
|
||||
DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
|
||||
{
|
||||
CGObjectInstance *obj = gs->map->objects[id];
|
||||
@ -230,6 +236,8 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
|
||||
int player = h->tempOwner;
|
||||
nitr = std::find(gs->getPlayer(player)->heroes.begin(), gs->getPlayer(player)->heroes.end(), h);
|
||||
gs->getPlayer(player)->heroes.erase(nitr);
|
||||
h->tempOwner = 255; //no one owns beaten hero
|
||||
|
||||
if(h->visitedTown)
|
||||
{
|
||||
if(h->inTownGarrison)
|
||||
|
@ -79,6 +79,7 @@ void registerTypes2(Serializer &s)
|
||||
s.template registerType<SetAvailableHeroes>();
|
||||
s.template registerType<GiveBonus>();
|
||||
s.template registerType<ChangeObjPos>();
|
||||
s.template registerType<PlayerEndsGame>();
|
||||
s.template registerType<RemoveObject>();
|
||||
s.template registerType<TryMoveHero>();
|
||||
s.template registerType<SetGarrisons>();
|
||||
|
53
lib/map.cpp
53
lib/map.cpp
@ -8,6 +8,7 @@
|
||||
#include <boost/crc.hpp>
|
||||
#include "../hch/CLodHandler.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* map.cpp, part of VCMI engine
|
||||
@ -353,6 +354,7 @@ void CMapHeader::loadPlayerInfo( int &pom, const unsigned char * bufor, int &i )
|
||||
|
||||
void CMapHeader::loadViCLossConditions( const unsigned char * bufor, int &i)
|
||||
{
|
||||
victoryCondition.obj = NULL;
|
||||
victoryCondition.condition = (EvictoryConditions)bufor[i++];
|
||||
if (victoryCondition.condition != winStandard) //specific victory conditions
|
||||
{
|
||||
@ -367,8 +369,8 @@ void CMapHeader::loadViCLossConditions( const unsigned char * bufor, int &i)
|
||||
}
|
||||
case gatherTroop:
|
||||
{
|
||||
int temp1 = bufor[i+2];
|
||||
int temp2 = bufor[i+3];
|
||||
// int temp1 = bufor[i+2];
|
||||
// int temp2 = bufor[i+3];
|
||||
victoryCondition.ID = bufor[i+2];
|
||||
victoryCondition.count = readNormalNr(bufor, i+(version==RoE ? 3 : 4));
|
||||
nr=(version==RoE ? 5 : 6);
|
||||
@ -438,17 +440,11 @@ void CMapHeader::loadViCLossConditions( const unsigned char * bufor, int &i)
|
||||
switch (lossCondition.typeOfLossCon) //read loss conditions
|
||||
{
|
||||
case lossCastle:
|
||||
{
|
||||
lossCondition.castlePos.x=bufor[i++];
|
||||
lossCondition.castlePos.y=bufor[i++];
|
||||
lossCondition.castlePos.z=bufor[i++];
|
||||
break;
|
||||
}
|
||||
case lossHero:
|
||||
{
|
||||
lossCondition.heroPos.x=bufor[i++];
|
||||
lossCondition.heroPos.y=bufor[i++];
|
||||
lossCondition.heroPos.z=bufor[i++];
|
||||
lossCondition.pos.x=bufor[i++];
|
||||
lossCondition.pos.y=bufor[i++];
|
||||
lossCondition.pos.z=bufor[i++];
|
||||
break;
|
||||
}
|
||||
case timeExpires:
|
||||
@ -500,6 +496,9 @@ void Mapa::initFromBytes(const unsigned char * bufor)
|
||||
addBlockVisTiles(objects[f]);
|
||||
}
|
||||
tlog0<<"\tCalculating blocked/visitable tiles: "<<th.getDif()<<std::endl;
|
||||
|
||||
checkForObjectives();
|
||||
tlog0 << "\tMap initialization done!" << std::endl;
|
||||
}
|
||||
void Mapa::removeBlockVisTiles(CGObjectInstance * obj, bool total)
|
||||
{
|
||||
@ -1402,6 +1401,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
|
||||
pos.x = bufor[i++];
|
||||
pos.y = bufor[i++];
|
||||
pos.z = bufor[i++];
|
||||
|
||||
int defnum = readNormalNr(bufor,i, 4); i+=4;
|
||||
|
||||
CGDefInfo * defInfo = defy[defnum];
|
||||
@ -2109,6 +2109,23 @@ bool Mapa::isWaterTile(const int3 &pos) const
|
||||
return isInTheMap(pos) && getTile(pos).tertype == TerrainTile::water;
|
||||
}
|
||||
|
||||
void Mapa::checkForObjectives()
|
||||
{
|
||||
if(isInTheMap(victoryCondition.pos))
|
||||
{
|
||||
const std::vector <CGObjectInstance*> &objs = getTile(victoryCondition.pos).visitableObjects;
|
||||
assert(objs.size());
|
||||
victoryCondition.obj = objs.front();
|
||||
}
|
||||
|
||||
if(isInTheMap(lossCondition.pos))
|
||||
{
|
||||
const std::vector <CGObjectInstance*> &objs = getTile(lossCondition.pos).visitableObjects;
|
||||
assert(objs.size());
|
||||
lossCondition.obj = objs.front();
|
||||
}
|
||||
}
|
||||
|
||||
void CMapInfo::countPlayers()
|
||||
{
|
||||
playerAmnt = humenPlayers = 0;
|
||||
@ -2143,3 +2160,17 @@ void CMapInfo::init(const std::string &fname, const unsigned char *map )
|
||||
initFromMemory(map, i);
|
||||
countPlayers();
|
||||
}
|
||||
|
||||
LossCondition::LossCondition()
|
||||
{
|
||||
obj = NULL;
|
||||
timeLimit = -1;
|
||||
pos = int3(-1,-1,-1);
|
||||
}
|
||||
|
||||
CVictoryCondition::CVictoryCondition()
|
||||
{
|
||||
pos = int3(-1,-1,-1);
|
||||
obj = NULL;
|
||||
ID = allowNormalVictory = appliesToAI = count = 0;
|
||||
}
|
19
lib/map.h
19
lib/map.h
@ -137,14 +137,19 @@ struct DLL_EXPORT PlayerInfo
|
||||
struct DLL_EXPORT LossCondition
|
||||
{
|
||||
ElossCon typeOfLossCon;
|
||||
int3 castlePos;
|
||||
int3 heroPos;
|
||||
int timeLimit; // in days
|
||||
|
||||
int3 pos;
|
||||
|
||||
si32 timeLimit; // in days; -1 if not used
|
||||
const CGObjectInstance *obj; //set during map parsing: hero/town (depending on typeOfLossCon); NULL if not used
|
||||
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & typeOfLossCon & castlePos & heroPos & timeLimit;
|
||||
h & typeOfLossCon & pos & timeLimit & obj;
|
||||
}
|
||||
|
||||
LossCondition();
|
||||
};
|
||||
struct DLL_EXPORT CVictoryCondition
|
||||
{
|
||||
@ -155,10 +160,13 @@ struct DLL_EXPORT CVictoryCondition
|
||||
ui32 ID; //artifact ID (0); monster ID (1); resource ID (2); needed fort level in upgraded town (3); artifact ID (8)
|
||||
ui32 count; //needed count for creatures (1) / resource (2); upgraded town hall level (3);
|
||||
|
||||
const CGObjectInstance *obj; //object of specific monster / city / hero instance (NULL if not used); set during map parsing
|
||||
|
||||
CVictoryCondition();
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & condition & allowNormalVictory & appliesToAI & pos & ID & count;
|
||||
h & condition & allowNormalVictory & appliesToAI & pos & ID & count & obj;
|
||||
}
|
||||
};
|
||||
|
||||
@ -329,6 +337,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
|
||||
void loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int &i, int subid);
|
||||
int loadSeerHut( const unsigned char * bufor, int i, CGObjectInstance *& nobj);
|
||||
|
||||
void checkForObjectives();
|
||||
|
||||
void addBlockVisTiles(CGObjectInstance * obj);
|
||||
void removeBlockVisTiles(CGObjectInstance * obj, bool total=false);
|
||||
|
@ -491,6 +491,10 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
||||
sg.garrs[bEndArmy2->id] = takeCasualties(bEndArmy2->tempOwner, bEndArmy2->army, gs->curB);
|
||||
sendAndApply(&sg);
|
||||
|
||||
ui8 sides[2];
|
||||
sides[0] = gs->curB->side1;
|
||||
sides[1] = gs->curB->side2;
|
||||
|
||||
//end battle, remove all info, free memory
|
||||
giveExp(*battleResult.data);
|
||||
sendAndApply(battleResult.data);
|
||||
@ -524,14 +528,17 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
||||
|
||||
// Necromancy if applicable.
|
||||
const CGHeroInstance *winnerHero = battleResult.data->winner != 0 ? hero2 : hero1;
|
||||
if (winnerHero) {
|
||||
if (winnerHero)
|
||||
{
|
||||
std::pair<ui32, si32> raisedStack = winnerHero->calculateNecromancy(*battleResult.data);
|
||||
|
||||
// Give raised units to winner and show dialog, if any were raised.
|
||||
if (raisedStack.first != -1) {
|
||||
if (raisedStack.first != -1)
|
||||
{
|
||||
int slot = winnerHero->army.getSlotFor(raisedStack.first);
|
||||
|
||||
if (slot != -1) {
|
||||
if (slot != -1)
|
||||
{
|
||||
SetGarrisons sg;
|
||||
|
||||
sg.garrs[winnerHero->id] = winnerHero->army;
|
||||
@ -545,6 +552,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
||||
}
|
||||
}
|
||||
|
||||
winLoseHandle(1<<sides[0] | 1<<sides[1]); //handle victory/loss of engaged players
|
||||
delete battleResult.data;
|
||||
}
|
||||
|
||||
@ -602,7 +610,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
|
||||
CPack *pack = NULL;
|
||||
try
|
||||
{
|
||||
while(!end2)
|
||||
while(1)//server should never shut connection first //was: while(!end2)
|
||||
{
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(*c.rmx);
|
||||
@ -640,11 +648,12 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
|
||||
}
|
||||
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
|
||||
{
|
||||
assert(!c.connected); //make sure that connection has been marked as broken
|
||||
tlog1 << e.what() << std::endl;
|
||||
end2 = true;
|
||||
}
|
||||
HANDLE_EXCEPTION(end2 = true);
|
||||
handleConEnd:
|
||||
|
||||
tlog1 << "Ended handling connection\n";
|
||||
}
|
||||
|
||||
@ -901,6 +910,8 @@ void CGameHandler::newTurn()
|
||||
for(size_t i = 0; i<gs->map->objects.size(); i++)
|
||||
if(gs->map->objects[i])
|
||||
gs->map->objects[i]->newTurn();
|
||||
|
||||
winLoseHandle(0xff);
|
||||
}
|
||||
void CGameHandler::run(bool resume)
|
||||
{
|
||||
@ -948,7 +959,13 @@ void CGameHandler::run(bool resume)
|
||||
for(; i != gs->players.end(); i++)
|
||||
{
|
||||
|
||||
if((i->second.towns.size()==0 && i->second.heroes.size()==0) || i->second.color<0 || i->first>=PLAYER_LIMIT ) continue; //players has not towns/castle - loser
|
||||
if(i->second.towns.size()==0 && i->second.heroes.size()==0
|
||||
|| i->second.color<0
|
||||
|| i->first>=PLAYER_LIMIT
|
||||
|| i->second.status)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
states.setFlag(i->first,&PlayerStatus::makingTurn,true);
|
||||
gs->currentPlayer = i->first;
|
||||
{
|
||||
@ -968,6 +985,9 @@ void CGameHandler::run(bool resume)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(conns.size() && (*conns.begin())->isOpen())
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(5)); //give time client to close socket
|
||||
}
|
||||
|
||||
namespace CGH
|
||||
@ -1385,6 +1405,8 @@ bool CGameHandler::removeObject( int objid )
|
||||
RemoveObject ro;
|
||||
ro.id = objid;
|
||||
sendAndApply(&ro);
|
||||
|
||||
winLoseHandle(255); //eg if monster escaped (removing objs after battle is done dircetly by endBattle, not this function)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1556,6 +1578,8 @@ void CGameHandler::setOwner(int objid, ui8 owner)
|
||||
{
|
||||
SetObjectProperty sop(objid,1,owner);
|
||||
sendAndApply(&sop);
|
||||
|
||||
winLoseHandle(1<<owner);
|
||||
}
|
||||
void CGameHandler::setHoverName(int objid, MetaString* name)
|
||||
{
|
||||
@ -3433,3 +3457,138 @@ void CGameHandler::engageIntoBattle( ui8 player )
|
||||
pb.reason = PlayerBlocked::UPCOMING_BATTLE;
|
||||
sendAndApply(&pb);
|
||||
}
|
||||
|
||||
void CGameHandler::winLoseHandle(ui8 players )
|
||||
{
|
||||
for(size_t i = 0; i < PLAYER_LIMIT; i++)
|
||||
{
|
||||
if(players & 1<<i && gs->getPlayer(i))
|
||||
{
|
||||
checkLossVictory(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameHandler::checkLossVictory( ui8 player )
|
||||
{
|
||||
int loss = gs->lossCheck(player);
|
||||
int vic = gs->victoryCheck(player);
|
||||
|
||||
if(!loss && !vic)
|
||||
return;
|
||||
|
||||
InfoWindow iw;
|
||||
getLossVicMessage(player, vic ? vic < 0 : loss < 0, vic, iw);
|
||||
sendAndApply(&iw);
|
||||
|
||||
PlayerEndsGame peg;
|
||||
peg.player = player;
|
||||
peg.victory = vic;
|
||||
sendAndApply(&peg);
|
||||
|
||||
if(vic)
|
||||
end2 = true;
|
||||
}
|
||||
|
||||
void CGameHandler::getLossVicMessage( ui8 player, bool standard, bool victory, InfoWindow &out ) const
|
||||
{
|
||||
const PlayerState *p = gs->getPlayer(player);
|
||||
if(!p->human)
|
||||
return; //AI doesn't need text info of loss
|
||||
|
||||
out.player = player;
|
||||
|
||||
if(victory)
|
||||
{
|
||||
if(!standard) //not std loss
|
||||
{
|
||||
switch(gs->map->victoryCondition.condition)
|
||||
{
|
||||
case artifact:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 280); //Congratulations! You have found the %s, and can claim victory!
|
||||
out.text.addReplacement(MetaString::ART_NAMES,gs->map->victoryCondition.obj->subID); //artifact name
|
||||
break;
|
||||
case gatherTroop:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 276); //Congratulations! You have over %d %s in your armies. Your enemies have no choice but to bow down before your power!
|
||||
out.text.addReplacement(gs->map->victoryCondition.count);
|
||||
out.text.addReplacement(MetaString::CRE_PL_NAMES, gs->map->victoryCondition.ID);
|
||||
break;
|
||||
case gatherResource:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 278); //Congratulations! You have collected over %d %s in your treasury. Victory is yours!
|
||||
out.text.addReplacement(gs->map->victoryCondition.count);
|
||||
out.text.addReplacement(MetaString::RES_NAMES, gs->map->victoryCondition.ID);
|
||||
break;
|
||||
case buildCity:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 282); //Congratulations! You have successfully upgraded your town, and can claim victory!
|
||||
break;
|
||||
case buildGrail:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 284); //Congratulations! You have constructed a permanent home for the Grail, and can claim victory!
|
||||
break;
|
||||
case beatHero:
|
||||
{
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 252); //Congratulations! You have completed your quest to defeat the enemy hero %s. Victory is yours!
|
||||
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance*>(gs->map->victoryCondition.obj);
|
||||
assert(h);
|
||||
out.text.addReplacement(h->name);
|
||||
}
|
||||
break;
|
||||
case captureCity:
|
||||
{
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 249); //Congratulations! You captured %s, and are victorious!
|
||||
const CGTownInstance *t = dynamic_cast<const CGTownInstance*>(gs->map->victoryCondition.obj);
|
||||
assert(t);
|
||||
out.text.addReplacement(t->name);
|
||||
}
|
||||
break;
|
||||
case beatMonster:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 286); //Congratulations! You have completed your quest to kill the fearsome beast, and can claim victory!
|
||||
break;
|
||||
case takeDwellings:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 288); //Congratulations! Your flag flies on the dwelling of every creature. Victory is yours!
|
||||
break;
|
||||
case takeMines:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 290); //Congratulations! Your flag flies on every mine. Victory is yours!
|
||||
break;
|
||||
case transportItem:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 292); //Congratulations! You have reached your destination, precious cargo intact, and can claim victory!
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!standard) //not std loss
|
||||
{
|
||||
switch(gs->map->lossCondition.typeOfLossCon)
|
||||
{
|
||||
case lossCastle:
|
||||
{
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 251); //The town of %s has fallen - all is lost!
|
||||
const CGTownInstance *t = dynamic_cast<const CGTownInstance*>(gs->map->lossCondition.obj);
|
||||
assert(t);
|
||||
out.text.addReplacement(t->name);
|
||||
}
|
||||
break;
|
||||
case lossHero:
|
||||
{
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 253); //The hero, %s, has suffered defeat - your quest is over!
|
||||
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance*>(gs->map->lossCondition.obj);
|
||||
assert(h);
|
||||
out.text.addReplacement(h->name);
|
||||
}
|
||||
break;
|
||||
case timeExpires:
|
||||
out.text.addTxt(MetaString::GENERAL_TXT, 254); //Alas, time has run out on your quest. All is lost.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else //lost all towns and heroes
|
||||
{
|
||||
out.text.addReplacement(MetaString::GENERAL_TXT, 660); //All your forces have been defeated, and you are banished from this land!
|
||||
}
|
||||
}
|
||||
}
|
@ -85,6 +85,10 @@ public:
|
||||
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
|
||||
int moveStack(int stack, int dest); //returned value - travelled distance
|
||||
void startBattle(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town = NULL); //use hero=NULL for no hero
|
||||
void checkLossVictory(ui8 player);
|
||||
void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all
|
||||
void getLossVicMessage(ui8 player, bool standard, bool victory, InfoWindow &out) const;
|
||||
|
||||
////used only in endBattle - don't touch elsewhere
|
||||
boost::function<void(BattleResult*)> * battleEndCallback;
|
||||
const CArmedInstance * bEndArmy1, * bEndArmy2;
|
||||
@ -95,7 +99,6 @@ public:
|
||||
void checkForBattleEnd( std::vector<CStack*> &stacks );
|
||||
void setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town);
|
||||
|
||||
|
||||
CGameHandler(void);
|
||||
~CGameHandler(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user