- Added new code for serialization/deserializaiton of full games including initial game and all the player actions.

- Added an undo menu using this code (beware, it's still very very alpha).
- Removed various warning
- Cleaned up avatar loading
- Added full random lists load/save including the deck shuffling (not sure if I could not replace that with seed load/save)
- Moved momir and Co rules configuration out of GameStateDuel
- Create a GameType type to avoid mixing int everywhere
This commit is contained in:
Xawotihs
2011-10-13 19:43:51 +00:00
parent 663058cdab
commit 0b6044551a
28 changed files with 595 additions and 156 deletions

View File

@@ -38,22 +38,6 @@ enum
#endif //NETWORK_SUPPORT
};
enum
{
GAME_TYPE_CLASSIC,
GAME_TYPE_MOMIR,
GAME_TYPE_RANDOM1,
GAME_TYPE_RANDOM2,
GAME_TYPE_STORY,
GAME_TYPE_DEMO,
GAME_TYPE_STONEHEWER,
GAME_TYPE_HERMIT,
#ifdef NETWORK_SUPPORT
GAME_TYPE_SLAVE,
#endif //NETWORK_SUPPORT
};
class MTGAllCards;
class TransitionBase;
@@ -73,7 +57,7 @@ private:
GameState* mGameStates[GAME_STATE_MAX];
public:
int gameType;
GameType gameType;
Rules * rules;
CardEffect *effect;
#ifdef NETWORK_SUPPORT

View File

