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

View File

@@ -33,15 +33,16 @@
#include <sstream>
#include "../include/JSocket.h"
map<string, processCmd> JNetwork::sCommandMap;
map<string, JNetwork::CommandStruc> JNetwork::sCommandMap;
JNetwork* JNetwork::mInstance = NULL;
bool JNetwork::isConnected(){
if (connected_to_ap !=1) return false;
if (connected_to_ap !=1 || !socket) return false;
return socket->isConnected();
}
JNetwork::JNetwork()
: mpWorkerThread(NULL)
: mpWorkerThread(NULL), socket(0)
{
#if (defined WIN32) || (defined LINUX)
connected_to_ap = 1;
@@ -62,30 +63,83 @@ JNetwork::~JNetwork()
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);
if(!socket) {
DebugTrace("sendCommand failed: no sockeet");
DebugTrace("sendCommand failed: no socket");
return false;
}
aString = aString + "Command";
aString = xString + suffix;
if(sCommandMap.find(aString) == sCommandMap.end()) {
DebugTrace("sendCommand failed: command not registered");
return false;
}
aString = aString + "\n";
aString = "<" + aString + ">" + "\n" + payload + "\n" + "<" + aString + "/>";
toSend << aString;
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;
sCommandMap[command + "Response"] = processResponse;
CommandStruc struc;
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)
@@ -105,64 +159,25 @@ void JNetwork::ThreadProc(void* param)
}
while(pSocket && pSocket->isConnected()) {
char buff[1024];
char buff[4096];
{
boost::mutex::scoped_lock l(pThis->receiveMutex);
int len = pSocket->Read(buff, sizeof(buff));
if(len) {
if(len > 0) {
DebugTrace("receiving " << len << " bytes : " << buff);
pThis->received << buff;
}
// 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() );
}
pThis->received.str(pThis->received.str() + buff);
DebugTrace("received " << pThis->received.str().size() << " bytes : " << pThis->received.str());
}
}
boost::mutex::scoped_lock l(pThis->sendMutex);
if(!pThis->toSend.str().empty())
{
DebugTrace("sending " << pThis->toSend.str().size() << " bytes : " << pThis->toSend.str());
pSocket->Write((char*)pThis->toSend.str().c_str(), pThis->toSend.str().size()+1);
pThis->toSend.str("");
}
{
boost::mutex::scoped_lock l(pThis->sendMutex);
if(!pThis->toSend.str().empty())
{
DebugTrace("sending " << pThis->toSend.str().size() << " bytes : " << pThis->toSend.str());
pSocket->Write((char*)pThis->toSend.str().c_str(), pThis->toSend.str().size()+1);
pThis->toSend.str("");
}
}
}
DebugTrace("Quitting Thread");

View File

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

View File

