Created a NetworkGameObserver class able to extend the serialization code of GameObserver to synchronize and forward game actions on the network

Fixes in GameObserver serialization/deserialization code
Fixes in JNetwork and JSocket on windows
Various code cleanup (currentGamePhase access in particular)
Updated GUI code to re-enable a basic network GUI
Activated threaded tests on Windows. It uses 4 threads by default.
This commit is contained in:
Xawotihs@gmail.com
2013-01-22 22:39:49 +00:00
parent ada0a1555d
commit 9db8478dfe
18 changed files with 493 additions and 269 deletions

View File

@@ -13,31 +13,42 @@ class JSocket;
#include <sstream> #include <sstream>
#include "Threading.h" #include "Threading.h"
typedef void(*processCmd)(istream&, ostream&); typedef void(*processCmd)(void*, stringstream&, stringstream&);
class JNetwork { class JNetwork {
private: private:
struct CommandStruc{
void* object;
string command;
processCmd processCommand;
};
string serverIP;
int connected_to_ap; int connected_to_ap;
JSocket* socket; JSocket* socket;
boost::mutex sendMutex; boost::mutex sendMutex;
boost::mutex receiveMutex; boost::mutex receiveMutex;
stringstream received; stringstream received;
stringstream toSend; stringstream toSend;
static map<string, processCmd> sCommandMap; static map<string, CommandStruc> sCommandMap;
static JNetwork* mInstance;
public: public:
JNetwork(); JNetwork();
~JNetwork(); ~JNetwork();
string serverIP; static JNetwork* GetInstance();
static void Destroy();
void Update();
int connect(string serverIP = ""); int connect(string serverIP = "");
bool isConnected(); bool isConnected();
bool isServer() { return serverIP == ""; };
static void ThreadProc(void* param); static void ThreadProc(void* param);
#if !defined (WIN32) && !defined (LINUX) #if !defined (WIN32) && !defined (LINUX)
static int connect_to_apctl(int config); static int connect_to_apctl(int config);
#endif #endif
bool sendCommand(string command); bool sendCommand(const string& command, const string& payload = "", const string& suffix = "Request");
static void registerCommand(string command, processCmd processCommand, processCmd processResponse); static void registerCommand(string command, void* object, processCmd processRequest, processCmd processResponse);
private: private:
boost::thread *mpWorkerThread; boost::thread *mpWorkerThread;

View File

@@ -33,15 +33,16 @@
#include <sstream> #include <sstream>
#include "../include/JSocket.h" #include "../include/JSocket.h"
map<string, processCmd> JNetwork::sCommandMap; map<string, JNetwork::CommandStruc> JNetwork::sCommandMap;
JNetwork* JNetwork::mInstance = NULL;
bool JNetwork::isConnected(){ bool JNetwork::isConnected(){
if (connected_to_ap !=1) return false; if (connected_to_ap !=1 || !socket) return false;
return socket->isConnected(); return socket->isConnected();
} }
JNetwork::JNetwork() JNetwork::JNetwork()
: mpWorkerThread(NULL) : mpWorkerThread(NULL), socket(0)
{ {
#if (defined WIN32) || (defined LINUX) #if (defined WIN32) || (defined LINUX)
connected_to_ap = 1; connected_to_ap = 1;
@@ -62,30 +63,83 @@ JNetwork::~JNetwork()
delete socket; delete socket;
} }
bool JNetwork::sendCommand(string xString) JNetwork* JNetwork::GetInstance()
{ {
string aString = xString; if (mInstance == NULL) mInstance = new JNetwork();
return mInstance;
}
void JNetwork::Destroy()
{
if (mInstance)
{
delete mInstance;
mInstance = NULL;
}
}
bool JNetwork::sendCommand(const string& xString, const string& payload, const string& suffix)
{
string aString;
boost::mutex::scoped_lock l(sendMutex); boost::mutex::scoped_lock l(sendMutex);
if(!socket) { if(!socket) {
DebugTrace("sendCommand failed: no sockeet"); DebugTrace("sendCommand failed: no socket");
return false; return false;
} }
aString = aString + "Command"; aString = xString + suffix;
if(sCommandMap.find(aString) == sCommandMap.end()) { if(sCommandMap.find(aString) == sCommandMap.end()) {
DebugTrace("sendCommand failed: command not registered"); DebugTrace("sendCommand failed: command not registered");
return false; return false;
} }
aString = aString + "\n"; aString = "<" + aString + ">" + "\n" + payload + "\n" + "<" + aString + "/>";
toSend << aString; toSend << aString;
return true; return true;
} }
void JNetwork::registerCommand(string command, processCmd processCommand, processCmd processResponse) void JNetwork::registerCommand(string command, void* object, processCmd processCommand, processCmd processResponse)
{ {
sCommandMap[command + "Command"] = processCommand; CommandStruc struc;
sCommandMap[command + "Response"] = processResponse; struc.object = object;
struc.command = command;
struc.processCommand = processCommand;
sCommandMap[command + "Request"] = struc;
struc.processCommand = processResponse;
sCommandMap[command + "Response"] = struc;
}
void JNetwork::Update()
{
boost::mutex::scoped_lock r(receiveMutex);
// Checking for some command to execute
size_t begin_start_tag = received.str().find("<");
size_t end_start_tag = received.str().find(">");
string command = received.str().substr(begin_start_tag+1, end_start_tag-(begin_start_tag+1));
size_t begin_end_tag = received.str().find(command + "/>");
size_t end_end_tag = received.str().find("/>");
if(begin_start_tag != string::npos && begin_end_tag != string::npos )
{
map<string, CommandStruc>::iterator ite = sCommandMap.find(command);
if(ite != sCommandMap.end())
{
DebugTrace("begin of command received : " + received.str() );
DebugTrace("begin of command toSend : " + toSend.str() );
processCmd theMethod = (ite)->second.processCommand;
stringstream input(received.str().substr(end_start_tag+1, (begin_end_tag-1)-(end_start_tag+1)));
stringstream output;
theMethod((ite)->second.object, input, output);
string aString = received.str().substr(end_end_tag+2, string::npos);
received.str(aString);
if(output.str().size())
sendCommand((ite)->second.command, output.str(), "Response");
DebugTrace("end of command received : "<< received.str() );
DebugTrace("end of command toSend : "<< toSend.str() );
}
}
} }
void JNetwork::ThreadProc(void* param) void JNetwork::ThreadProc(void* param)
@@ -105,64 +159,25 @@ void JNetwork::ThreadProc(void* param)
} }
while(pSocket && pSocket->isConnected()) { while(pSocket && pSocket->isConnected()) {
char buff[1024]; char buff[4096];
{ {
boost::mutex::scoped_lock l(pThis->receiveMutex); boost::mutex::scoped_lock l(pThis->receiveMutex);
int len = pSocket->Read(buff, sizeof(buff)); int len = pSocket->Read(buff, sizeof(buff));
if(len) { if(len > 0) {
DebugTrace("receiving " << len << " bytes : " << buff); DebugTrace("receiving " << len << " bytes : " << buff);
pThis->received << buff; pThis->received.str(pThis->received.str() + buff);
} DebugTrace("received " << pThis->received.str().size() << " bytes : " << pThis->received.str());
// Checking for some command to execute
size_t found = pThis->received.str().find("Command");
if(found != string::npos)
{
map<string, processCmd>::iterator ite = sCommandMap.find((pThis->received.str()).substr(0, found) + "Command");
if(ite != sCommandMap.end())
{
DebugTrace("begin of command received : "<< pThis->received.str() );
DebugTrace("begin of command toSend : "<< pThis->toSend.str() );
boost::mutex::scoped_lock l(pThis->sendMutex);
pThis->toSend << pThis->received.str().substr(0, found) + "Response ";
pThis->received.str("");
processCmd theMethod = (ite)->second;
theMethod(pThis->received, pThis->toSend);
DebugTrace("end of command received : "<< pThis->received.str() );
DebugTrace("end of command toSend : "<< pThis->toSend.str() );
}
}
// Checking for some response to execute
found = pThis->received.str().find("Response");
if(found != string::npos)
{
map<string, processCmd>::iterator ite = sCommandMap.find((pThis->received.str()).substr(0, found) + "Response");
if(ite != sCommandMap.end())
{
DebugTrace("begin of response received : "<< pThis->received.str() );
DebugTrace("begin of response toSend : "<< pThis->toSend.str() );
boost::mutex::scoped_lock l(pThis->sendMutex);
string aString;
pThis->received >> aString;
processCmd theMethod = (ite)->second;
theMethod(pThis->received, pThis->toSend);
pThis->received.str("");
DebugTrace("end of response received : "<< pThis->received.str() );
DebugTrace("end of response toSend : "<< pThis->toSend.str() );
}
} }
} }
{
boost::mutex::scoped_lock l(pThis->sendMutex); boost::mutex::scoped_lock l(pThis->sendMutex);
if(!pThis->toSend.str().empty()) if(!pThis->toSend.str().empty())
{ {
DebugTrace("sending " << pThis->toSend.str().size() << " bytes : " << pThis->toSend.str()); DebugTrace("sending " << pThis->toSend.str().size() << " bytes : " << pThis->toSend.str());
pSocket->Write((char*)pThis->toSend.str().c_str(), pThis->toSend.str().size()+1); pSocket->Write((char*)pThis->toSend.str().c_str(), pThis->toSend.str().size()+1);
pThis->toSend.str(""); pThis->toSend.str("");
} }
}
} }
DebugTrace("Quitting Thread"); DebugTrace("Quitting Thread");