@@ -26,10 +26,21 @@ class GameObserver{
protected:
MTGCardInstance * cardWaitingForTargets;
queue<WEvent *> eventsQueue;
list<string> actionsList;
int untap(MTGCardInstance * card);
bool WaitForExtraPayment(MTGCardInstance* card);
void initialize();
void cleanup();
string startupGameSerialized;
bool parseLine(const string& s);
void logAction(const string& s) {
actionsList.push_back(s);
};
bool processActions(bool undo);
friend ostream& operator<<(ostream&, GameObserver&);
bool load(const string& s, bool undo);
bool mLoading;
public:
int currentPlayerId;
@@ -49,6 +60,7 @@ class GameObserver{
vector<Player *> players; //created outside
time_t startedAt;
Rules * mRules;
GameType mGameType;
TargetChooser * getCurrentTargetChooser();
void stackObjectClicked(Interruptible * action);
@@ -74,10 +86,9 @@ class GameObserver{
void gameStateBasedEffects();
void enchantmentStatus();
void Affinity();
void eventOccured();
void addObserver(MTGAbility * observer);
bool removeObserver(ActionElement * observer);
void startGame(Rules * rules);
void startGame(GameType, Rules * rules);
void untapPhase();
MTGCardInstance * isCardWaiting(){ return cardWaitingForTargets; }
int isInPlay(MTGCardInstance * card);
@@ -90,6 +101,14 @@ class GameObserver{
int receiveEvent(WEvent * event);
bool connectRule;
void logAction(Player* player, const string& s="");
void logAction(int playerId, const string& s="") {
logAction(players[playerId], s);
};
void logAction(MTGCardInstance* card, MTGGameZone* zone = NULL);
bool undo();
bool isLoading(){ return mLoading; };
};
#endif

View File

@@ -78,9 +78,10 @@ public:
MENUITEM_MAIN_MENU = -13,
MENUITEM_EVIL_TWIN = kEvilTwinMenuID,
MENUITEM_MULLIGAN = -15,
MENUITEM_UNDO = -16,
#ifdef NETWORK_SUPPORT
MENUITEM_REMOTE_CLIENT = -16,
MENUITEM_REMOTE_SERVER = -17,
MENUITEM_REMOTE_CLIENT = -17,
MENUITEM_REMOTE_SERVER = -18,
#endif
MENUITEM_MORE_INFO = kInfoMenuID
};

View File

@@ -210,9 +210,8 @@ public:
static MTGCardInstance ExtraRules[2];
bool parseLine(const string& ss);
};
ostream& operator<<(ostream&, const MTGCardInstance&);
#endif

View File

@@ -7,6 +7,23 @@ const float DEFAULT_TEXT_FONT_SCALE = 1.0f;
#include <string>
using std::string;
typedef enum
{
GAME_TYPE_CLASSIC,
GAME_TYPE_MOMIR,
GAME_TYPE_RANDOM1,
GAME_TYPE_RANDOM2,
GAME_TYPE_STORY,
GAME_TYPE_DEMO,
GAME_TYPE_STONEHEWER,
GAME_TYPE_HERMIT,
#ifdef NETWORK_SUPPORT
GAME_TYPE_SLAVE,
#endif //NETWORK_SUPPORT
} GameType;
class Constants
{
public:

View File

@@ -83,6 +83,7 @@ class MTGGameZone {
void debugPrint();
MTGCardInstance * removeCard(MTGCardInstance * card, int createCopy = 1);
MTGCardInstance * hasCard(MTGCardInstance * card);
size_t getIndex(MTGCardInstance * card);
void cleanupPhase();
void beforeBeginPhase();

View File

@@ -15,6 +15,10 @@ class Player: public Damageable
{
protected:
ManaPool * manaPool;
JTexture * mAvatarTex;
JQuadPtr mAvatar;
bool loadAvatar(string file, string resName = "playerAvatar");
public:
enum ENUM_PLAY_MODE
@@ -25,8 +29,6 @@ public:
};
string mAvatarName;
JTexture * mAvatarTex;
JQuadPtr mAvatar;
int playMode;
bool nomaxhandsize;
MTGPlayerCards * game;
@@ -35,7 +37,7 @@ public:
string deckFileSmall;
string deckName;
string phaseRing;
int offerInterruptOnPhase;
int offerInterruptOnPhase;
Player(GameObserver *observer, string deckFile, string deckFileSmall, MTGDeck * deck = NULL);
virtual ~Player();
virtual void setObserver(GameObserver*g);
@@ -89,22 +91,18 @@ public:
{
}
void loadAvatar(string file);
/**
** Returns the path to the stats file of currently selected deck.
*/
std::string GetCurrentDeckStatsFile();
bool parseLine(const string& s);
friend ostream& operator<<(ostream&, const Player&);
};
class HumanPlayer: public Player
{
public:
HumanPlayer(GameObserver *observer, string deckFile, string deckFileSmall = "", MTGDeck * deck = NULL);
HumanPlayer(GameObserver *observer, string deckFile, string deckFileSmall, MTGDeck * deck = NULL);
};
ostream& operator<<(ostream&, const Player&);
#endif

View File

@@ -43,7 +43,7 @@ protected:
Player * loadPlayerRandom(GameObserver* observer, int isAI, int mode);
Player * initPlayer(GameObserver *observer, int playerId);
MTGDeck * buildDeck(int playerId);
int strToGameMode(string s);
GameType strToGameMode(string s);
bool postUpdateInitDone;
public:
enum
@@ -57,7 +57,7 @@ public:
string bg;
string filename;
int gamemode;
GameType gamemode;
bool hidden;
string displayName;
int unlockOption;

View File

@@ -67,7 +67,7 @@ public:
public:
int startTime, endTime;
int gameType;
GameType gameType;
unsigned int seed;
int nbFailed, nbTests, nbAIFailed, nbAITests;
TestSuite(const char * filename);

View File

@@ -63,9 +63,11 @@ std::string wordWrap(const std::string& s, float width, int fontId);
//basic hash function
unsigned long hash_djb2(const char *str);
int loadRandValues(string s);
void loadRandValues(string s);
ostream& saveRandValues(ostream& out);
int filesize(const char * filename);
int WRand();
ptrdiff_t MRand (ptrdiff_t i);
#ifdef LINUX
void dumpStack();

View File

@@ -97,7 +97,7 @@ int AIAction::clickMultiAct(vector<Targetable*>& actionTargets)
actionTargets.erase(actionTargets.begin() + f);
}
}
std::random_shuffle(actionTargets.begin(), actionTargets.end());
std::random_shuffle(actionTargets.begin(), actionTargets.end(), MRand);
//shuffle to make it less predictable, otherwise ai will always seem to target from right to left. making it very obvious.
for(int k = 0;k < int(actionTargets.size());k++)
{
@@ -172,7 +172,7 @@ int AIPlayer::clickMultiTarget(TargetChooser * tc, vector<Targetable*>& potentia
potentialTargets.erase(potentialTargets.begin() + f);
}
}
std::random_shuffle(potentialTargets.begin(), potentialTargets.end());
std::random_shuffle(potentialTargets.begin(), potentialTargets.end(), MRand);
if(potentialTargets.size())
clickstream.push(NEW AIAction(this, NULL,tc->source,potentialTargets));
while(clickstream.size())
@@ -257,7 +257,7 @@ AIPlayer * AIPlayerFactory::createAIPlayer(GameObserver *observer, MTGAllCards *
{
bool isOpponentAI = opponent->isAI() == 1;
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename( opponent->deckFile, isOpponentAI);
if ( meta->getVictoryPercentage() >= 65)
if ( meta && meta->getVictoryPercentage() >= 65)
deckSetting = HARD;
}

View File

@@ -1410,7 +1410,7 @@ int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCard
if(tc->belongsToAbility.size())
{
AbilityFactory af(observer);
MTGAbility * withoutGuessing = af.parseMagicLine(tc->belongsToAbility,NULL,NULL,tc->source);
MTGAbility * withoutGuessing = af.parseMagicLine(tc->belongsToAbility,0,NULL,tc->source);
cardEffect = af.abilityEfficiency(withoutGuessing,this,MODE_TARGET,tc,NULL);
delete withoutGuessing;
}
@@ -1458,7 +1458,7 @@ int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCard
if(tc->maxtargets != 1 && tc->belongsToAbility.size())
{
AbilityFactory af(observer);
MTGAbility * withoutGuessing = af.parseMagicLine(tc->belongsToAbility,NULL,NULL,tc->source);
MTGAbility * withoutGuessing = af.parseMagicLine(tc->belongsToAbility,0,NULL,tc->source);
OrderedAIAction * effCheck = NEW OrderedAIAction(this, withoutGuessing,(MTGCardInstance*)tc->source,card);
if(effCheck->getEfficiency())
{
@@ -2200,17 +2200,16 @@ AIPlayerBaka::AIPlayerBaka(GameObserver *observer, string file, string fileSmall
}
mAvatarTex = WResourceManager::Instance()->RetrieveTexture(avatarFile, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR);
if (!mAvatarTex)
if(avatarFile != "")
{
avatarFile = "baka.jpg";
mAvatarTex = WResourceManager::Instance()->RetrieveTexture(avatarFile, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR);
if(!loadAvatar(avatarFile, "bakaAvatar"))
{
avatarFile = "baka.jpg";
loadAvatar(avatarFile, "bakaAvatar");
}
mAvatarName = avatarFile;
}
if (mAvatarTex)
mAvatar = WResourceManager::Instance()->RetrieveQuad(avatarFile, 0, 0, 35, 50, "bakaAvatar", RETRIEVE_NORMAL,
TEXTURE_SUB_AVATAR);
if (fileSmall == "ai_baka_eviltwin")
mAvatar->SetHFlip(true);

View File

@@ -589,6 +589,7 @@ int ActionStack::setIsInterrupting(Player * player)
int playerId = (player == observer->players[1]) ? 1 : 0;
interruptDecision[playerId] = -1;
observer->isInterrupting = player;
observer->logAction(player, "yes");
return 1;
}
@@ -960,6 +961,7 @@ void ActionStack::cancelInterruptOffer(int cancelMode)
askIfWishesToInterrupt = NULL;
observer->isInterrupting = NULL;
timer = -1;
observer->logAction(playerId, "no");
}
void ActionStack::endOfInterruption()
@@ -967,6 +969,7 @@ void ActionStack::endOfInterruption()
int playerId = (observer->isInterrupting == observer->players[1]) ? 1 : 0;
interruptDecision[playerId] = 0;
observer->isInterrupting = NULL;
observer->logAction(playerId, "endinterruption");
}
bool ActionStack::CheckUserInput(JButton key)

