1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-03 00:46:55 +02:00

- Refactored victory loss condition checks

- Added toString() method to EVictoryLossCheckResult enum class to improve debugging
- Removed mostly unused CFunctionList2
- Added missing header files for vcmiclient project to CMakeLists
- Tweaked SDL suggests bpp message a bit
- Added showInfoDialogAndWait (info dialog and waits, used from client thread) and showOkDialog (callback to ok click, used from GUI thread) to player interface
- Added showOkDialog method to CInfoWindow (unused for now, but may be used later)
This commit is contained in:
beegee1
2013-11-30 09:43:31 +00:00
parent 2f698acf98
commit c786a3076a
14 changed files with 166 additions and 139 deletions

View File

@ -755,7 +755,7 @@ static void setScreenRes(int w, int h, int bpp, bool fullscreen, bool resetVideo
if(suggestedBpp != bpp) if(suggestedBpp != bpp)
{ {
logGlobal->warnStream() << "Note: SDL suggests to use " << suggestedBpp << " bpp instead of" << bpp << " bpp "; logGlobal->infoStream() << boost::format("Using %s bpp (bits per pixel) for the video mode. Default or overriden setting was %s bpp.") % suggestedBpp % bpp;
} }
//For some reason changing fullscreen via config window checkbox result in SDL_Quit event //For some reason changing fullscreen via config window checkbox result in SDL_Quit event

View File

@ -6,17 +6,13 @@ include_directories(${SDL_INCLUDE_DIR} ${SDLIMAGE_INCLUDE_DIR} ${SDLMIXER_INCLUD
include_directories(${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS})
set(client_SRCS set(client_SRCS
CPreGame.cpp
Client.cpp
CPlayerInterface.cpp
CMT.cpp
GUIClasses.cpp
battle/CBattleInterface.cpp
../CCallback.cpp ../CCallback.cpp
battle/CBattleInterface.cpp
battle/CBattleAnimations.cpp battle/CBattleAnimations.cpp
battle/CBattleInterfaceClasses.cpp battle/CBattleInterfaceClasses.cpp
battle/CCreatureAnimation.cpp battle/CCreatureAnimation.cpp
gui/CGuiHandler.cpp gui/CGuiHandler.cpp
gui/CIntObject.cpp gui/CIntObject.cpp
gui/CIntObjectClasses.cpp gui/CIntObjectClasses.cpp
@ -24,6 +20,12 @@ set(client_SRCS
gui/Geometries.cpp gui/Geometries.cpp
gui/CCursorHandler.cpp gui/CCursorHandler.cpp
gui/SDL_Extensions.cpp gui/SDL_Extensions.cpp
CPreGame.cpp
Client.cpp
CPlayerInterface.cpp
CMT.cpp
GUIClasses.cpp
AdventureMapClasses.cpp AdventureMapClasses.cpp
CAdvmapInterface.cpp CAdvmapInterface.cpp
CAnimation.cpp CAnimation.cpp
@ -44,15 +46,22 @@ set(client_SRCS
NetPacksClient.cpp NetPacksClient.cpp
) )
set(client_HEADERS
CSoundBase.h
FunctionList.h
gui/SDL_Pixels.h
)
if(WIN32) if(WIN32)
add_executable(vcmiclient WIN32 ${client_SRCS}) add_executable(vcmiclient WIN32 ${client_SRCS} ${client_HEADERS})
elseif(APPLE) elseif(APPLE)
# OS X specific includes # OS X specific includes
include_directories(${SPARKLE_INCLUDE_DIR}) include_directories(${SPARKLE_INCLUDE_DIR})
# OS X specific source files # OS X specific source files
set(client_SRCS ${client_SRCS} SDLMain.m OSX.mm Info.plist vcmi.icns ../osx/vcmi_dsa_public.pem) set(client_SRCS ${client_SRCS} SDLMain.m OSX.mm Info.plist vcmi.icns ../osx/vcmi_dsa_public.pem)
add_executable(vcmiclient MACOSX_BUNDLE ${client_SRCS}) add_executable(vcmiclient MACOSX_BUNDLE ${client_SRCS} ${client_HEADERS})
# OS X specific libraries # OS X specific libraries
target_link_libraries(vcmiclient ${SPARKLE_FRAMEWORK}) target_link_libraries(vcmiclient ${SPARKLE_FRAMEWORK})
@ -93,7 +102,7 @@ elseif(APPLE)
add_custom_command(TARGET vcmiclient POST_BUILD COMMAND ${MakeVCMIBundle}) add_custom_command(TARGET vcmiclient POST_BUILD COMMAND ${MakeVCMIBundle})
else() else()
add_executable(vcmiclient ${client_SRCS}) add_executable(vcmiclient ${client_SRCS} ${client_HEADERS})
endif() endif()
target_link_libraries(vcmiclient vcmi ${Boost_LIBRARIES} ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} ${SDLTTF_LIBRARY} ${ZLIB_LIBRARIES} ${FFMPEG_LIBRARIES} ${RT_LIB} ${DL_LIB}) target_link_libraries(vcmiclient vcmi ${Boost_LIBRARIES} ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} ${SDLTTF_LIBRARY} ${ZLIB_LIBRARIES} ${FFMPEG_LIBRARIES} ${RT_LIB} ${DL_LIB})

View File

@ -1022,6 +1022,21 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
} }
} }
void CPlayerInterface::showInfoDialogAndWait(std::vector<Component> & components, const MetaString & text)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
std::vector<Component*> comps;
for(auto & elem : components)
{
comps.push_back(&elem);
}
std::string str;
text.toString(str);
showInfoDialog(str,comps, 0);
waitWhileDialog();
}
void CPlayerInterface::showYesNoDialog(const std::string &text, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps, const std::vector<CComponent*> & components) void CPlayerInterface::showYesNoDialog(const std::string &text, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps, const std::vector<CComponent*> & components)
{ {
boost::unique_lock<boost::recursive_mutex> un(*pim); boost::unique_lock<boost::recursive_mutex> un(*pim);
@ -1031,6 +1046,27 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, CFunctionList<vo
CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID); CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID);
} }
void CPlayerInterface::showOkDialog(std::vector<Component> & components, const MetaString & text, const boost::function<void()> & onOk)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
std::vector<Component*> comps;
for(auto & elem : components)
{
comps.push_back(&elem);
}
std::string str;
text.toString(str);
stopMovement();
showingDialog->setn(true);
std::vector<CComponent*> intComps;
for(auto & component : comps)
intComps.push_back(new CComponent(*component));
CInfoWindow::showOkDialog(str, &intComps, onOk, true, playerID);
}
void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, QueryID askID, int soundID, bool selection, bool cancel ) void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, QueryID askID, int soundID, bool selection, bool cancel )
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -2251,6 +2287,31 @@ void CPlayerInterface::acceptTurn()
adventureInt->endTurn.callback(); adventureInt->endTurn.callback();
} }
// warn player if he has no town
if(cb->howManyTowns() == 0)
{
auto playerColor = *cb->getPlayerID();
std::vector<Component> components;
components.push_back(Component(Component::FLAG, playerColor.getNum(), 0, 0));
MetaString text;
auto daysWithoutCastle = cb->getPlayer(playerColor)->daysWithoutCastle;
if(daysWithoutCastle == 6)
{
text.addTxt(MetaString::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land.
text.addReplacement(MetaString::COLOR, playerColor.getNum());
}
else
{
text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
text.addReplacement(MetaString::COLOR, playerColor.getNum());
text.addReplacement(7 - daysWithoutCastle);
}
showInfoDialogAndWait(components, text);
}
} }
void CPlayerInterface::tryDiggging(const CGHeroInstance *h) void CPlayerInterface::tryDiggging(const CGHeroInstance *h)