View File

@@ -264,9 +264,17 @@ int JSocket::Read(char* buff, int size)
#endif //WINDOWS #endif //WINDOWS
if(readbytes < 0) if(readbytes < 0)
{ {
DebugTrace("Error reading from socket\n"); #ifdef WIN32
DebugTrace("Error reading from socket: " << WSAGetLastError());
#endif //WINDOWS
Disconnect();
return -1; return -1;
} }
else if(readbytes == 0)
{
Disconnect();
return 0;
}
else else
return readbytes; return readbytes;
} }
@@ -303,6 +311,7 @@ int JSocket::Write(char* buff, int size)
} }
else if (result < 0) else if (result < 0)
{ {
Disconnect();
return -1; return -1;
} }
} }

View File

@@ -12,7 +12,9 @@
#include "GuiStatic.h" #include "GuiStatic.h"
#include <queue> #include <queue>
#include <time.h> #include <time.h>
#ifdef NETWORK_SUPPORT
#include "JNetwork.h"
#endif //NETWORK_SUPPORT
class MTGGamePhase; class MTGGamePhase;
class MTGAbility; class MTGAbility;
@@ -42,13 +44,15 @@ class GameObserver{
JGE* mJGE; JGE* mJGE;
DeckManager* mDeckManager; DeckManager* mDeckManager;
Player * gameOver; Player * gameOver;
GamePhase mCurrentGamePhase;
int untap(MTGCardInstance * card); int untap(MTGCardInstance * card);
bool WaitForExtraPayment(MTGCardInstance* card); bool WaitForExtraPayment(MTGCardInstance* card);
void cleanup(); void cleanup();
string startupGameSerialized; string startupGameSerialized;
bool parseLine(const string& s); bool parseLine(const string& s);
void logAction(const string& s); virtual void logAction(const string& s);
bool processAction(const string& s, bool swapPlayer = false);
bool processActions(bool undo bool processActions(bool undo
#ifdef TESTSUITE #ifdef TESTSUITE
, TestSuiteGame* testgame , TestSuiteGame* testgame
@@ -58,7 +62,7 @@ class GameObserver{
bool mLoading; bool mLoading;
void nextGamePhase(); void nextGamePhase();
void shuffleLibrary(Player* p); void shuffleLibrary(Player* p);
void createPlayer(const string& playerMode Player* createPlayer(const string& playerMode
#ifdef TESTSUITE #ifdef TESTSUITE
, TestSuiteGame* testgame , TestSuiteGame* testgame
#endif //TESTSUITE #endif //TESTSUITE
@@ -73,7 +77,6 @@ class GameObserver{
PhaseRing * phaseRing; PhaseRing * phaseRing;
vector<list<Phase*> >gameTurn; vector<list<Phase*> >gameTurn;
int cancelCurrentAction(); int cancelCurrentAction();
GamePhase currentGamePhase;
ExtraCosts * mExtraPayment; ExtraCosts * mExtraPayment;
int oldGamePhase; int oldGamePhase;
TargetChooser * targetChooser; TargetChooser * targetChooser;
@@ -85,10 +88,7 @@ class GameObserver{
MTGCardInstance* ExtraRules; MTGCardInstance* ExtraRules;
Trash* mTrash; Trash* mTrash;
GameType gameType() const GameType gameType() const { return mGameType; };
{
return mGameType;
};
TargetChooser * getCurrentTargetChooser(); TargetChooser * getCurrentTargetChooser();
void stackObjectClicked(Interruptible * action); void stackObjectClicked(Interruptible * action);
@@ -97,6 +97,7 @@ class GameObserver{
int cardClick(MTGCardInstance * card, int abilityType); int cardClick(MTGCardInstance * card, int abilityType);
int cardClick(MTGCardInstance * card,Targetable * _object = NULL, bool log = true); int cardClick(MTGCardInstance * card,Targetable * _object = NULL, bool log = true);
GamePhase getCurrentGamePhase(); GamePhase getCurrentGamePhase();
void setCurrentGamePhase(GamePhase phase) { mCurrentGamePhase = phase; };
const char * getCurrentGamePhaseName(); const char * getCurrentGamePhaseName();
const char * getNextGamePhaseName(); const char * getNextGamePhaseName();
void nextCombatStep(); void nextCombatStep();
@@ -107,7 +108,7 @@ class GameObserver{
#ifdef TESTSUITE #ifdef TESTSUITE
void loadTestSuitePlayer(int playerId, TestSuiteGame* testSuite); void loadTestSuitePlayer(int playerId, TestSuiteGame* testSuite);
#endif //TESTSUITE #endif //TESTSUITE
void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false); virtual void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false);
void loadPlayer(int playerId, Player* player); void loadPlayer(int playerId, Player* player);
Player * currentPlayer; Player * currentPlayer;
@@ -117,7 +118,7 @@ class GameObserver{
Player * nextTurnsPlayer(); Player * nextTurnsPlayer();
Player * currentlyActing(); Player * currentlyActing();
GameObserver(WResourceManager* output = 0, JGE* input = 0); GameObserver(WResourceManager* output = 0, JGE* input = 0);
~GameObserver(); virtual ~GameObserver();
void gameStateBasedEffects(); void gameStateBasedEffects();
void enchantmentStatus(); void enchantmentStatus();
void Affinity(); void Affinity();
@@ -129,7 +130,7 @@ class GameObserver{
int isInPlay(MTGCardInstance * card); int isInPlay(MTGCardInstance * card);
int isInGrave(MTGCardInstance * card); int isInGrave(MTGCardInstance * card);
int isInExile(MTGCardInstance * card); int isInExile(MTGCardInstance * card);
void Update(float dt); virtual void Update(float dt);
void Render(); void Render();
void ButtonPressed(PlayGuiObject*); void ButtonPressed(PlayGuiObject*);
int getPlayersNumber() {return players.size();}; int getPlayersNumber() {return players.size();};
@@ -181,4 +182,27 @@ class GameObserver{
}; };
}; };
#ifdef NETWORK_SUPPORT
class NetworkGameObserver : public GameObserver
{
protected:
JNetwork* mpNetworkSession;
bool mSynchronized;
bool mForwardAction;
virtual void logAction(const string& s);
public:
// no serverIp means a server is being instantiated, otherwise a client
NetworkGameObserver(JNetwork* pNetwork, WResourceManager* output = 0, JGE* input = 0);
virtual ~NetworkGameObserver();
virtual void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false);
virtual void Update(float dt);
void synchronize();
static void loadPlayer(void*pThis, stringstream& in, stringstream& out);
static void sendAction(void*pThis, stringstream& in, stringstream& out);
static void synchronize(void*pThis, stringstream& in, stringstream& out);
static void ignoreResponse(void*pThis, stringstream& in, stringstream& out){};
};
#endif
#endif #endif

View File

@@ -15,7 +15,7 @@ protected:
static ProxyPlayer* mInstance; static ProxyPlayer* mInstance;
public: public:
ProxyPlayer(Player* pxPlayer, JNetwork* pxNetwork); ProxyPlayer(Player* pxPlayer, JNetwork* pxNetwork);
static void Serialize(istream& in, ostream& out); static void Serialize(void*, stringstream& in, stringstream& out);
}; };
@@ -25,8 +25,8 @@ protected:
JNetwork* mpNetwork; JNetwork* mpNetwork;
static RemotePlayer* mInstance; static RemotePlayer* mInstance;
public: public:
RemotePlayer(JNetwork*); RemotePlayer(GameObserver* observer, JNetwork*);
static void Deserialize(istream& in, ostream& out); static void Deserialize(void*, stringstream& in, stringstream& out);
bool isLoaded() {return game!=NULL;}; bool isLoaded() {return game!=NULL;};
}; };

View File

@@ -102,6 +102,7 @@ public:
std::string GetCurrentDeckStatsFile(); std::string GetCurrentDeckStatsFile();
virtual bool parseLine(const string& s); virtual bool parseLine(const string& s);
friend ostream& operator<<(ostream&, const Player&); friend ostream& operator<<(ostream&, const Player&);
friend istream& operator>>(istream&, Player&);
bool operator<(Player& aPlayer); bool operator<(Player& aPlayer);
bool isDead(); bool isDead();
}; };