View File

@@ -2360,6 +2360,7 @@ int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
game->mLayers->stackLayer()->cancelInterruptOffer();
this->forceDestroy = 1;
removeMenu = true;
game->logAction(source->controller(), "choice " + choice);
return reactToTargetClick(object);
}

View File

@@ -661,7 +661,6 @@ void CardGui::AlternateRender(MTGCard * card, const Pos& pos)
formattedfield = FormattedData(formattedfield, "expansion", setlist[card->setId].c_str());
}
float w = font->GetStringWidth(formattedfield.c_str()) * kWidthScaleFactor;
font->DrawString(formattedfield.c_str(), x + (Carditem->mPosX - BigWidth / 2) * pos.actZ, pos.actY + (Carditem->mPosY) * pos.actZ);
}
@@ -994,7 +993,6 @@ void CardGui::TinyCropRender(MTGCard * card, const Pos& pos, JQuad * quad)
formattedfield = FormattedData(formattedfield, "expansion", setlist[card->setId].c_str());
}
float w = font->GetStringWidth(formattedfield.c_str()) * kWidthScaleFactor;
font->DrawString(formattedfield.c_str(), x + (Carditem->mPosX - BigWidth / 2) * pos.actZ, pos.actY + (Carditem->mPosY) * pos.actZ);
}

View File

@@ -305,6 +305,10 @@ ostream& DamageStack::toString(ostream& out) const
ostream& operator<<(ostream& out, const Damageable& p)
{
out << "life=" << p.life << endl;
out << "poisoncount=" << p.poisonCount << endl;
out << "damagecount=" << p.damageCount << endl;
out << "preventable=" << p.preventable << endl;
return out;
}

View File

@@ -182,8 +182,13 @@ DeckManager* DeckManager::GetInstance()
// p2 is the opponent
int DeckManager::getDifficultyRating(Player *statsPlayer, Player *player)
{
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename(player->deckFile, (player->isAI() == 1) );
return meta->getDifficulty();
if(player->deckFile != "")
{
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename(player->deckFile, (player->isAI() == 1) );
return meta->getDifficulty();
}
else
return EASY;
}
DeckManager::~DeckManager()

View File

@@ -79,8 +79,9 @@ void DuelLayers::Update(float dt, Player * currentPlayer)
for (int i = 0; i < nbitems; ++i)
objects[i]->Update(dt);
int isAI = currentPlayer->isAI();
if (isAI)
if (isAI && !currentPlayer->getObserver()->isLoading())
currentPlayer->Act(dt);
CheckUserInput(isAI);
}

View File