View File

@ -229,9 +229,14 @@ public:
void updateInfo(const CGObjectInstance * specific); void updateInfo(const CGObjectInstance * specific);
void init(shared_ptr<CCallback> CB); void init(shared_ptr<CCallback> CB);
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
// show dialogs
void showInfoDialog(const std::string &text, CComponent * component); void showInfoDialog(const std::string &text, CComponent * component);
void showInfoDialog(const std::string &text, const std::vector<CComponent*> & components = std::vector<CComponent*>(), int soundID = 0, bool delComps = false); void showInfoDialog(const std::string &text, const std::vector<CComponent*> & components = std::vector<CComponent*>(), int soundID = 0, bool delComps = false);
void showInfoDialogAndWait(std::vector<Component> & components, const MetaString & text);
void showOkDialog(std::vector<Component> & components, const MetaString & text, const boost::function<void()> & onOk);
void showYesNoDialog(const std::string &text, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps = false, const std::vector<CComponent*> & components = std::vector<CComponent*>()); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close void showYesNoDialog(const std::string &text, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps = false, const std::vector<CComponent*> & components = std::vector<CComponent*>()); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
void stopMovement(); void stopMovement();
bool moveHero(const CGHeroInstance *h, CGPath path); bool moveHero(const CGHeroInstance *h, CGPath path);
void initMovement(const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp );//initializing objects and performing first step of move void initMovement(const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp );//initializing objects and performing first step of move