View File

@@ -75,7 +75,7 @@ GameApp::GameApp() :
mCurrentState = NULL; mCurrentState = NULL;
mNextState = NULL; mNextState = NULL;
rules = 0;
music = NULL; music = NULL;
} }

View File

@@ -15,9 +15,14 @@
#include "Trash.h" #include "Trash.h"
#include "DeckManager.h" #include "DeckManager.h"
#include "GuiCombat.h" #include "GuiCombat.h"
#include <algorithm>
#ifdef TESTSUITE #ifdef TESTSUITE
#include "TestSuiteAI.h" #include "TestSuiteAI.h"
#endif #endif
#ifdef NETWORK_SUPPORT
#include "NetworkPlayer.h"
#endif
void GameObserver::cleanup() void GameObserver::cleanup()
{ {
@@ -35,7 +40,7 @@ void GameObserver::cleanup()
currentActionPlayer = NULL; currentActionPlayer = NULL;
isInterrupting = NULL; isInterrupting = NULL;
currentPlayerId = 0; currentPlayerId = 0;
currentGamePhase = MTG_PHASE_INVALID; mCurrentGamePhase = MTG_PHASE_INVALID;
targetChooser = NULL; targetChooser = NULL;
cardWaitingForTargets = NULL; cardWaitingForTargets = NULL;
mExtraPayment = NULL; mExtraPayment = NULL;
@@ -51,6 +56,7 @@ void GameObserver::cleanup()
GameObserver::~GameObserver() GameObserver::~GameObserver()
{ {
LOG("==Destroying GameObserver=="); LOG("==Destroying GameObserver==");
for (size_t i = 0; i < players.size(); ++i) for (size_t i = 0; i < players.size(); ++i)
{ {
players[i]->End(); players[i]->End();
@@ -83,7 +89,7 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input)
currentActionPlayer = NULL; currentActionPlayer = NULL;
isInterrupting = NULL; isInterrupting = NULL;
currentPlayerId = 0; currentPlayerId = 0;
currentGamePhase = MTG_PHASE_INVALID; mCurrentGamePhase = MTG_PHASE_INVALID;
targetChooser = NULL; targetChooser = NULL;
cardWaitingForTargets = NULL; cardWaitingForTargets = NULL;
mExtraPayment = NULL; mExtraPayment = NULL;
@@ -101,17 +107,17 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input)
GamePhase GameObserver::getCurrentGamePhase() GamePhase GameObserver::getCurrentGamePhase()
{ {
return currentGamePhase; return mCurrentGamePhase;
} }
const char* GameObserver::getCurrentGamePhaseName() const char* GameObserver::getCurrentGamePhaseName()
{ {
return phaseRing->phaseName(currentGamePhase); return phaseRing->phaseName(mCurrentGamePhase);
} }
const char* GameObserver::getNextGamePhaseName() const char* GameObserver::getNextGamePhaseName()
{ {
return phaseRing->phaseName((currentGamePhase + 1) % MTG_PHASE_CLEANUP); return phaseRing->phaseName((mCurrentGamePhase + 1) % MTG_PHASE_CLEANUP);
} }
Player * GameObserver::opponent() Player * GameObserver::opponent()
@@ -182,18 +188,18 @@ void GameObserver::nextGamePhase()
} }
Phase * cPhase = phaseRing->getCurrentPhase(); Phase * cPhase = phaseRing->getCurrentPhase();
currentGamePhase = cPhase->id; mCurrentGamePhase = cPhase->id;
if (MTG_PHASE_COMBATDAMAGE == currentGamePhase) if (MTG_PHASE_COMBATDAMAGE == mCurrentGamePhase)
nextCombatStep(); nextCombatStep();
if (MTG_PHASE_COMBATEND == currentGamePhase) if (MTG_PHASE_COMBATEND == mCurrentGamePhase)
combatStep = BLOCKERS; combatStep = BLOCKERS;
//if (currentPlayer != cPhase->player) //if (currentPlayer != cPhase->player)
// nextPlayer();//depreciated; we call this at EOT step now. unsure what the purpose of this was originally.fix for a bug? // nextPlayer();//depreciated; we call this at EOT step now. unsure what the purpose of this was originally.fix for a bug?
//init begin of turn //init begin of turn
if (currentGamePhase == MTG_PHASE_BEFORE_BEGIN) if (mCurrentGamePhase == MTG_PHASE_BEFORE_BEGIN)
{ {
cleanupPhase(); cleanupPhase();
currentPlayer->damageCount = 0; currentPlayer->damageCount = 0;
@@ -211,7 +217,7 @@ void GameObserver::nextGamePhase()
return nextGamePhase(); return nextGamePhase();
} }
if (currentGamePhase == MTG_PHASE_AFTER_EOT) if (mCurrentGamePhase == MTG_PHASE_AFTER_EOT)
{ {
//Auto Hand cleaning, in case the player didn't do it himself //Auto Hand cleaning, in case the player didn't do it himself
while (currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false) while (currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false)
@@ -228,7 +234,7 @@ void GameObserver::nextGamePhase()
} }
//Phase Specific actions //Phase Specific actions
switch (currentGamePhase) switch (mCurrentGamePhase)
{ {
case MTG_PHASE_UNTAP: case MTG_PHASE_UNTAP:
DebugTrace("Untap Phase ------------- Turn " << turn ); DebugTrace("Untap Phase ------------- Turn " << turn );
@@ -281,7 +287,7 @@ void GameObserver::userRequestNextGamePhase(bool allowInterrupt, bool log)
{ {
if(log) { if(log) {
stringstream stream; stringstream stream;
stream << "next " << allowInterrupt << " " <<currentGamePhase; stream << "next " << allowInterrupt << " " <<mCurrentGamePhase;
logAction(currentPlayer, stream.str()); logAction(currentPlayer, stream.str());
} }
@@ -308,8 +314,8 @@ void GameObserver::userRequestNextGamePhase(bool allowInterrupt, bool log)
|| (cPhaseOld->id == MTG_PHASE_COMBATBLOCKERS && combatStep == TRIGGERS) || (cPhaseOld->id == MTG_PHASE_COMBATBLOCKERS && combatStep == TRIGGERS)
|| (cPhaseOld->id == MTG_PHASE_COMBATDAMAGE) || (cPhaseOld->id == MTG_PHASE_COMBATDAMAGE)
|| opponent()->isAI() || opponent()->isAI()
|| options[Options::optionInterrupt(currentGamePhase)].number || options[Options::optionInterrupt(mCurrentGamePhase)].number
|| currentPlayer->offerInterruptOnPhase - 1 == currentGamePhase || currentPlayer->offerInterruptOnPhase - 1 == mCurrentGamePhase
)) ))
{ {
mLayers->stackLayer()->AddNextGamePhase(); mLayers->stackLayer()->AddNextGamePhase();
@@ -480,7 +486,7 @@ bool GameObserver::operator==(const GameObserver& aGame)
{ {
int error = 0; int error = 0;
if (aGame.currentGamePhase != currentGamePhase) if (aGame.mCurrentGamePhase != mCurrentGamePhase)
{ {
error++; error++;
} }
@@ -544,7 +550,7 @@ void GameObserver::dumpAssert(bool val)
void GameObserver::Update(float dt) void GameObserver::Update(float dt)
{ {
Player * player = currentPlayer; Player * player = currentPlayer;
if (MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) if (MTG_PHASE_COMBATBLOCKERS == mCurrentGamePhase && BLOCKERS == combatStep)
{ {
player = player->opponent(); player = player->opponent();
} }
@@ -567,7 +573,7 @@ void GameObserver::Update(float dt)
} }
gameStateBasedEffects(); gameStateBasedEffects();
} }
oldGamePhase = currentGamePhase; oldGamePhase = mCurrentGamePhase;
} }
//applies damage to creatures after updates //applies damage to creatures after updates
@@ -649,7 +655,7 @@ void GameObserver::gameStateBasedEffects()
////////////////////////// //////////////////////////
//handles phasing events// //handles phasing events//
////////////////////////// //////////////////////////
if(card->has(Constants::PHASING)&& currentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn && !card->isPhased) if(card->has(Constants::PHASING)&& mCurrentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn && !card->isPhased)
{ {
card->isPhased = true; card->isPhased = true;
card->phasedTurn = turn; card->phasedTurn = turn;
@@ -657,7 +663,7 @@ void GameObserver::gameStateBasedEffects()
card->view->alpha = 50; card->view->alpha = 50;
card->initAttackersDefensers(); card->initAttackersDefensers();
} }
else if((card->has(Constants::PHASING) || card->isPhased)&& currentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn) else if((card->has(Constants::PHASING) || card->isPhased)&& mCurrentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn)
{ {
card->isPhased = false; card->isPhased = false;
card->phasedTurn = turn; card->phasedTurn = turn;
@@ -761,7 +767,7 @@ void GameObserver::gameStateBasedEffects()
///////////////////////////////////////////////// /////////////////////////////////////////////////
//handle end of turn effects while we're at it.// //handle end of turn effects while we're at it.//
///////////////////////////////////////////////// /////////////////////////////////////////////////
if (currentGamePhase == MTG_PHASE_ENDOFTURN+1) if (mCurrentGamePhase == MTG_PHASE_ENDOFTURN+1)
{ {
for (int j = 0; j < nbcards; ++j) for (int j = 0; j < nbcards; ++j)
{ {
@@ -860,17 +866,17 @@ void GameObserver::gameStateBasedEffects()
if (skipLevel == Constants::ASKIP_SAFE || skipLevel == Constants::ASKIP_FULL) if (skipLevel == Constants::ASKIP_SAFE || skipLevel == Constants::ASKIP_FULL)
{ {
if ((opponent()->isAI() && !(isInterrupting)) && ((currentGamePhase == MTG_PHASE_UNTAP) if ((opponent()->isAI() && !(isInterrupting)) && ((mCurrentGamePhase == MTG_PHASE_UNTAP)
|| (currentGamePhase == MTG_PHASE_DRAW) || (currentGamePhase == MTG_PHASE_COMBATBEGIN) || (mCurrentGamePhase == MTG_PHASE_DRAW) || (mCurrentGamePhase == MTG_PHASE_COMBATBEGIN)
|| ((currentGamePhase == MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0)) || ((mCurrentGamePhase == MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0))
|| currentGamePhase == MTG_PHASE_COMBATEND || currentGamePhase == MTG_PHASE_ENDOFTURN || mCurrentGamePhase == MTG_PHASE_COMBATEND || mCurrentGamePhase == MTG_PHASE_ENDOFTURN
|| ((currentGamePhase == MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8)))) || ((mCurrentGamePhase == MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8))))
userRequestNextGamePhase(); userRequestNextGamePhase();
} }
if (skipLevel == Constants::ASKIP_FULL) if (skipLevel == Constants::ASKIP_FULL)
{ {
if ((opponent()->isAI() && !(isInterrupting)) && (currentGamePhase == MTG_PHASE_UPKEEP if ((opponent()->isAI() && !(isInterrupting)) && (mCurrentGamePhase == MTG_PHASE_UPKEEP
|| currentGamePhase == MTG_PHASE_COMBATDAMAGE)) || mCurrentGamePhase == MTG_PHASE_COMBATDAMAGE))
userRequestNextGamePhase(); userRequestNextGamePhase();
} }
} }
@@ -1316,7 +1322,7 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object, bool lo
} }
//Current player's hand //Current player's hand
if (currentPlayer->game->hand->hasCard(card) && currentGamePhase == MTG_PHASE_CLEANUP if (currentPlayer->game->hand->hasCard(card) && mCurrentGamePhase == MTG_PHASE_CLEANUP
&& currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false) && currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false)
{ {
WEvent * e = NEW WEventCardDiscard(currentPlayer->game->hand->cards[0]); WEvent * e = NEW WEventCardDiscard(currentPlayer->game->hand->cards[0]);
@@ -1475,8 +1481,8 @@ ostream& operator<<(ostream& out, const GameObserver& g)
{ {
out << "[init]" << endl; out << "[init]" << endl;
out << "player=" << g.currentPlayerId + 1 << endl; out << "player=" << g.currentPlayerId + 1 << endl;
if(g.currentGamePhase != -1) if(g.mCurrentGamePhase != MTG_PHASE_INVALID)
out << "phase=" << g.phaseRing->phaseName(g.currentGamePhase) << endl; out << "phase=" << g.phaseRing->phaseName(g.mCurrentGamePhase) << endl;
out << "[player1]" << endl; out << "[player1]" << endl;
out << *(g.players[0]) << endl; out << *(g.players[0]) << endl;
out << "[player2]" << endl; out << "[player2]" << endl;
@@ -1518,7 +1524,7 @@ bool GameObserver::parseLine(const string& s)
} }
else if (areaS.compare("phase") == 0) else if (areaS.compare("phase") == 0)
{ {
currentGamePhase = PhaseRing::phaseStrToInt(s.substr(limiter + 1).c_str()); mCurrentGamePhase = PhaseRing::phaseStrToInt(s.substr(limiter + 1).c_str());
return true; return true;
} }
} }
@@ -1630,7 +1636,7 @@ bool GameObserver::load(const string& ss, bool undo
mRules->initGame(this); mRules->initGame(this);
phaseRing->goToPhase(0, currentPlayer, false); phaseRing->goToPhase(0, currentPlayer, false);
phaseRing->goToPhase(currentGamePhase, currentPlayer); phaseRing->goToPhase(mCurrentGamePhase, currentPlayer);
#ifdef TESTSUITE #ifdef TESTSUITE
if(testgame) if(testgame)
@@ -1654,6 +1660,63 @@ bool GameObserver::load(const string& ss, bool undo
return true; return true;
} }
bool GameObserver::processAction(const string& s, bool swapPlayer)
{
Player* p = (swapPlayer)?players[0]:players[1];
if (s.find("p1") != string::npos)
p = (swapPlayer)?players[1]:players[0];
MTGGameZone* zone = NULL;
if(s.find(string(p->game->hand->getName())+"[") != string::npos)
zone = p->game->hand;
else if(s.find(string(p->game->battlefield->getName())+"[") != string::npos)
zone = p->game->battlefield;
else if(s.find(string(p->game->graveyard->getName())+"[") != string::npos)
zone = p->game->graveyard;
else if(s.find(string(p->game->library->getName())+"[") != string::npos)
zone = p->game->library;
if(zone) {
size_t begin = s.find("[")+1;
size_t size = s.find("]")-begin;
size_t index = atoi(s.substr(begin, size).c_str());
dumpAssert(index < zone->cards.size());
cardClick(zone->cards[index], zone->cards[index]);
} else if (s.find("stack") != string::npos) {
size_t begin = s.find("[")+1;
size_t size = s.find("]")-begin;
size_t index = atoi(s.substr(begin, size).c_str());
stackObjectClicked((Interruptible*)mLayers->stackLayer()->getByIndex(index));
} else if (s.find("yes") != string::npos) {
mLayers->stackLayer()->setIsInterrupting(p);
} else if (s.find("no") != string::npos) {
mLayers->stackLayer()->cancelInterruptOffer();
} else if (s.find("endinterruption") != string::npos) {
mLayers->stackLayer()->endOfInterruption();
} else if (s.find("next") != string::npos) {
userRequestNextGamePhase();
} else if (s.find("combatok") != string::npos) {
mLayers->combatLayer()->clickOK();
} else if (s == "p1" || s == "p2") {
cardClick(NULL, p);
} else if (s.find("choice") != string::npos) {
int choice = atoi(s.substr(s.find("choice ") + 7).c_str());
mLayers->actionLayer()->doReactTo(choice);
} else if (s == "p1" || s == "p2") {
cardClick(NULL, p);
} else if(s.find("mulligan") != string::npos) {
Mulligan(p);
} else if(s.find("shufflelib") != string::npos) {
// This should probably be differently and be automatically part of the ability triggered
// that would allow the AI to use it as well.
shuffleLibrary(p);
} else {
DebugTrace("no clue about: " + s);
}
return true;
}
bool GameObserver::processActions(bool undo bool GameObserver::processActions(bool undo
#ifdef TESTSUITE #ifdef TESTSUITE
, TestSuiteGame* testgame , TestSuiteGame* testgame
@@ -1680,7 +1743,7 @@ bool GameObserver::processActions(bool undo
// We fake here cause the initialization before caused mana pool reset events to be triggered // We fake here cause the initialization before caused mana pool reset events to be triggered
// So, we need them flushed to be able to set the manapool to whatever we need // So, we need them flushed to be able to set the manapool to whatever we need
Update(counter); GameObserver::Update(counter);
counter += 1.000f; counter += 1.000f;
#ifdef TESTSUITE #ifdef TESTSUITE
@@ -1692,65 +1755,14 @@ bool GameObserver::processActions(bool undo
for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++, cmdIndex++) for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++, cmdIndex++)
{ {
string s = *loadingite; processAction(*loadingite);
Player* p = players[1];
if (s.find("p1") != string::npos)
p = players[0];
MTGGameZone* zone = NULL;
if(s.find(string(p->game->hand->getName())+"[") != string::npos)
zone = p->game->hand;
else if(s.find(string(p->game->battlefield->getName())+"[") != string::npos)
zone = p->game->battlefield;
else if(s.find(string(p->game->graveyard->getName())+"[") != string::npos)
zone = p->game->graveyard;
else if(s.find(string(p->game->library->getName())+"[") != string::npos)
zone = p->game->library;
if(zone) {
size_t begin = s.find("[")+1;
size_t size = s.find("]")-begin;
size_t index = atoi(s.substr(begin, size).c_str());
dumpAssert(index < zone->cards.size());
cardClick(zone->cards[index], zone->cards[index]);
} else if (s.find("stack") != string::npos) {
size_t begin = s.find("[")+1;
size_t size = s.find("]")-begin;
size_t index = atoi(s.substr(begin, size).c_str());
stackObjectClicked((Interruptible*)mLayers->stackLayer()->getByIndex(index));
} else if (s.find("yes") != string::npos) {
mLayers->stackLayer()->setIsInterrupting(p);
} else if (s.find("no") != string::npos) {
mLayers->stackLayer()->cancelInterruptOffer();
} else if (s.find("endinterruption") != string::npos) {
mLayers->stackLayer()->endOfInterruption();
} else if (s.find("next") != string::npos) {
userRequestNextGamePhase();
} else if (s.find("combatok") != string::npos) {
mLayers->combatLayer()->clickOK();
} else if (s == "p1" || s == "p2") {
cardClick(NULL, p);
} else if (s.find("choice") != string::npos) {
int choice = atoi(s.substr(s.find("choice ") + 7).c_str());
mLayers->actionLayer()->doReactTo(choice);
} else if (s == "p1" || s == "p2") {
cardClick(NULL, p);
} else if(s.find("mulligan") != string::npos) {
Mulligan(p);
} else if(s.find("shufflelib") != string::npos) {
// This should probably be differently and be automatically part of the ability triggered
// that would allow the AI to use it as well.
shuffleLibrary(p);
} else {
dumpAssert(0);
}
size_t nb = actionsList.size(); size_t nb = actionsList.size();
for (int i = 0; i<6; i++) for (int i = 0; i<6; i++)
{ {
// let's fake an update // let's fake an update
Update(counter); GameObserver::Update(counter);
counter += 1.000f; counter += 1.000f;
} }
dumpAssert(actionsList.back() == *loadingite); dumpAssert(actionsList.back() == *loadingite);
@@ -1809,34 +1821,43 @@ void GameObserver::Mulligan(Player* player)
player->takeMulligan(); player->takeMulligan();
} }
void GameObserver::createPlayer(const string& playerMode Player* GameObserver::createPlayer(const string& playerMode
#ifdef TESTSUITE #ifdef TESTSUITE
, TestSuiteGame* testgame , TestSuiteGame* testgame
#endif //TESTSUITE #endif //TESTSUITE
) )
{ {
Player::Mode aMode = (Player::Mode)atoi(playerMode.c_str()); Player::Mode aMode = (Player::Mode)atoi(playerMode.c_str());
Player* pPlayer = 0;
switch(aMode) switch(aMode)
{ {
case Player::MODE_AI: case Player::MODE_AI:
AIPlayerFactory playerCreator; AIPlayerFactory playerCreator;
if(players.size()) if(players.size())
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), players[0])); pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), players[0]);
else else
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), 0)); pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), 0);
break; break;
case Player::MODE_HUMAN: case Player::MODE_HUMAN:
players.push_back(new HumanPlayer(this, "", "")); pPlayer = new HumanPlayer(this, "", "");
break; break;
case Player::MODE_TEST_SUITE: case Player::MODE_TEST_SUITE:
#ifdef TESTSUITE #ifdef TESTSUITE
if(players.size()) if(players.size())
players.push_back(new TestSuiteAI(testgame, 1)); pPlayer = new TestSuiteAI(testgame, 1);
else else
players.push_back(new TestSuiteAI(testgame, 0)); pPlayer = new TestSuiteAI(testgame, 0);
#endif //TESTSUITE #endif //TESTSUITE
break; break;
} }
if(pPlayer)
{
players.push_back(pPlayer);
}
return pPlayer;
} }
#ifdef TESTSUITE #ifdef TESTSUITE
@@ -1881,20 +1902,19 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b
sprintf(deckFileSmall, "player_deck%i", decknb); sprintf(deckFileSmall, "player_deck%i", decknb);
loadPlayer(playerId, NEW HumanPlayer(this, deckFile, deckFileSmall, premadeDeck)); loadPlayer(playerId, NEW HumanPlayer(this, deckFile, deckFileSmall, premadeDeck));
}
}
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
// FIXME, this is broken else if(playerType == PLAYER_TYPE_REMOTE)
if(isNetwork) {
{ //Player 0 is the human player
ProxyPlayer* mProxy; ProxyPlayer* mProxy;
mProxy = NEW ProxyPlayer(mPlayers[playerId], mParent->mpNetwork); mProxy = NEW ProxyPlayer(players[0], JNetwork::GetInstance());
}
} //Player 1 is the remote player
else loadPlayer(playerId, NEW RemotePlayer(this, JNetwork::GetInstance()));
{ //Remote player
loadPlayer(playerId, NEW RemotePlayer(mParent->mpNetwork));
#endif //NETWORK_SUPPORT
}
} }
#endif //NETWORK_SUPPORT
else else
{ //AI Player, chooses deck { //AI Player, chooses deck
AIPlayerFactory playerCreator; AIPlayerFactory playerCreator;
@@ -1928,3 +1948,91 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b
} }
} }
#ifdef NETWORK_SUPPORT
NetworkGameObserver::NetworkGameObserver(JNetwork* pNetwork, WResourceManager* output, JGE* input)
: GameObserver(output, input), mpNetworkSession(pNetwork), mSynchronized(false)
{
mpNetworkSession->registerCommand("loadPlayer", this, loadPlayer, ignoreResponse);
mpNetworkSession->registerCommand("synchronize", this, synchronize, ignoreResponse);
mpNetworkSession->registerCommand("sendAction", this, sendAction, ignoreResponse);
}
NetworkGameObserver::~NetworkGameObserver()
{
}
void NetworkGameObserver::Update(float dt)
{
mpNetworkSession->Update();
::GameObserver::Update(dt);
}
void NetworkGameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, bool premadeDeck)
{
GameObserver::loadPlayer(playerId, playerType, decknb, premadeDeck);
Player* player = getPlayer(playerId);
stringstream out;
out << *player;
mpNetworkSession->sendCommand("loadPlayer", out.str());
}
void NetworkGameObserver::loadPlayer(void*pxThis, stringstream& in, stringstream& out)
{
NetworkGameObserver* pThis = (NetworkGameObserver*)pxThis;
Player* pPlayer = 0;
string s;
while(std::getline(in, s))
{
if (s.find("mode=") == 0)
{
pPlayer = pThis->createPlayer(s.substr(5)
#ifdef TESTSUITE
, 0
#endif //TESTSUITE
);
}
if(pPlayer && (!pPlayer->parseLine(s)))
{
break;
}
}
}
void NetworkGameObserver::synchronize()
{
if(!mSynchronized && mpNetworkSession->isServer())
{
stringstream out;
out << *this;
mpNetworkSession->sendCommand("synchronize", out.str());
mSynchronized = true;
}
}
void NetworkGameObserver::synchronize(void*pxThis, stringstream& in, stringstream& out)
{
NetworkGameObserver* pThis = (NetworkGameObserver*)pxThis;
pThis->load(in.str());
// now, we need to swap players as player1 for host is player 2 for guest
std::swap(pThis->players[0], pThis->players[1]);
}
void NetworkGameObserver::sendAction(void*pxThis, stringstream& in, stringstream& out)
{
NetworkGameObserver* pThis = (NetworkGameObserver*)pxThis;
pThis->mForwardAction = false;
pThis->processAction(in.str(), true);
pThis->mForwardAction = true;
}
void NetworkGameObserver::logAction(const string& s)
{
GameObserver::logAction(s);
if(mForwardAction)
mpNetworkSession->sendCommand("sendAction", s);
}
#endif