@@ -10,14 +10,12 @@
#include <JRenderer.h>
#include "MTGGamePhase.h"
#include "GuiPhaseBar.h"
GameObserver::GameObserver()
{
initialize();
}
#include "AIPlayerBaka.h"
#include "MTGRules.h"
void GameObserver::initialize()
{
mGameType = GAME_TYPE_CLASSIC;
currentPlayer = NULL;
currentActionPlayer = NULL;
isInterrupting = NULL;
@@ -32,6 +30,61 @@ void GameObserver::initialize()
combatStep = BLOCKERS;
mRules = NULL;
connectRule = false;
mLoading = false;
}
void GameObserver::cleanup()
{
SAFE_DELETE(targetChooser);
SAFE_DELETE(mLayers);
SAFE_DELETE(phaseRing);
SAFE_DELETE(replacementEffects);
for (size_t i = 0; i < players.size(); ++i)
{
SAFE_DELETE(players[i]);
}
players.clear();
currentPlayer = NULL;
currentActionPlayer = NULL;
isInterrupting = NULL;
currentPlayerId = 0;
currentGamePhase = -1;
targetChooser = NULL;
cardWaitingForTargets = NULL;
mExtraPayment = NULL;
gameOver = NULL;
phaseRing = NULL;
replacementEffects = NEW ReplacementEffects();
combatStep = BLOCKERS;
connectRule = false;
actionsList.clear();
}
GameObserver::~GameObserver()
{
LOG("==Destroying GameObserver==");
SAFE_DELETE(targetChooser);
SAFE_DELETE(mLayers);
SAFE_DELETE(phaseRing);
SAFE_DELETE(replacementEffects);
for (size_t i = 0; i < players.size(); ++i)
{
SAFE_DELETE(players[i]);
}
players.clear();
LOG("==GameObserver Destroyed==");
}
GameObserver::GameObserver()
{
initialize();
}
GameObserver::GameObserver(vector<Player *> _players)
{
initialize();
setPlayers(_players);
}
void GameObserver::setPlayers(vector<Player *> _players)
@@ -43,12 +96,6 @@ void GameObserver::setPlayers(vector<Player *> _players)
}
}
GameObserver::GameObserver(vector<Player *> _players)
{
initialize();
setPlayers(_players);
}
int GameObserver::getCurrentGamePhase()
{
return currentGamePhase;
@@ -231,7 +278,7 @@ void GameObserver::userRequestNextGamePhase()
{
nextGamePhase();
}
logAction(currentPlayer, "next");
}
int GameObserver::forceShuffleLibraries()
@@ -250,8 +297,9 @@ int GameObserver::forceShuffleLibraries()
return result;
}
void GameObserver::startGame(Rules * rules)
void GameObserver::startGame(GameType gtype, Rules * rules)
{
mGameType = gtype;
turn = 0;
mRules = rules;
if (rules)
@@ -266,6 +314,11 @@ void GameObserver::startGame(Rules * rules)
currentPlayer = players[0];
currentActionPlayer = currentPlayer;
phaseRing = NEW PhaseRing(this);
stringstream stream;
stream << *this;
startupGameSerialized = stream.str();
if (rules)
rules->initGame(this);
@@ -311,6 +364,26 @@ void GameObserver::startGame(Rules * rules)
}
}
}
switch(gtype) {
case GAME_TYPE_MOMIR:
{
addObserver(NEW MTGMomirRule(this, -1, MTGCollection()));
break;
}
case GAME_TYPE_STONEHEWER:
{
addObserver(NEW MTGStoneHewerRule(this, -1,MTGCollection()));
break;
}
case GAME_TYPE_HERMIT:
{
addObserver(NEW MTGHermitRule(this, -1));
break;
}
default:
break;
}
}
void GameObserver::addObserver(MTGAbility * observer)
@@ -328,21 +401,6 @@ bool GameObserver::removeObserver(ActionElement * observer)
}
GameObserver::~GameObserver()
{
LOG("==Destroying GameObserver==");
SAFE_DELETE(targetChooser);
SAFE_DELETE(mLayers);
SAFE_DELETE(phaseRing);
SAFE_DELETE(replacementEffects);
for (size_t i = 0; i < players.size(); ++i)
{
SAFE_DELETE(players[i]);
}
players.clear();
LOG("==GameObserver Destroyed==");
}
void GameObserver::Update(float dt)
{
Player * player = currentPlayer;
@@ -890,8 +948,12 @@ bool GameObserver::WaitForExtraPayment(MTGCardInstance * card)
int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
{
Player * clickedPlayer = NULL;
if (!card)
if (!card) {
clickedPlayer = ((Player *) object);
logAction(clickedPlayer);
} else {
logAction(card);
}
if (targetChooser)
{
int result;
@@ -928,8 +990,8 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
return 1;
}
if (WaitForExtraPayment(card))
return 1;
if (WaitForExtraPayment(card))
return 1;
int reaction = 0;
@@ -959,18 +1021,18 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
}
reaction = mLayers->actionLayer()->isReactingToClick(card);
if (reaction == -1)
return mLayers->actionLayer()->reactToClick(card);
if (reaction == -1)
return mLayers->actionLayer()->reactToClick(card);
}
else
{//this handles abilities on a menu...not just when card is being played
reaction = mLayers->actionLayer()->isReactingToTargetClick(object);
if (reaction == -1)
return mLayers->actionLayer()->reactToTargetClick(object);
if (reaction == -1)
return mLayers->actionLayer()->reactToTargetClick(object);
}
if (!card)
return 0;
if (!card)
return 0;
//Current player's hand
if (currentPlayer->game->hand->hasCard(card) && currentGamePhase == Constants::MTG_PHASE_CLEANUP
@@ -998,7 +1060,6 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
}
return 0;
}
int GameObserver::untap(MTGCardInstance * card)
@@ -1118,3 +1179,247 @@ int GameObserver::targetListIsSet(MTGCardInstance * card)
return 0;
}
ostream& operator<<(ostream& out, GameObserver& g)
{
if(g.startupGameSerialized == "")
{
out << "[init]" << endl;
out << "player=" << g.currentPlayerId + 1 << endl;
if(g.currentGamePhase != -1)
out << "phase=" << g.phaseRing->phaseName(g.currentGamePhase) << endl;
out << "[player1]" << endl;
out << *(g.players[0]) << endl;
out << "[player2]" << endl;
out << *(g.players[1]) << endl;
return out;
}
else
{
out << "rvalues:";
out << saveRandValues(out);
out << endl;
out << g.startupGameSerialized;
}
out << "[do]" << endl;
list<string>::iterator it;
for(it = (g.actionsList.begin()); it != (g.actionsList.end()); it++)
{
out << (*it) << endl;
}
out << "[end]" << endl;
return out;
}
bool GameObserver::parseLine(const string& s)
{
size_t limiter = s.find("=");
if (limiter == string::npos) limiter = s.find(":");
string areaS;
if (limiter != string::npos)
{
areaS = s.substr(0, limiter);
if (areaS.compare("player") == 0)
{
currentPlayerId = atoi(s.substr(limiter + 1).c_str()) - 1;
return true;
}
else if (areaS.compare("phase") == 0)
{
currentGamePhase = PhaseRing::phaseStrToInt(s.substr(limiter + 1).c_str());
return true;
}
}
return false;
}
bool GameObserver::load(const string& ss, bool undo)
{
int state = -1;
string s;
stringstream stream(ss);
string deckFile = players[0]->deckFile;
string deckFileSmall = players[0]->deckFileSmall;
DebugTrace("Loading " + ss);
cleanup();
while (std::getline(stream, s))
{
if (!s.size()) continue;
if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files
if (!s.size()) continue;
if (s[0] == '#') continue;
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
if (s.find("seed ") == 0)
{
// seed = atoi(s.substr(5).c_str());
continue;
}
if (s.find("rvalues:") == 0)
{
loadRandValues(s.substr(8).c_str());
continue;
}
switch (state)
{
case -1:
if (s.compare("[init]") == 0)
state++;
break;
case 0:
if (s.compare("[player1]") == 0)
{
state++;
}
else
{
parseLine(s);
}
break;
case 1:
if (s.compare("[player2]") == 0)
{
state++;
}
else
{
if(!players[0])
players.push_back(new HumanPlayer(this, deckFile, deckFileSmall));
players[0]->parseLine(s);
}
break;
case 2:
if (s.compare("[do]") == 0)
{
state++;
}
else
{
if(!players[1]) {
AIPlayerFactory playerCreator;
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), players[0]));
}
players[1]->parseLine(s);
}
break;
case 3:
if (s.compare("[end]") == 0)
{
turn = 0;
mLayers = NEW DuelLayers();
mLayers->init(this);
currentPlayer = players[currentPlayerId];
phaseRing = NEW PhaseRing(this);
startedAt = time(0);
mRules->initGame(this);
phaseRing->goToPhase(0, currentPlayer, false);
phaseRing->goToPhase(currentGamePhase, currentPlayer);
processActions(undo);
}
else
{
logAction(s);
}
break;
}
}
return true;
}
bool GameObserver::processActions(bool undo)
{
bool result = false;
list<string> copyList = actionsList;
actionsList.clear();
mLoading = true;
list<string>::iterator ite;
float counter = 0.0f;
// To handle undo, we'll remove the last P1 action and all P2 actions after.
if(undo) {
while(copyList.back().find("p2") != string::npos)
copyList.pop_back();
copyList.pop_back();
}
for(ite = copyList.begin(); ite != copyList.end(); ite++)
{
string s = *ite;
Player* p = players[1];
if (s.find("p1") != string::npos)
p = players[0];
MTGGameZone* zone = NULL;
if(s.find(p->game->hand->getName()) != string::npos)
zone = p->game->hand;
else if(s.find(p->game->battlefield->getName()) != string::npos)
zone = p->game->battlefield;
else if(s.find(p->game->graveyard->getName()) != string::npos)
zone = p->game->graveyard;
else if(s.find(p->game->library->getName()) != string::npos)
zone = p->game->library;
if(zone) {
size_t begin = s.find("[")+1;
size_t size = s.find("]")-begin;
int index = atoi(s.substr(begin, size).c_str());
cardClick(zone->cards[index], zone->cards[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("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 {
assert(0);
}
// let's fake an update
Update(counter);
counter += 1.000f;
// or two
Update(counter);
counter += 1.000f;
}
mLoading = false;
return result;
}
void GameObserver::logAction(Player* player, const string& s) {
if(player == players[0])
logAction("p1." + s);
else
logAction("p2." + s);
}
void GameObserver::logAction(MTGCardInstance* card, MTGGameZone* zone) {
stringstream stream;
if(zone == NULL) zone = card->currentZone;
stream << "p" << ((card->controller()==players[0])?"1.":"2.")
<< zone->getName()<< "[" << zone->getIndex(card) << "]";
logAction(stream.str());
}
bool GameObserver::undo()
{
stringstream stream;
stream << *this;
DebugTrace(stream.str());
return load(stream.str(), true);
}

View File

@@ -10,7 +10,6 @@
#include "DeckManager.h"
#include "DeckMetaData.h"
#include "MTGRules.h"
#include "Credits.h"
#include "Translate.h"
#include "Rules.h"
@@ -267,11 +266,7 @@ void GameStateDuel::loadTestSuitePlayers()
game->setPlayers(mPlayers);
mParent->gameType = testSuite->gameType;
game->startGame(mParent->rules);
if (mParent->gameType == GAME_TYPE_MOMIR)
{
game->addObserver(NEW MTGMomirRule(game, -1, MTGCollection()));
}
game->startGame(mParent->gameType, mParent->rules);
}
#endif
@@ -447,19 +442,7 @@ void GameStateDuel::Update(float dt)
if (!game)
{
game = new GameObserver(mPlayers);
game->startGame(mParent->rules);
if (mParent->gameType == GAME_TYPE_MOMIR)
{
game->addObserver(NEW MTGMomirRule(game, -1, MTGCollection()));
}
if (mParent->gameType == GAME_TYPE_STONEHEWER)
{
game->addObserver(NEW MTGStoneHewerRule(game, -1,MTGCollection()));
}
if (mParent->gameType == GAME_TYPE_HERMIT)
{
game->addObserver(NEW MTGHermitRule(game, -1));
}
game->startGame(mParent->gameType, mParent->rules);
//start of in game music code
musictrack = "";
@@ -539,6 +522,7 @@ void GameStateDuel::Update(float dt)
}
//END almosthumane - mulligan
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
menu->Add(MENUITEM_UNDO, "Undo");
menu->Add(MENUITEM_CANCEL, "Cancel");
}
setGamePhase(DUEL_STATE_MENU);
@@ -922,10 +906,14 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
menu->Close();
setGamePhase(DUEL_STATE_CANCEL);
break;
//END almosthumane - mulligan
case MENUITEM_UNDO:
{
game->undo();
menu->Close();
setGamePhase(DUEL_STATE_CANCEL);
break;
}
}
}
}