View File

@ -83,48 +83,3 @@ public:
} }
} }
}; };
template<typename Signature>
class CFunctionList2
{
public:
std::vector<boost::function<Signature> > funcs;
CFunctionList2(int){};
CFunctionList2(){};
template <typename Functor>
CFunctionList2(const Functor &f)
{
funcs.push_back(boost::function<Signature>(f));
}
CFunctionList2(const boost::function<Signature> &first)
{
funcs.push_back(first);
}
CFunctionList2(boost::function<Signature> &first)
{
funcs.push_back(first);
}
CFunctionList2 & operator+=(const boost::function<Signature> &first)
{
funcs.push_back(first);
return *this;
}
void clear()
{
funcs.clear();
}
operator bool() const
{
return funcs.size();
}
template <typename Arg>
void operator()(const Arg & a) const
{
std::vector<boost::function<Signature> > funcs2 = funcs; //backup
for(size_t i=0;i<funcs2.size(); ++i)
{
funcs2[i](a);
}
}
};

View File

@ -742,6 +742,16 @@ void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<CC
GH.pushInt(temp); GH.pushInt(temp);
} }
void CInfoWindow::showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps, PlayerColor player)
{
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, player, *components, pom, delComps);
temp->buttons[0]->callback += onOk;
GH.pushInt(temp);
}
CInfoWindow * CInfoWindow::create(const std::string &text, PlayerColor playerID /*= 1*/, const std::vector<CComponent*> *components /*= nullptr*/, bool DelComps) CInfoWindow * CInfoWindow::create(const std::string &text, PlayerColor playerID /*= 1*/, const std::vector<CComponent*> *components /*= nullptr*/, bool DelComps)
{ {
std::vector<std::pair<std::string,CFunctionList<void()> > > pom; std::vector<std::pair<std::string,CFunctionList<void()> > > pom;

View File

@ -106,6 +106,7 @@ public:
//use only before the game starts! (showYesNoDialog in LOCPLINT must be used then) //use only before the game starts! (showYesNoDialog in LOCPLINT must be used then)
static void showInfoDialog( const std::string & text, const std::vector<CComponent*> *components, bool DelComps = true, PlayerColor player = PlayerColor(1)); static void showInfoDialog( const std::string & text, const std::vector<CComponent*> *components, bool DelComps = true, PlayerColor player = PlayerColor(1));
static void showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps = true, PlayerColor player = PlayerColor(1));
static void showYesNoDialog( const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps = true, PlayerColor player = PlayerColor(1)); static void showYesNoDialog( const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps = true, PlayerColor player = PlayerColor(1));
static CInfoWindow *create(const std::string &text, PlayerColor playerID = PlayerColor(1), const std::vector<CComponent*> *components = nullptr, bool DelComps = false); static CInfoWindow *create(const std::string &text, PlayerColor playerID = PlayerColor(1), const std::vector<CComponent*> *components = nullptr, bool DelComps = false);

View File

@ -534,7 +534,7 @@ void CHighlightableButtonsGroup::addButton(const std::map<int,std::string> &tool
buttons.push_back(bt); buttons.push_back(bt);
} }
CHighlightableButtonsGroup::CHighlightableButtonsGroup(const CFunctionList2<void(int)> &OnChange, bool musicLikeButtons) CHighlightableButtonsGroup::CHighlightableButtonsGroup(const CFunctionList<void(int)> &OnChange, bool musicLikeButtons)
: onChange(OnChange), musicLike(musicLikeButtons) : onChange(OnChange), musicLike(musicLikeButtons)
{} {}