@@ -12,7 +12,9 @@
#include "GuiStatic.h"
#include <queue>
#include <time.h>
#ifdef NETWORK_SUPPORT
#include "JNetwork.h"
#endif //NETWORK_SUPPORT
class MTGGamePhase;
class MTGAbility;
@@ -42,13 +44,15 @@ class GameObserver{
JGE* mJGE;
DeckManager* mDeckManager;
Player * gameOver;
GamePhase mCurrentGamePhase;
int untap(MTGCardInstance * card);
bool WaitForExtraPayment(MTGCardInstance* card);
void cleanup();
string startupGameSerialized;
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
#ifdef TESTSUITE
, TestSuiteGame* testgame
@@ -58,7 +62,7 @@ class GameObserver{
bool mLoading;
void nextGamePhase();
void shuffleLibrary(Player* p);
void createPlayer(const string& playerMode
Player* createPlayer(const string& playerMode
#ifdef TESTSUITE
, TestSuiteGame* testgame
#endif //TESTSUITE
@@ -73,7 +77,6 @@ class GameObserver{
PhaseRing * phaseRing;
vector<list<Phase*> >gameTurn;
int cancelCurrentAction();
GamePhase currentGamePhase;
ExtraCosts * mExtraPayment;
int oldGamePhase;
TargetChooser * targetChooser;
@@ -85,10 +88,7 @@ class GameObserver{
MTGCardInstance* ExtraRules;
Trash* mTrash;
GameType gameType() const
{
return mGameType;
};
GameType gameType() const { return mGameType; };
TargetChooser * getCurrentTargetChooser();
void stackObjectClicked(Interruptible * action);
@@ -97,6 +97,7 @@ class GameObserver{
int cardClick(MTGCardInstance * card, int abilityType);
int cardClick(MTGCardInstance * card,Targetable * _object = NULL, bool log = true);
GamePhase getCurrentGamePhase();
void setCurrentGamePhase(GamePhase phase) { mCurrentGamePhase = phase; };
const char * getCurrentGamePhaseName();
const char * getNextGamePhaseName();
void nextCombatStep();
@@ -107,7 +108,7 @@ class GameObserver{
#ifdef TESTSUITE
void loadTestSuitePlayer(int playerId, TestSuiteGame* 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);
Player * currentPlayer;
@@ -117,7 +118,7 @@ class GameObserver{
Player * nextTurnsPlayer();
Player * currentlyActing();
GameObserver(WResourceManager* output = 0, JGE* input = 0);
~GameObserver();
virtual ~GameObserver();
void gameStateBasedEffects();
void enchantmentStatus();
void Affinity();
@@ -129,7 +130,7 @@ class GameObserver{
int isInPlay(MTGCardInstance * card);
int isInGrave(MTGCardInstance * card);
int isInExile(MTGCardInstance * card);
void Update(float dt);
virtual void Update(float dt);
void Render();
void ButtonPressed(PlayGuiObject*);
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

View File

@@ -15,7 +15,7 @@ protected:
static ProxyPlayer* mInstance;
public:
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;
static RemotePlayer* mInstance;
public:
RemotePlayer(JNetwork*);
static void Deserialize(istream& in, ostream& out);
RemotePlayer(GameObserver* observer, JNetwork*);
static void Deserialize(void*, stringstream& in, stringstream& out);
bool isLoaded() {return game!=NULL;};
};

View File

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

View File

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

View File

@@ -15,9 +15,14 @@
#include "Trash.h"
#include "DeckManager.h"
#include "GuiCombat.h"
#include <algorithm>
#ifdef TESTSUITE
#include "TestSuiteAI.h"
#endif
#ifdef NETWORK_SUPPORT
#include "NetworkPlayer.h"
#endif
void GameObserver::cleanup()
{
@@ -35,7 +40,7 @@ void GameObserver::cleanup()
currentActionPlayer = NULL;
isInterrupting = NULL;
currentPlayerId = 0;
currentGamePhase = MTG_PHASE_INVALID;
mCurrentGamePhase = MTG_PHASE_INVALID;
targetChooser = NULL;
cardWaitingForTargets = NULL;
mExtraPayment = NULL;
@@ -51,6 +56,7 @@ void GameObserver::cleanup()
GameObserver::~GameObserver()
{
LOG("==Destroying GameObserver==");
for (size_t i = 0; i < players.size(); ++i)
{
players[i]->End();
@@ -83,7 +89,7 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input)
currentActionPlayer = NULL;
isInterrupting = NULL;
currentPlayerId = 0;
currentGamePhase = MTG_PHASE_INVALID;
mCurrentGamePhase = MTG_PHASE_INVALID;
targetChooser = NULL;
cardWaitingForTargets = NULL;
mExtraPayment = NULL;
@@ -101,17 +107,17 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input)
GamePhase GameObserver::getCurrentGamePhase()
{
return currentGamePhase;
return mCurrentGamePhase;
}
const char* GameObserver::getCurrentGamePhaseName()
{
return phaseRing->phaseName(currentGamePhase);
return phaseRing->phaseName(mCurrentGamePhase);
}
const char* GameObserver::getNextGamePhaseName()
{
return phaseRing->phaseName((currentGamePhase + 1) % MTG_PHASE_CLEANUP);
return phaseRing->phaseName((mCurrentGamePhase + 1) % MTG_PHASE_CLEANUP);
}
Player * GameObserver::opponent()
@@ -182,18 +188,18 @@ void GameObserver::nextGamePhase()
}
Phase * cPhase = phaseRing->getCurrentPhase();
currentGamePhase = cPhase->id;
mCurrentGamePhase = cPhase->id;
if (MTG_PHASE_COMBATDAMAGE == currentGamePhase)
if (MTG_PHASE_COMBATDAMAGE == mCurrentGamePhase)
nextCombatStep();
if (MTG_PHASE_COMBATEND == currentGamePhase)
if (MTG_PHASE_COMBATEND == mCurrentGamePhase)
combatStep = BLOCKERS;
//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?
//init begin of turn
if (currentGamePhase == MTG_PHASE_BEFORE_BEGIN)
if (mCurrentGamePhase == MTG_PHASE_BEFORE_BEGIN)
{
cleanupPhase();
currentPlayer->damageCount = 0;
@@ -211,7 +217,7 @@ void GameObserver::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
while (currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false)
@@ -228,7 +234,7 @@ void GameObserver::nextGamePhase()
}
//Phase Specific actions
switch (currentGamePhase)
switch (mCurrentGamePhase)
{
case MTG_PHASE_UNTAP:
DebugTrace("Untap Phase ------------- Turn " << turn );
@@ -281,7 +287,7 @@ void GameObserver::userRequestNextGamePhase(bool allowInterrupt, bool log)
{
if(log) {
stringstream stream;
stream << "next " << allowInterrupt << " " <<currentGamePhase;
stream << "next " << allowInterrupt << " " <<mCurrentGamePhase;
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_COMBATDAMAGE)
|| opponent()->isAI()
|| options[Options::optionInterrupt(currentGamePhase)].number
|| currentPlayer->offerInterruptOnPhase - 1 == currentGamePhase
|| options[Options::optionInterrupt(mCurrentGamePhase)].number
|| currentPlayer->offerInterruptOnPhase - 1 == mCurrentGamePhase
))
{
mLayers->stackLayer()->AddNextGamePhase();
@@ -480,7 +486,7 @@ bool GameObserver::operator==(const GameObserver& aGame)
{
int error = 0;
if (aGame.currentGamePhase != currentGamePhase)
if (aGame.mCurrentGamePhase != mCurrentGamePhase)
{
error++;
}
@@ -544,7 +550,7 @@ void GameObserver::dumpAssert(bool val)
void GameObserver::Update(float dt)
{
Player * player = currentPlayer;
if (MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep)
if (MTG_PHASE_COMBATBLOCKERS == mCurrentGamePhase && BLOCKERS == combatStep)
{
player = player->opponent();
}
@@ -567,7 +573,7 @@ void GameObserver::Update(float dt)
}
gameStateBasedEffects();
}
oldGamePhase = currentGamePhase;
oldGamePhase = mCurrentGamePhase;
}
//applies damage to creatures after updates
@@ -649,7 +655,7 @@ void GameObserver::gameStateBasedEffects()
//////////////////////////
//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->phasedTurn = turn;
@@ -657,7 +663,7 @@ void GameObserver::gameStateBasedEffects()
card->view->alpha = 50;
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->phasedTurn = turn;
@@ -761,7 +767,7 @@ void GameObserver::gameStateBasedEffects()
/////////////////////////////////////////////////
//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)
{
@@ -860,17 +866,17 @@ void GameObserver::gameStateBasedEffects()
if (skipLevel == Constants::ASKIP_SAFE || skipLevel == Constants::ASKIP_FULL)
{
if ((opponent()->isAI() && !(isInterrupting)) && ((currentGamePhase == MTG_PHASE_UNTAP)
|| (currentGamePhase == MTG_PHASE_DRAW) || (currentGamePhase == MTG_PHASE_COMBATBEGIN)
|| ((currentGamePhase == MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0))
|| currentGamePhase == MTG_PHASE_COMBATEND || currentGamePhase == MTG_PHASE_ENDOFTURN
|| ((currentGamePhase == MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8))))
if ((opponent()->isAI() && !(isInterrupting)) && ((mCurrentGamePhase == MTG_PHASE_UNTAP)
|| (mCurrentGamePhase == MTG_PHASE_DRAW) || (mCurrentGamePhase == MTG_PHASE_COMBATBEGIN)
|| ((mCurrentGamePhase == MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0))
|| mCurrentGamePhase == MTG_PHASE_COMBATEND || mCurrentGamePhase == MTG_PHASE_ENDOFTURN
|| ((mCurrentGamePhase == MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8))))
userRequestNextGamePhase();
}
if (skipLevel == Constants::ASKIP_FULL)
{
if ((opponent()->isAI() && !(isInterrupting)) && (currentGamePhase == MTG_PHASE_UPKEEP
|| currentGamePhase == MTG_PHASE_COMBATDAMAGE))
if ((opponent()->isAI() && !(isInterrupting)) && (mCurrentGamePhase == MTG_PHASE_UPKEEP
|| mCurrentGamePhase == MTG_PHASE_COMBATDAMAGE))
userRequestNextGamePhase();
}
}
@@ -1316,7 +1322,7 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object, bool lo
}
//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)
{
WEvent * e = NEW WEventCardDiscard(currentPlayer->game->hand->cards[0]);
@@ -1475,8 +1481,8 @@ ostream& operator<<(ostream& out, const GameObserver& g)
{
out << "[init]" << endl;
out << "player=" << g.currentPlayerId + 1 << endl;
if(g.currentGamePhase != -1)
out << "phase=" << g.phaseRing->phaseName(g.currentGamePhase) << endl;
if(g.mCurrentGamePhase != MTG_PHASE_INVALID)
out << "phase=" << g.phaseRing->phaseName(g.mCurrentGamePhase) << endl;
out << "[player1]" << endl;
out << *(g.players[0]) << endl;
out << "[player2]" << endl;
@@ -1518,7 +1524,7 @@ bool GameObserver::parseLine(const string& s)
}
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;
}
}
@@ -1630,7 +1636,7 @@ bool GameObserver::load(const string& ss, bool undo
mRules->initGame(this);
phaseRing->goToPhase(0, currentPlayer, false);
phaseRing->goToPhase(currentGamePhase, currentPlayer);
phaseRing->goToPhase(mCurrentGamePhase, currentPlayer);
#ifdef TESTSUITE
if(testgame)
@@ -1654,6 +1660,63 @@ bool GameObserver::load(const string& ss, bool undo
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
#ifdef TESTSUITE
, 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
// So, we need them flushed to be able to set the manapool to whatever we need
Update(counter);
GameObserver::Update(counter);
counter += 1.000f;
#ifdef TESTSUITE
@@ -1692,65 +1755,14 @@ bool GameObserver::processActions(bool undo
for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++, cmdIndex++)
{
string s = *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);
}
processAction(*loadingite);
size_t nb = actionsList.size();
for (int i = 0; i<6; i++)
{
// let's fake an update
Update(counter);
GameObserver::Update(counter);
counter += 1.000f;
}
dumpAssert(actionsList.back() == *loadingite);
@@ -1809,34 +1821,43 @@ void GameObserver::Mulligan(Player* player)
player->takeMulligan();
}
void GameObserver::createPlayer(const string& playerMode
Player* GameObserver::createPlayer(const string& playerMode
#ifdef TESTSUITE
, TestSuiteGame* testgame
#endif //TESTSUITE
)
{
Player::Mode aMode = (Player::Mode)atoi(playerMode.c_str());
Player* pPlayer = 0;
switch(aMode)
{
case Player::MODE_AI:
AIPlayerFactory playerCreator;
if(players.size())
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), players[0]));
pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), players[0]);
else
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), 0));
pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), 0);
break;
case Player::MODE_HUMAN:
players.push_back(new HumanPlayer(this, "", ""));
pPlayer = new HumanPlayer(this, "", "");
break;
case Player::MODE_TEST_SUITE:
#ifdef TESTSUITE
if(players.size())
players.push_back(new TestSuiteAI(testgame, 1));
pPlayer = new TestSuiteAI(testgame, 1);
else
players.push_back(new TestSuiteAI(testgame, 0));
pPlayer = new TestSuiteAI(testgame, 0);
#endif //TESTSUITE
break;
}
if(pPlayer)
{
players.push_back(pPlayer);
}
return pPlayer;
}
#ifdef TESTSUITE
@@ -1881,20 +1902,19 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b
sprintf(deckFileSmall, "player_deck%i", decknb);
loadPlayer(playerId, NEW HumanPlayer(this, deckFile, deckFileSmall, premadeDeck));
}
}
#ifdef NETWORK_SUPPORT
// FIXME, this is broken
if(isNetwork)
{
ProxyPlayer* mProxy;
mProxy = NEW ProxyPlayer(mPlayers[playerId], mParent->mpNetwork);
}
}
else
{ //Remote player
loadPlayer(playerId, NEW RemotePlayer(mParent->mpNetwork));
#endif //NETWORK_SUPPORT
}
else if(playerType == PLAYER_TYPE_REMOTE)
{
//Player 0 is the human player
ProxyPlayer* mProxy;
mProxy = NEW ProxyPlayer(players[0], JNetwork::GetInstance());
//Player 1 is the remote player
loadPlayer(playerId, NEW RemotePlayer(this, JNetwork::GetInstance()));
}
#endif //NETWORK_SUPPORT
else
{ //AI Player, chooses deck
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);
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
SAFE_DELETE(testSuite);
@@ -298,7 +308,7 @@ void GameStateDuel::ThreadProc(void* inParam)
observer.startGame(instance->mParent->gameType, instance->mParent->rules);
while(!observer.didWin())
{
if(observer.turn == oldTurn && observer.currentGamePhase == oldPhase)
if(observer.turn == oldTurn && observer.getCurrentGamePhase() == oldPhase)
{
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)
mParent->rules->postUpdateInit(game);
#ifdef NETWORK_SUPPORT
if(mParent->mpNetwork) ((NetworkGameObserver*)game)->synchronize();
#endif
if (game->didWin())
{
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
thread_count = QThread::idealThreadCount();
#endif
#else
thread_count = 4;
#endif
for(size_t i = 0; i < (thread_count); i++)
mWorkerThread.push_back(boost::thread(ThreadProc, this));
}
@@ -508,7 +525,7 @@ void GameStateDuel::Update(float dt)
int cardsinhand = game->currentPlayer->game->hand->nb_cards;
//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->exile->nb_cards == 0 && game->currentlyActing() == (Player*)game->currentPlayer) //1st Play Check
//IF there was no play at the moment automatically mulligan
@@ -517,7 +534,7 @@ void GameStateDuel::Update(float dt)
}
//END almosthumane - mulligan
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
#ifdef DEBUG
#ifdef TESTSUITE
menu->Add(MENUITEM_UNDO, "Undo");
#endif
#ifdef TESTSUITE
@@ -531,23 +548,23 @@ void GameStateDuel::Update(float dt)
#ifdef NETWORK_SUPPORT
case DUEL_STATE_OPPONENT_WAIT:
{
if(mPlayers[1] && mPlayers[1]->game)
{ // Player loaded
menu->Close();
SAFE_DELETE(menu);
setGamePhase(DUEL_STATE_PLAY);
} else if(menu == NULL)
{
loadPlayer(1, 42/* 0 not good*/, false, true);
menu = NEW SimpleMenu(DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60);
if (menu)
{
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
}
} else
{
menu->Update(dt);
}
if(game->players.size() > 1)
{ // Player loaded
menu->Close();
SAFE_DELETE(menu);
setGamePhase(DUEL_STATE_PLAY);
} else if(menu == NULL)
{
menu = NEW SimpleMenu(JGE::GetInstance(), DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60);
if (menu)
{
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
}
} else
{
menu->Update(dt);
game->Update(dt);
}
}
break;
#endif //NETWORK_SUPPORT
@@ -732,10 +749,13 @@ void GameStateDuel::Render()
// display the player deck names in their respective corners
string playerDeckName = game->players[0]->deckName;
string opponentDeckName = game->players[1]->deckName;
float playerDeckNamePixelLength = mFont->GetStringWidth(playerDeckName.c_str());
mFont->DrawString( opponentDeckName, 0, 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
case MENU_STATE_NETWORK_DEFINE:
currentState = MENU_STATE_MAJOR_SUBMENU;
subMenuController = NEW SimpleMenu(MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60);
if (subMenuController)
if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR))
{
subMenuController->Add(SUBMENUITEM_HOST_GAME, "Host a game");
subMenuController->Add(SUBMENUITEM_JOIN_GAME, "Join a game");
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel");
}
break;
currentState = MENU_STATE_MAJOR_SUBMENU;
subMenuController = NEW SimpleMenu(JGE::GetInstance(), MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60);
if (subMenuController)
{
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:
if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR))
{
@@ -578,7 +581,7 @@ void GameStateMenu::Update(float dt)
else if(!subMenuController)
{
// 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)
{
subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel connection");
@@ -840,7 +843,7 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
{
if(!mParent->mpNetwork)
{
mParent->mpNetwork = new JNetwork();
mParent->mpNetwork = JNetwork::GetInstance();
}
mParent->mpNetwork->connect();
subMenuController->Close();
@@ -851,16 +854,17 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
{
if(!mParent->mpNetwork)
{
mParent->mpNetwork = new JNetwork();
mParent->mpNetwork = JNetwork::GetInstance();
}
// FIXME needs to be able to specify the server ip
mParent->mpNetwork->connect("127.0.0.1");
// we let the server choose the game mode
mParent->gameType = GAME_TYPE_SLAVE;
// just to select one, the HOST is in control here.
mParent->rules = Rules::getRulesByFilename("classic.txt");
hasChosenGameType = true;
subMenuController->Close();
// currentState = MENU_STATE_MAJOR_DUEL | MENU_STATE_MINOR_SUBMENU_CLOSING;
currentState = MENU_STATE_NETWORK_WAIT;
currentState = MENU_STATE_NETWORK_WAIT | MENU_STATE_MINOR_SUBMENU_CLOSING;
break;
}
#endif //NETWORK_SUPPORT
@@ -878,10 +882,8 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId)
subMenuController->Close();
}
#ifdef NETWORK_SUPPORT
if(mParent->mpNetwork)
{
SAFE_DELETE(mParent->mpNetwork);
}
JNetwork::Destroy();
mParent->mpNetwork=0;
#endif //NETWORK_SUPPORT
currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_SUBMENU_CLOSING;
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,
// 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
if (!blockers.size() && observer->currentGamePhase == MTG_PHASE_COMBATBLOCKERS)
if (!blockers.size() && observer->getCurrentGamePhase() == MTG_PHASE_COMBATBLOCKERS)
{
blocked = false;
}

View File

@@ -288,7 +288,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
if (!player->game->hand->hasCard(card))
return 0;
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->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)
return 0;
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;
@@ -319,8 +319,8 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
}
else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH)
|| (player == currentPlayer && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN))
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| 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)
return 0;
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;
}
else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH)
|| (player == currentPlayer && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN))
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
)
{
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.
if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == currentPlayer
&& !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN))
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
)
{
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))
return 0;
if (player == currentPlayer && !game->isInterrupting
&& (game->currentGamePhase == MTG_PHASE_FIRSTMAIN
|| game->currentGamePhase == MTG_PHASE_SECONDMAIN)
&& (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
|| game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)
)
{
return 1;

View File

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

View File

@@ -243,6 +243,11 @@ bool Player::parseLine(const string& s)
ManaCost::parseManaCost(s.substr(limiter + 1), manaPool);
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)
{
mAvatarName = s.substr(limiter + 1);
@@ -326,9 +331,12 @@ ostream& operator<<(ostream& out, const Player& p)
{
out << "mode=" << p.playMode << endl;
out << *(Damageable*)&p;
string manapoolstring = p.manaPool->toString();
if(manapoolstring != "")
out << "manapool=" << manapoolstring << endl;
if(p.manaPool)
{
string manapoolstring = p.manaPool->toString();
if(manapoolstring != "")
out << "manapool=" << manapoolstring << endl;
}
if(p.mAvatarName != "")
out << "avatar=" << p.mAvatarName << endl;
if(p.phaseRing != "")
@@ -348,6 +356,22 @@ ostream& operator<<(ostream& out, const Player& p)
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
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
!= GAME_TYPE_RANDOM1 && g->mRules->gamemode != GAME_TYPE_RANDOM2 && g->mRules->gamemode
!= 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
&& !g->players[1] == PLAYER_TYPE_REMOTE
&& !(g->players[1]->playMode == PLAYER_TYPE_REMOTE) && !(g->players[1]->playMode == PLAYER_TYPE_HUMAN)
#endif //NETWORK_SUPPORT
)//keep this out of momir and other game modes.
{
@@ -377,7 +377,7 @@ void Rules::initGame(GameObserver *g)
g->currentPlayerId = initState.player;
g->phaseRing->goToPhase(0, g->currentPlayer, false);
g->phaseRing->goToPhase(initState.phase, g->currentPlayer);
g->currentGamePhase = initState.phase;
g->setCurrentGamePhase(initState.phase);
for (int i = 0; i < 2; i++)
{

View File

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

View File

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

View File

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