View File

@@ -389,8 +389,8 @@ void GuiCombat::Render()
damage = 0;
if (activeAtk->card->has(Constants::TRAMPLE))
{
observer->opponent()->mAvatar->SetHotSpot(18, 25);
enemy_avatar.Render(observer->opponent()->mAvatar.get());
observer->opponent()->getIcon()->SetHotSpot(18, 25);
enemy_avatar.Render(observer->opponent()->getIcon().get());
WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT);
mFont->SetColor(ARGB(255, 255, 64, 0));
{

View File

@@ -64,6 +64,12 @@ bool GuiHand::isInHand(CardView* card)
GuiHandOpponent::GuiHandOpponent(GameObserver* observer, MTGHand* hand) :
GuiHand(observer, hand)
{
vector<MTGCardInstance *>::iterator ite;
for(ite = hand->cards.begin(); ite != hand->cards.end(); ite++)
{
WEventZoneChange event(*ite, NULL, hand);
receiveEventPlus(&event);
}
}
void GuiHandOpponent::Render()
@@ -92,6 +98,13 @@ GuiHandSelf::GuiHandSelf(GameObserver* observer, MTGHand* hand) :
backpos.x = SCREEN_WIDTH - 30 * 7 - 14;
backpos.UpdateNow();
}
vector<MTGCardInstance *>::iterator ite;
for(ite = hand->cards.begin(); ite != hand->cards.end(); ite++)
{
WEventZoneChange event(*ite, NULL, hand);
receiveEventPlus(&event);
}
}
GuiHandSelf::~GuiHandSelf()