View File

@ -171,14 +171,14 @@ public:
class CHighlightableButtonsGroup : public CIntObject class CHighlightableButtonsGroup : public CIntObject
{ {
public: public:
CFunctionList2<void(int)> onChange; //called when changing selected button with new button's id CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
std::vector<CHighlightableButton*> buttons; std::vector<CHighlightableButton*> buttons;
bool musicLike; //determines the behaviour of this group bool musicLike; //determines the behaviour of this group
//void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid); //void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid);
void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor
void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button
CHighlightableButtonsGroup(const CFunctionList2<void(int)> &OnChange, bool musicLikeButtons = false); CHighlightableButtonsGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
~CHighlightableButtonsGroup(); ~CHighlightableButtonsGroup();
void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id
void selectionChanged(int to); void selectionChanged(int to);

View File

@ -3327,15 +3327,19 @@ bool EVictoryLossCheckResult::loss() const
return !victory(); return !victory();
} }
std::string EVictoryLossCheckResult::toString() const
{
if(*this == EVictoryLossCheckResult::NO_VICTORY_OR_LOSS) return "No victory or loss";
else if(*this == EVictoryLossCheckResult::VICTORY_STANDARD) return "Victory standard";
else if(*this == EVictoryLossCheckResult::VICTORY_SPECIAL) return "Victory special";
else if(*this == EVictoryLossCheckResult::LOSS_STANDARD_HEROES_AND_TOWNS) return "Loss standard heroes and towns";
else if(*this == EVictoryLossCheckResult::LOSS_STANDARD_TOWNS_AND_TIME_OVER) return "Loss standard towns and time over";
else if(*this == EVictoryLossCheckResult::LOSS_SPECIAL) return "Loss special";
else return "Unknown type";
}
std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult) std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult)
{ {
if(victoryLossCheckResult == EVictoryLossCheckResult::NO_VICTORY_OR_LOSS) os << "No victory or loss"; os << victoryLossCheckResult.toString();
else if(victoryLossCheckResult == EVictoryLossCheckResult::VICTORY_STANDARD) os << "Victory standard";
else if(victoryLossCheckResult == EVictoryLossCheckResult::VICTORY_SPECIAL) os << "Victory special";
else if(victoryLossCheckResult == EVictoryLossCheckResult::LOSS_STANDARD_HEROES_AND_TOWNS) os << "Loss standard heroes and towns";
else if(victoryLossCheckResult == EVictoryLossCheckResult::LOSS_STANDARD_TOWNS_AND_TIME_OVER) os << "Loss standard towns and time over";
else if(victoryLossCheckResult == EVictoryLossCheckResult::LOSS_SPECIAL) os << "Loss special";
else os << "Unknown type";
return os; return os;
} }

View File