View File

@@ -120,7 +120,17 @@ void GameStateDuel::Start()
renderer->EnableVSync(true); renderer->EnableVSync(true);
OpponentsDeckid = 0; OpponentsDeckid = 0;
game = NEW GameObserver(WResourceManager::Instance(), JGE::GetInstance());
#ifdef NETWORK_SUPPORT
if(!mParent->mpNetwork) {
#endif //NETWORK_SUPPORT
game = NEW GameObserver(WResourceManager::Instance(), JGE::GetInstance());
#ifdef NETWORK_SUPPORT
} else {
game = NEW NetworkGameObserver(mParent->mpNetwork, WResourceManager::Instance(), JGE::GetInstance());
}
#endif //NETWORK_SUPPORT
#ifdef TESTSUITE #ifdef TESTSUITE
SAFE_DELETE(testSuite); SAFE_DELETE(testSuite);
@@ -298,7 +308,7 @@ void GameStateDuel::ThreadProc(void* inParam)
observer.startGame(instance->mParent->gameType, instance->mParent->rules); observer.startGame(instance->mParent->gameType, instance->mParent->rules);
while(!observer.didWin()) while(!observer.didWin())
{ {
if(observer.turn == oldTurn && observer.currentGamePhase == oldPhase) if(observer.turn == oldTurn && observer.getCurrentGamePhase() == oldPhase)
{ {
stagnationCounter++; stagnationCounter++;
} }
@@ -453,6 +463,10 @@ void GameStateDuel::Update(float dt)
// That's mostly because of a legacy bug, where we use the update sequence for some things when we should use events (such as phase changes) // That's mostly because of a legacy bug, where we use the update sequence for some things when we should use events (such as phase changes)
mParent->rules->postUpdateInit(game); mParent->rules->postUpdateInit(game);
#ifdef NETWORK_SUPPORT
if(mParent->mpNetwork) ((NetworkGameObserver*)game)->synchronize();
#endif
if (game->didWin()) if (game->didWin())
{ {
if (game->players[1]->playMode != Player::MODE_TEST_SUITE) credits->compute(game, mParent); if (game->players[1]->playMode != Player::MODE_TEST_SUITE) credits->compute(game, mParent);
@@ -487,7 +501,10 @@ void GameStateDuel::Update(float dt)
#ifdef QT_CONFIG #ifdef QT_CONFIG
thread_count = QThread::idealThreadCount(); thread_count = QThread::idealThreadCount();
#endif
#else
thread_count = 4;
#endif
for(size_t i = 0; i < (thread_count); i++) for(size_t i = 0; i < (thread_count); i++)
mWorkerThread.push_back(boost::thread(ThreadProc, this)); mWorkerThread.push_back(boost::thread(ThreadProc, this));
} }
@@ -508,7 +525,7 @@ void GameStateDuel::Update(float dt)
int cardsinhand = game->currentPlayer->game->hand->nb_cards; int cardsinhand = game->currentPlayer->game->hand->nb_cards;
//almosthumane - mulligan //almosthumane - mulligan
if ((game->turn < 1) && (cardsinhand != 0) && game->currentGamePhase == MTG_PHASE_FIRSTMAIN if ((game->turn < 1) && (cardsinhand != 0) && game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
&& game->currentPlayer->game->inPlay->nb_cards == 0 && game->currentPlayer->game->graveyard->nb_cards == 0 && game->currentPlayer->game->inPlay->nb_cards == 0 && game->currentPlayer->game->graveyard->nb_cards == 0
&& game->currentPlayer->game->exile->nb_cards == 0 && game->currentlyActing() == (Player*)game->currentPlayer) //1st Play Check && game->currentPlayer->game->exile->nb_cards == 0 && game->currentlyActing() == (Player*)game->currentPlayer) //1st Play Check
//IF there was no play at the moment automatically mulligan //IF there was no play at the moment automatically mulligan
@@ -517,7 +534,7 @@ void GameStateDuel::Update(float dt)
} }
//END almosthumane - mulligan //END almosthumane - mulligan
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
#ifdef DEBUG #ifdef TESTSUITE
menu->Add(MENUITEM_UNDO, "Undo"); menu->Add(MENUITEM_UNDO, "Undo");
#endif #endif
#ifdef TESTSUITE #ifdef TESTSUITE
@@ -531,23 +548,23 @@ void GameStateDuel::Update(float dt)
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
case DUEL_STATE_OPPONENT_WAIT: case DUEL_STATE_OPPONENT_WAIT:
{ {
if(mPlayers[1] && mPlayers[1]->game) if(game->players.size() > 1)
{ // Player loaded { // Player loaded
menu->Close(); menu->Close();
SAFE_DELETE(menu); SAFE_DELETE(menu);
setGamePhase(DUEL_STATE_PLAY); setGamePhase(DUEL_STATE_PLAY);
} else if(menu == NULL) } else if(menu == NULL)
{ {
loadPlayer(1, 42/* 0 not good*/, false, true); menu = NEW SimpleMenu(JGE::GetInstance(), DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60);
menu = NEW SimpleMenu(DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60); if (menu)
if (menu) {
{ menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); }
} } else
} else {
{ menu->Update(dt);
menu->Update(dt); game->Update(dt);
} }
} }
break; break;
#endif //NETWORK_SUPPORT #endif //NETWORK_SUPPORT
@@ -732,10 +749,13 @@ void GameStateDuel::Render()
// display the player deck names in their respective corners // display the player deck names in their respective corners
string playerDeckName = game->players[0]->deckName; string playerDeckName = game->players[0]->deckName;
string opponentDeckName = game->players[1]->deckName;
float playerDeckNamePixelLength = mFont->GetStringWidth(playerDeckName.c_str()); float playerDeckNamePixelLength = mFont->GetStringWidth(playerDeckName.c_str());
mFont->DrawString( opponentDeckName, 0, 50);
mFont->DrawString( playerDeckName, SCREEN_WIDTH_F - playerDeckNamePixelLength, SCREEN_HEIGHT_F - 50); mFont->DrawString( playerDeckName, SCREEN_WIDTH_F - playerDeckNamePixelLength, SCREEN_HEIGHT_F - 50);
if(game->players.size()>1)
{
string opponentDeckName = game->players[1]->deckName;
mFont->DrawString( opponentDeckName, 0, 50);
}
} }
} }
} }