View File

@@ -56,27 +56,27 @@ void GuiAvatar::Render()
float x0 = actX;
float y0 = actY;
if (player->mAvatar.get())
if (player->getIcon().get())
{
if (corner == BOTTOM_RIGHT)
{
x0 -= player->mAvatar->mWidth * actZ;
y0 -= player->mAvatar->mHeight * actZ;
x0 -= player->getIcon()->mWidth * actZ;
y0 -= player->getIcon()->mHeight * actZ;
}
switch (corner)
{
case TOP_LEFT:
player->mAvatar->SetHotSpot(0, 0);
player->getIcon()->SetHotSpot(0, 0);
break;
case BOTTOM_RIGHT:
player->mAvatar->SetHotSpot(35, 50);
player->getIcon()->SetHotSpot(35, 50);
break;
}
player->mAvatar->SetColor(ARGB((int)actA, 255, avatarRed, avatarRed));
r->RenderQuad(player->mAvatar.get(), actX, actY, actT, actZ, actZ);
player->getIcon()->SetColor(ARGB((int)actA, 255, avatarRed, avatarRed));
r->RenderQuad(player->getIcon().get(), actX, actY, actT, actZ, actZ);
if (mHasFocus)
{
r->FillRect(x0, x0, player->mAvatar->mWidth * actZ, player->mAvatar->mHeight * actZ, ARGB(abs(128 - wave),255,255,255));
r->FillRect(x0, x0, player->getIcon()->mWidth * actZ, player->getIcon()->mHeight * actZ, ARGB(abs(128 - wave),255,255,255));
}
}