@ -371,6 +371,7 @@ public:
bool operator!=(EVictoryLossCheckResult const & other) const; bool operator!=(EVictoryLossCheckResult const & other) const;
bool victory() const; bool victory() const;
bool loss() const; bool loss() const;
std::string toString() const;
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {

View File

@ -2,7 +2,6 @@
#include "BattleHex.h" #include "BattleHex.h"
#include "../client/FunctionList.h"
#include "ResourceSet.h" #include "ResourceSet.h"
#include "int3.h" #include "int3.h"
#include "GameConstants.h" #include "GameConstants.h"

View File

@ -685,7 +685,9 @@ void CGameHandler::battleAfterLevelUp( const BattleResult &result )
} }
visitObjectAfterVictory = false; visitObjectAfterVictory = false;
winLoseHandle(1<<finishingBattle->loser.getNum() | 1<<finishingBattle->victor.getNum()); //handle victory/loss of engaged players //handle victory/loss of engaged players
std::set<PlayerColor> playerColors = boost::assign::list_of(finishingBattle->loser)(finishingBattle->victor);
checkVictoryLossConditions(playerColors);
if(result.result == BattleResult::SURRENDER || result.result == BattleResult::ESCAPE) //loser has escaped or surrendered if(result.result == BattleResult::SURRENDER || result.result == BattleResult::ESCAPE) //loser has escaped or surrendered
{ {
@ -1411,39 +1413,7 @@ void CGameHandler::newTurn()
elem->newTurn(); elem->newTurn();
} }
winLoseHandle(0xff); checkVictoryLossConditionsForAll();
//warn players without town
if(gs->day)
{
for (auto i=gs->players.cbegin() ; i!=gs->players.cend();i++)
{
if(i->second.status || i->second.towns.size() || i->second.color >= PlayerColor::PLAYER_LIMIT)
continue;
InfoWindow iw;
iw.player = i->first;
iw.components.push_back(Component(Component::FLAG, i->first.getNum(), 0, 0));
if(!i->second.daysWithoutCastle)
{
iw.text.addTxt(MetaString::GENERAL_TXT,6); //%s, you have lost your last town. If you do not conquer another town in the next week, you will be eliminated.
iw.text.addReplacement(MetaString::COLOR, i->first.getNum());
}
else if(i->second.daysWithoutCastle == 6)
{
iw.text.addTxt(MetaString::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land.
iw.text.addReplacement(MetaString::COLOR, i->first.getNum());
}
else
{
iw.text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
iw.text.addReplacement(MetaString::COLOR, i->first.getNum());
iw.text.addReplacement(7 - i->second.daysWithoutCastle);
}
sendAndApply(&iw);
}
}
synchronizeArtifactHandlerLists(); //new day events may have changed them. TODO better of managing that synchronizeArtifactHandlerLists(); //new day events may have changed them. TODO better of managing that
} }
@ -1515,19 +1485,13 @@ void CGameHandler::run(bool resume)
resume = false; resume = false;
for(; i != gs->players.end(); i++) for(; i != gs->players.end(); i++)
{ {
if((i->second.towns.size()==0 && i->second.heroes.size()==0) if(i->second.status == EPlayerStatus::INGAME)
|| i->first>=PlayerColor::PLAYER_LIMIT
|| i->second.status)
{ {
continue;
}
states.setFlag(i->first,&PlayerStatus::makingTurn,true); states.setFlag(i->first,&PlayerStatus::makingTurn,true);
{
YourTurn yt; YourTurn yt;
yt.player = i->first; yt.player = i->first;
applyAndSend(&yt); applyAndSend(&yt);
}
//wait till turn is done //wait till turn is done
boost::unique_lock<boost::mutex> lock(states.mx); boost::unique_lock<boost::mutex> lock(states.mx);
@ -1535,7 +1499,7 @@ void CGameHandler::run(bool resume)
{ {
static time_duration p = milliseconds(200); static time_duration p = milliseconds(200);
states.cv.timed_wait(lock,p); states.cv.timed_wait(lock,p);
}
} }
} }
} }
@ -1608,7 +1572,7 @@ bool CGameHandler::removeObject( const CGObjectInstance * obj )
ro.id = obj->id; ro.id = obj->id;
sendAndApply(&ro); sendAndApply(&ro);
winLoseHandle(255); //eg if monster escaped (removing objs after battle is done dircetly by endBattle, not this function) checkVictoryLossConditionsForAll(); //eg if monster escaped (removing objs after battle is done dircetly by endBattle, not this function)
return true; return true;
} }
@ -1811,7 +1775,9 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
SetObjectProperty sop(obj->id, 1, owner.getNum()); SetObjectProperty sop(obj->id, 1, owner.getNum());
sendAndApply(&sop); sendAndApply(&sop);
winLoseHandle(1<<owner.getNum() | 1<<oldOwner.getNum()); std::set<PlayerColor> playerColors = boost::assign::list_of(owner)(oldOwner);
checkVictoryLossConditions(playerColors);
if(owner < PlayerColor::PLAYER_LIMIT && dynamic_cast<const CGTownInstance *>(obj)) //town captured if(owner < PlayerColor::PLAYER_LIMIT && dynamic_cast<const CGTownInstance *>(obj)) //town captured
{ {
const CGTownInstance * town = dynamic_cast<const CGTownInstance *>(obj); const CGTownInstance * town = dynamic_cast<const CGTownInstance *>(obj);
@ -1933,7 +1899,7 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
giveSpells (obj, hero); giveSpells (obj, hero);
if(gs->map->victoryCondition.condition == EVictoryConditionType::TRANSPORTITEM) if(gs->map->victoryCondition.condition == EVictoryConditionType::TRANSPORTITEM)
checkLossVictory(hero->tempOwner); //transported artifact? checkVictoryLossConditionsForPlayer(hero->tempOwner); //transported artifact?
} }
void CGameHandler::vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h) void CGameHandler::vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h)
@ -2178,28 +2144,28 @@ void CGameHandler::sendAndApply(CGarrisonOperationPack * info)
{ {
sendAndApply(static_cast<CPackForClient*>(info)); sendAndApply(static_cast<CPackForClient*>(info));
if(gs->map->victoryCondition.condition == EVictoryConditionType::GATHERTROOP) if(gs->map->victoryCondition.condition == EVictoryConditionType::GATHERTROOP)
winLoseHandle(); checkVictoryLossConditionsForAll();
} }
void CGameHandler::sendAndApply( SetResource * info ) void CGameHandler::sendAndApply( SetResource * info )
{ {
sendAndApply(static_cast<CPackForClient*>(info)); sendAndApply(static_cast<CPackForClient*>(info));
if(gs->map->victoryCondition.condition == EVictoryConditionType::GATHERRESOURCE) if(gs->map->victoryCondition.condition == EVictoryConditionType::GATHERRESOURCE)
checkLossVictory(info->player); checkVictoryLossConditionsForPlayer(info->player);
} }
void CGameHandler::sendAndApply( SetResources * info ) void CGameHandler::sendAndApply( SetResources * info )
{ {
sendAndApply(static_cast<CPackForClient*>(info)); sendAndApply(static_cast<CPackForClient*>(info));
if(gs->map->victoryCondition.condition == EVictoryConditionType::GATHERRESOURCE) if(gs->map->victoryCondition.condition == EVictoryConditionType::GATHERRESOURCE)
checkLossVictory(info->player); checkVictoryLossConditionsForPlayer(info->player);
} }
void CGameHandler::sendAndApply( NewStructures * info ) void CGameHandler::sendAndApply( NewStructures * info )
{ {
sendAndApply(static_cast<CPackForClient*>(info)); sendAndApply(static_cast<CPackForClient*>(info));
if(gs->map->victoryCondition.condition == EVictoryConditionType::BUILDCITY) if(gs->map->victoryCondition.condition == EVictoryConditionType::BUILDCITY)
checkLossVictory(getTown(info->tid)->tempOwner); checkVictoryLossConditionsForPlayer(getTown(info->tid)->tempOwner);
} }
void CGameHandler::save(const std::string & filename ) void CGameHandler::save(const std::string & filename )
@ -2525,7 +2491,7 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
if(t->garrisonHero) if(t->garrisonHero)
vistiCastleObjects (t, t->garrisonHero); vistiCastleObjects (t, t->garrisonHero);
checkLossVictory(t->tempOwner); checkVictoryLossConditionsForPlayer(t->tempOwner);
return true; return true;
} }
bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid) bool CGameHandler::razeStructure (ObjectInstanceID tid, BuildingID bid)
@ -3927,7 +3893,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
{ {
SystemMessage temp_message(VLC->generaltexth->allTexts.at(260)); SystemMessage temp_message(VLC->generaltexth->allTexts.at(260));
sendAndApply(&temp_message); sendAndApply(&temp_message);
checkLossVictory(player);//Player enter win code or got required art\creature checkVictoryLossConditionsForPlayer(player);//Player enter win code or got required art\creature
} }
} }
@ -5055,21 +5021,28 @@ void CGameHandler::engageIntoBattle( PlayerColor player )
sendAndApply(&pb); sendAndApply(&pb);
} }
void CGameHandler::winLoseHandle(ui8 players ) void CGameHandler::checkVictoryLossConditions(const std::set<PlayerColor> & playerColors)
{ {
for(size_t i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) for(auto playerColor : playerColors)
{ {
if(players & 1<<i && gs->getPlayer(PlayerColor(i))) if(gs->getPlayer(playerColor)) checkVictoryLossConditionsForPlayer(playerColor);
{
checkLossVictory(PlayerColor(i));
}
} }
} }
void CGameHandler::checkLossVictory( PlayerColor player ) void CGameHandler::checkVictoryLossConditionsForAll()
{
std::set<PlayerColor> playerColors;
for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
{
playerColors.insert(PlayerColor(i));
}
checkVictoryLossConditions(playerColors);
}
void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
{ {
const PlayerState *p = gs->getPlayer(player); const PlayerState *p = gs->getPlayer(player);
if(p->status == EPlayerStatus::WINNER || p->status == EPlayerStatus::LOSER || p->status == EPlayerStatus::WRONG) return; if(p->status != EPlayerStatus::INGAME) return;
auto victoryLossCheckResult = gs->checkForVictoryAndLoss(player); auto victoryLossCheckResult = gs->checkForVictoryAndLoss(player);
@ -5091,7 +5064,7 @@ void CGameHandler::checkLossVictory( PlayerColor player )
for (auto i = gs->players.cbegin(); i!=gs->players.cend(); i++) for (auto i = gs->players.cbegin(); i!=gs->players.cend(); i++)
{ {
if(i->first < PlayerColor::PLAYER_LIMIT && i->first != player)//FIXME: skip already eliminated players? if(i->first != player && gs->getPlayer(i->first)->status == EPlayerStatus::INGAME)
{ {
iw.player = i->first; iw.player = i->first;
sendAndApply(&iw); sendAndApply(&iw);
@ -5150,7 +5123,13 @@ void CGameHandler::checkLossVictory( PlayerColor player )
} }
//eliminating one player may cause victory of another: //eliminating one player may cause victory of another:
winLoseHandle(GameConstants::ALL_PLAYERS & ~(1<<player.getNum())); std::set<PlayerColor> playerColors;
for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
{
if(player.getNum() != i) playerColors.insert(PlayerColor(i));
}
checkVictoryLossConditions(playerColors);
} }
//If player making turn has lost his turn must be over as well //If player making turn has lost his turn must be over as well

View File

@ -106,8 +106,6 @@ public:
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h); void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
int moveStack(int stack, BattleHex dest); //returned value - travelled distance int moveStack(int stack, BattleHex dest); //returned value - travelled distance
void runBattle(); void runBattle();
void checkLossVictory(PlayerColor player);
void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all
////used only in endBattle - don't touch elsewhere ////used only in endBattle - don't touch elsewhere
bool visitObjectAfterVictory; bool visitObjectAfterVictory;
@ -293,6 +291,11 @@ public:
private: private:
void makeStackDoNothing(const CStack * next); void makeStackDoNothing(const CStack * next);
void getVictoryLossMessage(PlayerColor player, EVictoryLossCheckResult victoryLossCheckResult, InfoWindow & out) const; void getVictoryLossMessage(PlayerColor player, EVictoryLossCheckResult victoryLossCheckResult, InfoWindow & out) const;
// Check for victory and loss conditions
void checkVictoryLossConditionsForPlayer(PlayerColor player);
void checkVictoryLossConditions(const std::set<PlayerColor> & playerColors);
void checkVictoryLossConditionsForAll();
}; };
void makeStackDoNothing(); void makeStackDoNothing();