View File

@@ -558,15 +558,18 @@ void GameStateMenu::Update(float dt)
} }
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
case MENU_STATE_NETWORK_DEFINE: case MENU_STATE_NETWORK_DEFINE:
currentState = MENU_STATE_MAJOR_SUBMENU; if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR))
subMenuController = NEW SimpleMenu(MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60);
if (subMenuController)
{ {
subMenuController->Add(SUBMENUITEM_HOST_GAME, "Host a game"); currentState = MENU_STATE_MAJOR_SUBMENU;
subMenuController->Add(SUBMENUITEM_JOIN_GAME, "Join a game"); subMenuController = NEW SimpleMenu(JGE::GetInstance(), MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60);
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel"); if (subMenuController)
} {
break; subMenuController->Add(SUBMENUITEM_HOST_GAME, "Host a game");
subMenuController->Add(SUBMENUITEM_JOIN_GAME, "Join a game");
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel");
}
}
break;
case MENU_STATE_NETWORK_WAIT: case MENU_STATE_NETWORK_WAIT:
if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR)) if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR))
{ {
@@ -578,7 +581,7 @@ void GameStateMenu::Update(float dt)
else if(!subMenuController) else if(!subMenuController)
{ {
// currentState = MENU_STATE_MAJOR_SUBMENU; // currentState = MENU_STATE_MAJOR_SUBMENU;
subMenuController = NEW SimpleMenu(MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60); subMenuController = NEW SimpleMenu(JGE::GetInstance(), MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60);
if (subMenuController) if (subMenuController)
{ {
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel connection"); subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel connection");
@@ -840,7 +843,7 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
{ {
if(!mParent->mpNetwork) if(!mParent->mpNetwork)
{ {
mParent->mpNetwork = new JNetwork(); mParent->mpNetwork = JNetwork::GetInstance();
} }
mParent->mpNetwork->connect(); mParent->mpNetwork->connect();
subMenuController->Close(); subMenuController->Close();
@@ -851,16 +854,17 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
{ {
if(!mParent->mpNetwork) if(!mParent->mpNetwork)
{ {
mParent->mpNetwork = new JNetwork(); mParent->mpNetwork = JNetwork::GetInstance();
} }
// FIXME needs to be able to specify the server ip // FIXME needs to be able to specify the server ip
mParent->mpNetwork->connect("127.0.0.1"); mParent->mpNetwork->connect("127.0.0.1");
// we let the server choose the game mode // we let the server choose the game mode
mParent->gameType = GAME_TYPE_SLAVE; mParent->gameType = GAME_TYPE_SLAVE;
// just to select one, the HOST is in control here.
mParent->rules = Rules::getRulesByFilename("classic.txt");
hasChosenGameType = true; hasChosenGameType = true;
subMenuController->Close(); subMenuController->Close();
// currentState = MENU_STATE_MAJOR_DUEL | MENU_STATE_MINOR_SUBMENU_CLOSING; currentState = MENU_STATE_NETWORK_WAIT | MENU_STATE_MINOR_SUBMENU_CLOSING;
currentState = MENU_STATE_NETWORK_WAIT;
break; break;
} }
#endif //NETWORK_SUPPORT #endif //NETWORK_SUPPORT
@@ -878,10 +882,8 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
subMenuController->Close(); subMenuController->Close();
} }
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
if(mParent->mpNetwork) JNetwork::Destroy();
{ mParent->mpNetwork=0;
SAFE_DELETE(mParent->mpNetwork);
}
#endif //NETWORK_SUPPORT #endif //NETWORK_SUPPORT
currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_SUBMENU_CLOSING; currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_SUBMENU_CLOSING;
break; break;

View File

@@ -824,7 +824,7 @@ int MTGCardInstance::removeBlocker(MTGCardInstance * blocker)
// Blockers can be removed "manually" (by the blocking player) at the Blockers step, // Blockers can be removed "manually" (by the blocking player) at the Blockers step,
// Or "automatically" in the damage phase, when they die and regenerate (see http://code.google.com/p/wagic/issues/detail?id=563 ) // Or "automatically" in the damage phase, when they die and regenerate (see http://code.google.com/p/wagic/issues/detail?id=563 )
// In the second case, we still want the card to be marked as "blocked" this turn // In the second case, we still want the card to be marked as "blocked" this turn
if (!blockers.size() && observer->currentGamePhase == MTG_PHASE_COMBATBLOCKERS) if (!blockers.size() && observer->getCurrentGamePhase() == MTG_PHASE_COMBATBLOCKERS)
{ {
blocked = false; blocked = false;
} }

View File

@@ -288,7 +288,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
if (!player->game->hand->hasCard(card)) if (!player->game->hand->hasCard(card))
return 0; return 0;
if ((game->turn < 1) && (cardsinhand != 0) && (card->basicAbilities[(int)Constants::LEYLINE]) if ((game->turn < 1) && (cardsinhand != 0) && (card->basicAbilities[(int)Constants::LEYLINE])
&& game->currentGamePhase == MTG_PHASE_FIRSTMAIN && game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
&& game->players[0]->game->graveyard->nb_cards == 0 && game->players[0]->game->graveyard->nb_cards == 0
&& game->players[0]->game->exile->nb_cards == 0 && game->players[0]->game->exile->nb_cards == 0
) )
@@ -311,7 +311,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY)
return 0; return 0;
if (player == currentPlayer if (player == currentPlayer
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN || game->currentGamePhase == MTG_PHASE_SECONDMAIN) && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)
) )
{ {
return 1; return 1;
@@ -319,8 +319,8 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
} }
else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH)
|| (player == currentPlayer && !game->isInterrupting || (player == currentPlayer && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN)) || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
) )
{ {
@@ -644,15 +644,15 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY)
return 0; return 0;
if (player == currentPlayer if (player == currentPlayer
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN) || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)
) )
return 1; return 1;
} }
else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH)
|| (player == currentPlayer && !game->isInterrupting || (player == currentPlayer && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN)) || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
) )
{ {
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->stack) == PlayRestriction::CANT_PLAY) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->stack) == PlayRestriction::CANT_PLAY)
@@ -1039,8 +1039,8 @@ int MTGMorphCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
//note lands can morph too, this is different from other cost types. //note lands can morph too, this is different from other cost types.
if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == currentPlayer if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == currentPlayer
&& !game->isInterrupting && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN)) || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
) )
{ {
if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->stack) == PlayRestriction::CANT_PLAY) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->stack) == PlayRestriction::CANT_PLAY)
@@ -1640,8 +1640,8 @@ int MTGMomirRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
if (!player->game->hand->hasCard(card)) if (!player->game->hand->hasCard(card))
return 0; return 0;
if (player == currentPlayer && !game->isInterrupting if (player == currentPlayer && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN) || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)
) )
{ {
return 1; return 1;

View File

@@ -1,3 +1,4 @@
#include "PrecompiledHeader.h"
#include "NetworkPlayer.h" #include "NetworkPlayer.h"
#include <sstream> #include <sstream>
@@ -10,14 +11,14 @@ void RegisterNetworkPlayers()
} }
RemotePlayer::RemotePlayer(JNetwork* pxNetwork) RemotePlayer::RemotePlayer(GameObserver* observer, JNetwork* pxNetwork)
: Player("remote", "", NULL), mpNetwork(pxNetwork) : Player(observer, "remote", "", NULL), mpNetwork(pxNetwork)
{ {
mInstance = this; mInstance = this;
mpNetwork->sendCommand("GetPlayer"); mpNetwork->sendCommand("GetPlayer");
} }
void RemotePlayer::Deserialize(istream& in, ostream& out) void RemotePlayer::Deserialize(void*, stringstream& in, stringstream& out)
{ {
// istringstream ss(mInstance->mpNetwork->receiveString()); // istringstream ss(mInstance->mpNetwork->receiveString());
in >> *mInstance; in >> *mInstance;
@@ -28,14 +29,14 @@ ProxyPlayer::ProxyPlayer(Player* pxPlayer, JNetwork* pxNetwork)
: mpPlayer(pxPlayer), mpNetwork(pxNetwork) : mpPlayer(pxPlayer), mpNetwork(pxNetwork)
{ {
mInstance = this; mInstance = this;
JNetwork::registerCommand("GetPlayer", ProxyPlayer::Serialize, RemotePlayer::Deserialize); JNetwork::registerCommand("GetPlayer", this, ProxyPlayer::Serialize, RemotePlayer::Deserialize);
// ostringstream ss; // ostringstream ss;
// ss << "Player : " << *mpPlayer; // ss << "Player : " << *mpPlayer;
// mpNetwork->send(ss.str()); // mpNetwork->send(ss.str());
} }
void ProxyPlayer::Serialize(istream& in, ostream& out) void ProxyPlayer::Serialize(void*, stringstream& in, stringstream& out)
{ {
out << *(mInstance->mpPlayer); out << *(mInstance->mpPlayer);
} }

View File

@@ -243,6 +243,11 @@ bool Player::parseLine(const string& s)
ManaCost::parseManaCost(s.substr(limiter + 1), manaPool); ManaCost::parseManaCost(s.substr(limiter + 1), manaPool);
return true; return true;
} }
else if (areaS.compare("mode") == 0)
{
this->playMode = (Player::Mode)atoi(s.substr(limiter + 1).c_str());
return true;
}
else if (areaS.compare("avatar") == 0) else if (areaS.compare("avatar") == 0)
{ {
mAvatarName = s.substr(limiter + 1); mAvatarName = s.substr(limiter + 1);
@@ -326,9 +331,12 @@ ostream& operator<<(ostream& out, const Player& p)
{ {
out << "mode=" << p.playMode << endl; out << "mode=" << p.playMode << endl;
out << *(Damageable*)&p; out << *(Damageable*)&p;
string manapoolstring = p.manaPool->toString(); if(p.manaPool)
if(manapoolstring != "") {
out << "manapool=" << manapoolstring << endl; string manapoolstring = p.manaPool->toString();
if(manapoolstring != "")
out << "manapool=" << manapoolstring << endl;
}
if(p.mAvatarName != "") if(p.mAvatarName != "")
out << "avatar=" << p.mAvatarName << endl; out << "avatar=" << p.mAvatarName << endl;
if(p.phaseRing != "") if(p.phaseRing != "")
@@ -348,6 +356,22 @@ ostream& operator<<(ostream& out, const Player& p)
return out; return out;
} }
istream& operator>>(istream& in, Player& p)
{
string s;
while(std::getline(in, s))
{
if(!p.parseLine(s))
{
break;
}
}
return in;
}
// Method comparing "this" to "aPlayer", each in their own gameObserver // Method comparing "this" to "aPlayer", each in their own gameObserver
bool Player::operator<(Player& aPlayer) bool Player::operator<(Player& aPlayer)
{ {

View File

@@ -159,9 +159,9 @@ void Rules::addExtraRules(GameObserver* g)
if (p->playMode != Player::MODE_TEST_SUITE && g->mRules->gamemode != GAME_TYPE_MOMIR && g->mRules->gamemode if (p->playMode != Player::MODE_TEST_SUITE && g->mRules->gamemode != GAME_TYPE_MOMIR && g->mRules->gamemode
!= GAME_TYPE_RANDOM1 && g->mRules->gamemode != GAME_TYPE_RANDOM2 && g->mRules->gamemode != GAME_TYPE_RANDOM1 && g->mRules->gamemode != GAME_TYPE_RANDOM2 && g->mRules->gamemode
!= GAME_TYPE_STORY && != GAME_TYPE_STORY &&
g->mRules->gamemode != GAME_TYPE_DEMO && (!g->players[0] == PLAYER_TYPE_CPU && !g->players[1] == PLAYER_TYPE_CPU) g->mRules->gamemode != GAME_TYPE_DEMO && (!g->players[0]->playMode == PLAYER_TYPE_CPU && !g->players[1]->playMode == PLAYER_TYPE_CPU)
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
&& !g->players[1] == PLAYER_TYPE_REMOTE && !(g->players[1]->playMode == PLAYER_TYPE_REMOTE) && !(g->players[1]->playMode == PLAYER_TYPE_HUMAN)
#endif //NETWORK_SUPPORT #endif //NETWORK_SUPPORT
)//keep this out of momir and other game modes. )//keep this out of momir and other game modes.
{ {
@@ -377,7 +377,7 @@ void Rules::initGame(GameObserver *g)
g->currentPlayerId = initState.player; g->currentPlayerId = initState.player;
g->phaseRing->goToPhase(0, g->currentPlayer, false); g->phaseRing->goToPhase(0, g->currentPlayer, false);
g->phaseRing->goToPhase(initState.phase, g->currentPlayer); g->phaseRing->goToPhase(initState.phase, g->currentPlayer);
g->currentGamePhase = initState.phase; g->setCurrentGamePhase(initState.phase);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {

View File

@@ -160,7 +160,7 @@ int TestSuiteAI::Act(float dt)
phaseToGo = i; phaseToGo = i;
} }
} }
if(observer->currentGamePhase != phaseToGo) if(observer->getCurrentGamePhase() != phaseToGo)
suite->currentAction--; suite->currentAction--;
else else
{ {
@@ -340,11 +340,11 @@ void TestSuiteGame::assertGame()
int error = 0; int error = 0;
bool wasAI = false; bool wasAI = false;
if (observer->currentGamePhase != endState.phase) if (observer->getCurrentGamePhase() != endState.phase)
{ {
sprintf(result, "<span class=\"error\">==phase problem. Expected [ %s ](%i), got [ %s ](%i)==</span><br />", sprintf(result, "<span class=\"error\">==phase problem. Expected [ %s ](%i), got [ %s ](%i)==</span><br />",
Constants::MTGPhaseNames[endState.phase],endState.phase, Constants::MTGPhaseNames[endState.phase],endState.phase,
Constants::MTGPhaseNames[observer->currentGamePhase], observer->currentGamePhase); Constants::MTGPhaseNames[observer->getCurrentGamePhase()], observer->getCurrentGamePhase());
Log(result); Log(result);
error++; error++;
} }
@@ -560,6 +560,8 @@ int TestSuite::loadNext()
thread_count = QThread::idealThreadCount(); thread_count = QThread::idealThreadCount();
#elif defined(IOS) #elif defined(IOS)
thread_count = 6; thread_count = 6;
#else
thread_count = 4;
#endif #endif
for(size_t i = 0; i < (thread_count-1); i++) for(size_t i = 0; i < (thread_count-1); i++)
mWorkerThread.push_back(new boost::thread(ThreadProc, this)); mWorkerThread.push_back(new boost::thread(ThreadProc, this));
@@ -819,7 +821,7 @@ void TestSuiteGame::initGame()
{ {
DebugTrace("TESTSUITE Init Game"); DebugTrace("TESTSUITE Init Game");
observer->phaseRing->goToPhase(initState.phase, observer->players[0], false); observer->phaseRing->goToPhase(initState.phase, observer->players[0], false);
observer->currentGamePhase = initState.phase; observer->setCurrentGamePhase(initState.phase);
observer->resetStartupGame(); observer->resetStartupGame();

View File

@@ -158,7 +158,6 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>./include;$(MTGEXTRAS);../../JGE/include;../../JGE/Dependencies/include;../../Boost;../../JGE/Dependencies/SDL/include;../../JGE/src/zipFS;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>./include;$(MTGEXTRAS);../../JGE/include;../../JGE/Dependencies/include;../../Boost;../../JGE/Dependencies/SDL/include;../../JGE/src/zipFS;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>SDL_CONFIG;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>SDL_CONFIG;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeaderOutputFile>.\Debug/template.pch</PrecompiledHeaderOutputFile> <PrecompiledHeaderOutputFile>.\Debug/template.pch</PrecompiledHeaderOutputFile>
@@ -171,7 +170,7 @@
<EnablePREfast>false</EnablePREfast> <EnablePREfast>false</EnablePREfast>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>false</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
@@ -375,7 +374,7 @@
<ClCompile Include="src\GuiPlay.cpp" /> <ClCompile Include="src\GuiPlay.cpp" />
<ClCompile Include="src\GuiStatic.cpp" /> <ClCompile Include="src\GuiStatic.cpp" />
<ClCompile Include="src\IconButton.cpp" /> <ClCompile Include="src\IconButton.cpp" />
<ClCompile Include="src\InteractiveButton.cpp" /> <ClCompile Include="src\InteractiveButton.cpp" />
<ClCompile Include="src\ManaCost.cpp" /> <ClCompile Include="src\ManaCost.cpp" />
<ClCompile Include="src\ManaCostHybrid.cpp" /> <ClCompile Include="src\ManaCostHybrid.cpp" />
<ClCompile Include="src\MenuItem.cpp" /> <ClCompile Include="src\MenuItem.cpp" />
@@ -390,6 +389,7 @@
<ClCompile Include="src\MTGPack.cpp" /> <ClCompile Include="src\MTGPack.cpp" />
<ClCompile Include="src\MTGRules.cpp" /> <ClCompile Include="src\MTGRules.cpp" />
<ClCompile Include="src\Navigator.cpp" /> <ClCompile Include="src\Navigator.cpp" />
<ClCompile Include="src\NetworkPlayer.cpp" />
<ClCompile Include="src\ObjectAnalytics.cpp" /> <ClCompile Include="src\ObjectAnalytics.cpp" />
<ClCompile Include="src\OptionItem.cpp" /> <ClCompile Include="src\OptionItem.cpp" />
<ClCompile Include="src\PhaseRing.cpp" /> <ClCompile Include="src\PhaseRing.cpp" />
@@ -499,7 +499,7 @@
<ClInclude Include="include\GuiPlay.h" /> <ClInclude Include="include\GuiPlay.h" />
<ClInclude Include="include\GuiStatic.h" /> <ClInclude Include="include\GuiStatic.h" />
<ClInclude Include="include\IconButton.h" /> <ClInclude Include="include\IconButton.h" />
<ClInclude Include="include\InteractiveButton.h"/> <ClInclude Include="include\InteractiveButton.h" />
<ClInclude Include="include\Manacost.h" /> <ClInclude Include="include\Manacost.h" />
<ClInclude Include="include\ManaCostHybrid.h" /> <ClInclude Include="include\ManaCostHybrid.h" />
<ClInclude Include="include\MenuItem.h" /> <ClInclude Include="include\MenuItem.h" />
@@ -514,6 +514,7 @@
<ClInclude Include="include\MTGPack.h" /> <ClInclude Include="include\MTGPack.h" />
<ClInclude Include="include\MTGRules.h" /> <ClInclude Include="include\MTGRules.h" />
<ClInclude Include="include\Navigator.h" /> <ClInclude Include="include\Navigator.h" />
<ClInclude Include="include\NetworkPlayer.h" />
<ClInclude Include="include\ObjectAnalytics.h" /> <ClInclude Include="include\ObjectAnalytics.h" />
<ClInclude Include="include\OptionItem.h" /> <ClInclude Include="include\OptionItem.h" />
<ClInclude Include="include\OSD.h" /> <ClInclude Include="include\OSD.h" />
@@ -571,4 +572,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

@@ -322,12 +322,15 @@
<ClCompile Include="src\AbilityParser.cpp"> <ClCompile Include="src\AbilityParser.cpp">
<Filter>src</Filter> <Filter>src</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\InteractiveButton.cpp"> <ClCompile Include="src\InteractiveButton.cpp">
<Filter>src</Filter> <Filter>src</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\SimpleButton.cpp"> <ClCompile Include="src\SimpleButton.cpp">
<Filter>src</Filter> <Filter>src</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\NetworkPlayer.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="include\ActionElement.h"> <ClInclude Include="include\ActionElement.h">
@@ -681,6 +684,9 @@
<ClInclude Include="include\AbilityParser.h"> <ClInclude Include="include\AbilityParser.h">
<Filter>inc</Filter> <Filter>inc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="include\NetworkPlayer.h">
<Filter>inc</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Makefile" /> <None Include="Makefile" />
@@ -704,4 +710,4 @@
<Filter>res</Filter> <Filter>res</Filter>
</ResourceCompile> </ResourceCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>