View File

@@ -498,6 +498,18 @@ MTGCardInstance * MTGGameZone::hasCard(MTGCardInstance * card)
}
size_t MTGGameZone::getIndex(MTGCardInstance * card)
{
size_t i;
for(i = 0; i < cards.size(); i++)
{
if(cards[i] == card)
return i;
}
return -1;
}
unsigned int MTGGameZone::countByType(const char * value)
{
int result = 0;
@@ -669,7 +681,7 @@ void MTGGameZone::cleanupPhase()
void MTGGameZone::shuffle()
{
std::random_shuffle(cards.begin(), cards.end());
std::random_shuffle(cards.begin(), cards.end(), MRand );
}
void MTGGameZone::addCard(MTGCardInstance * card)
@@ -999,16 +1011,15 @@ ostream& MTGInPlay::toString(ostream& out) const
}
ostream& operator<<(ostream& out, const MTGGameZone& z)
{
return z.toString(out);
}
ostream& operator<<(ostream& out, const MTGPlayerCards& z)
{
out << z.library->nb_cards << " ";
for (int i = 0; i < z.library->nb_cards; i++)
out << z.library->cards[i]->getMTGId() << " ";
for (int i = 0; i < z.nb_cards; i++)
{
out << z.cards[i]->getMTGId();
if(i < z.nb_cards - 1)
out << ",";
}
return out;
// return z.toString(out);
}
bool MTGGameZone::parseLine(const string& ss)
@@ -1022,6 +1033,7 @@ bool MTGGameZone::parseLine(const string& ss)
}
cards.clear();
cardsMap.clear();
nb_cards = 0;
while(s.size())
{
@@ -1072,6 +1084,28 @@ bool MTGGameZone::parseLine(const string& ss)
return result;
}
ostream& operator<<(ostream& out, const MTGPlayerCards& z)
{
if(z.library->cards.size()) {
out << "library=";
out << *(z.library) << endl;
}
if(z.battlefield->cards.size()) {
out << "inplay=";
out << *(z.battlefield) << endl;
}
if(z.graveyard->cards.size()) {
out << "graveyard=";
out << *(z.graveyard) << endl;
}
if(z.hand->cards.size()) {
out << "hand=";
out << *(z.hand) << endl;
}
return out;
}
bool MTGPlayerCards::parseLine(const string& s)
{
size_t limiter = s.find("=");

View File

@@ -10,7 +10,7 @@
#endif
Player::Player(GameObserver *observer, string file, string fileSmall, MTGDeck * deck) :
Damageable(observer, 20), mAvatarName("")
Damageable(observer, 20), mAvatarName(""), offerInterruptOnPhase(Constants::MTG_PHASE_DRAW)
{
if(deck == NULL && file != "testsuite" && file != "remote" && file != "")
deck = NEW MTGDeck(file.c_str(), MTGCollection());
@@ -18,7 +18,7 @@ Player::Player(GameObserver *observer, string file, string fileSmall, MTGDeck *
game = NULL;
deckFile = file;
deckFileSmall = fileSmall;
handsize = 0;
handsize = 0;
manaPool = NEW ManaPool(this);
nomaxhandsize = false;
poisonCount = 0;
@@ -34,6 +34,11 @@ Player::Player(GameObserver *observer, string file, string fileSmall, MTGDeck *
game->setOwner(this);
deckName = deck->meta_name;
}
else
{
game = new MTGPlayerCards();
game->setOwner(this);
}
mDeck = deck;
}
@@ -59,7 +64,7 @@ Player::~Player()
SAFE_DELETE(mDeck);
}
void Player::loadAvatar(string file)
bool Player::loadAvatar(string file, string resName)
{
if (mAvatarTex)
{
@@ -67,8 +72,12 @@ void Player::loadAvatar(string file)
mAvatarTex = NULL;
}
mAvatarTex = WResourceManager::Instance()->RetrieveTexture(file, RETRIEVE_LOCK, TEXTURE_SUB_AVATAR);
if (mAvatarTex)
mAvatar = WResourceManager::Instance()->RetrieveQuad(file, 0, 0, 35, 50, "playerAvatar", RETRIEVE_NORMAL, TEXTURE_SUB_AVATAR);
if (mAvatarTex) {
mAvatar = WResourceManager::Instance()->RetrieveQuad(file, 0, 0, 35, 50, resName, RETRIEVE_NORMAL, TEXTURE_SUB_AVATAR);
return true;
}
return false;
}
const string Player::getDisplayName() const
@@ -93,6 +102,9 @@ int Player::getId()
JQuadPtr Player::getIcon()
{
if(!mAvatarTex)
loadAvatar(mAvatarName);
return mAvatar;
}
@@ -105,7 +117,7 @@ Player * Player::opponent()
HumanPlayer::HumanPlayer(GameObserver *observer, string file, string fileSmall, MTGDeck * deck) :
Player(observer, file, fileSmall, deck)
{
loadAvatar("avatar.jpg");
mAvatarName = "avatar.jpg";
playMode = MODE_HUMAN;
}
@@ -231,6 +243,11 @@ bool Player::parseLine(const string& s)
phaseRing = s.substr(limiter + 1);
return true;
}
else if (areaS.compare("deckfile") == 0)
{
deckFile = s.substr(limiter + 1);
return true;
}
else if (areaS.compare("offerinterruptonphase") == 0)
{
for (int i = 0; i < Constants::NB_MTG_PHASES; i++)
@@ -259,5 +276,22 @@ bool Player::parseLine(const string& s)
ostream& operator<<(ostream& out, const Player& p)
{
return out << *(p.game);
out << *(Damageable*)&p;
string manapoolstring = p.manaPool->toString();
if(manapoolstring != "")
out << "manapool=" << manapoolstring << endl;
if(p.mAvatarName != "")
out << "avatar=" << p.mAvatarName << endl;
if(p.phaseRing != "")
out << "customphasering=" << p.phaseRing << endl;
out << "offerinterruptonphase=" << Constants::MTGPhaseCodeNames[p.offerInterruptOnPhase] << endl;
if(p.deckFile != "")
out << "deckfile=" << p.deckFile << endl;
if(p.game)
{
out << *(p.game);
}
return out;
}

View File

@@ -1,7 +1,7 @@
#include "PrecompiledHeader.h"
#include "Rules.h"
#include "MTGDefinitions.h"
#include "Rules.h"
#include "ManaCost.h"
#include "Player.h"
#include "AIMomirPlayer.h"
@@ -303,6 +303,8 @@ Player * Rules::initPlayer(GameObserver *g, int playerId)
return loadPlayerRandom(g, isAI, GAME_TYPE_RANDOM1);
case GAME_TYPE_RANDOM2:
return loadPlayerRandom(g, isAI, GAME_TYPE_RANDOM2);
default:
return NULL;
}
}
//TODO p may still be NULL, what do we do to handle this? Above switch has no default case to handle the case where p is NULL
@@ -385,7 +387,7 @@ void Rules::initGame(GameObserver *g)
p->preventable = initState.playerData[i].player->preventable;
if (initState.playerData[i].player->mAvatarName.size())
{
p->loadAvatar(initState.playerData[i].player->mAvatarName);
p->mAvatarName = initState.playerData[i].player->mAvatarName;
}
MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay };
MTGGameZone * loadedPlayerZones[] = { initState.playerData[i].player->game->graveyard,
@@ -590,7 +592,7 @@ int Rules::load(string _filename)
return 1;
}
int Rules::strToGameMode(string s)
GameType Rules::strToGameMode(string s)
{
if (s.compare("momir") == 0) return GAME_TYPE_MOMIR;
if (s.compare("random1") == 0) return GAME_TYPE_RANDOM1;

View File

@@ -324,7 +324,7 @@ void StoryDuel::init()
game = new GameObserver(players);
rules->gamemode = GAME_TYPE_STORY;
game->startGame(rules);
game->startGame(GAME_TYPE_STORY, rules);
}
StoryDuel::StoryDuel(TiXmlElement* root, StoryFlow * mParent) :

View File

@@ -19,14 +19,35 @@ namespace wagic
}
using std::vector;
using std::queue;
int randValuesCursor = -1;
vector<int> randValues;
int loadRandValues(string s)
queue<int> loadedRandomValues;
queue<int> usedRandomValues;
ostream& saveRandValues(ostream& out)
{
randValues.clear();
randValuesCursor = -1;
while(usedRandomValues.size())
{
out << usedRandomValues.front();
if(usedRandomValues.size() >= 1)
out << ",";
usedRandomValues.pop();
}
return out;
}
void loadRandValues(string s)
{
while(loadedRandomValues.size())
loadedRandomValues.pop();
while(usedRandomValues.size())
usedRandomValues.pop();
while (s.size())
{
unsigned int value;
@@ -41,18 +62,28 @@ int loadRandValues(string s)
value = atoi(s.c_str());
s = "";
}
if (value) randValues.push_back(value);
if (value) loadedRandomValues.push(value);
}
if (randValues.size()) randValuesCursor = 0;
return 1;
}
ptrdiff_t MRand (ptrdiff_t i)
{
return WRand()%i;
}
int WRand()
{
if (randValuesCursor == -1) return rand();
int result = randValues[randValuesCursor];
randValuesCursor++;
if ((size_t) randValuesCursor >= randValues.size()) randValuesCursor = 0;
int result;
if (!loadedRandomValues.size())
{
result = rand();
}
else
{
result = loadedRandomValues.front();
loadedRandomValues.pop();
}
usedRandomValues.push(result);
return result;
}
@@ -379,4 +410,4 @@ std::string ensureFolder(const std::string & folderName)
result.append("/");
}
return result;
}
}