Files
wagic/projects/mtg/src/PhaseRing.cpp
2013-11-29 11:51:22 +01:00

375 lines
12 KiB
C++

#include "PrecompiledHeader.h"
#include "PhaseRing.h"
#include "MTGDefinitions.h"
#include "Player.h"
#include "WEvent.h"
//Parses a string and gives phase numer
GamePhase PhaseRing::phaseStrToInt(string s)
{
if (s.compare("untap") == 0) return MTG_PHASE_UNTAP;
if (s.compare("upkeep") == 0) return MTG_PHASE_UPKEEP;
if (s.compare("draw") == 0) return MTG_PHASE_DRAW;
if (s.compare("firstmain") == 0) return MTG_PHASE_FIRSTMAIN;
if (s.compare("mainphase") == 0) return MTG_PHASE_FIRSTMAIN;
if (s.compare("combatbegin") == 0) return MTG_PHASE_COMBATBEGIN;
if (s.compare("combatbegins") == 0) return MTG_PHASE_COMBATBEGIN;
if (s.compare("combatattackers") == 0) return MTG_PHASE_COMBATATTACKERS;
if (s.compare("combatblockers") == 0) return MTG_PHASE_COMBATBLOCKERS;
if (s.compare("combatdamage") == 0) return MTG_PHASE_COMBATDAMAGE;
if (s.compare("combatend") == 0) return MTG_PHASE_COMBATEND;
if (s.compare("combatends") == 0) return MTG_PHASE_COMBATEND;
if (s.compare("secondmain") == 0) return MTG_PHASE_SECONDMAIN;
if (s.compare("endofturn") == 0) return MTG_PHASE_ENDOFTURN;
if (s.compare("end") == 0) return MTG_PHASE_ENDOFTURN;
if (s.compare("cleanup") == 0) return MTG_PHASE_CLEANUP;
DebugTrace("PHASERING: Unknown Phase name: " << s);
return MTG_PHASE_INVALID;//was returning first main...why would we return something that is not == s?
}
string PhaseRing::phaseIntToStr(int id)
{
if (id == MTG_PHASE_UNTAP) return "untap";
if (id == MTG_PHASE_UPKEEP) return "upkeep";
if (id == MTG_PHASE_DRAW) return "draw";
if (id == MTG_PHASE_FIRSTMAIN) return "firstmain";
if (id == MTG_PHASE_COMBATBEGIN) return "combatbegins";
if (id == MTG_PHASE_COMBATATTACKERS) return "combatattackers";
if (id == MTG_PHASE_COMBATBLOCKERS) return "combatblockers";
if (id == MTG_PHASE_COMBATDAMAGE) return "combatdamage";
if (id == MTG_PHASE_COMBATEND) return "combatends";
if (id == MTG_PHASE_SECONDMAIN) return "secondmain";
if (id == MTG_PHASE_ENDOFTURN) return "endofturn";
if (id == MTG_PHASE_CLEANUP) return "cleanup";
DebugTrace("PHASERING: Unknown Phase id:%i " << id);
return "";
}
/* Creates a New phase ring with the default rules */
PhaseRing::PhaseRing(GameObserver* observer)
:observer(observer)
{
for (int i = 0; i < observer->getPlayersNumber(); i++)
{
list<Phase*>turnRing;//this is temporary;
if(observer->players[i]->phaseRing.size())
{
addPhase(NEW Phase(MTG_PHASE_BEFORE_BEGIN, observer->players[i]));
vector<string>customRing = split(observer->players[i]->phaseRing,',');
for (unsigned int k = 0;k < customRing.size(); k++)
{
GamePhase customOrder = phaseStrToInt(customRing[k]);
Phase * phase = NEW Phase(customOrder, observer->players[i]);
addPhase(phase);
turnRing.push_back(phase);
}
addPhase( NEW Phase(MTG_PHASE_AFTER_EOT, observer->players[i]));
}
else
{
for (int j = 0; j < NB_MTG_PHASES; j++)
{
Phase * phase = NEW Phase((GamePhase)j, observer->players[i]);
addPhase(phase);
turnRing.push_back(phase);
}
}
observer->gameTurn.push_back(turnRing);
//push back the complete turn of a player for easy refference.
//since they are pushed back per player you can denote that gameTurn[playerid] is the exact turn for that player.
}
turn = currentTurn();
current = turn.begin();
}
list<Phase*> PhaseRing::currentTurn()
{
list<Phase*> temp = observer->gameTurn[observer->currentPlayer->getId()];
list<Phase *>::iterator tempiter;
currentTurnList.clear();
for (tempiter = temp.begin(); tempiter != temp.end(); tempiter++)
{
Phase * currentIter = *tempiter;
currentTurnList.push_back(currentIter);
}
return currentTurnList;
}
list<Phase*> PhaseRing::nextTurn()
{
list<Phase*> temp = observer->gameTurn[observer->nextTurnsPlayer()->getId()];
list<Phase*>::iterator tempiter;
Phase * currentIter = NULL;
nextTurnList.clear();
for (tempiter = temp.begin(); tempiter != temp.end(); tempiter++)
{
currentIter = *tempiter;
nextTurnList.push_back(currentIter);
}
return nextTurnList;
}
PhaseRing::~PhaseRing()
{
list<Phase *>::iterator it;
for (it = ring.begin(); it != ring.end(); it++)
{
Phase * currentPhase = *it;
delete (currentPhase);
}
for (it = extraPhases.begin();it != extraPhases.end();it++)
{
Phase * currentPhase = *it;
SAFE_DELETE(currentPhase);
}
}
//Tells if next phase will be another Damage phase rather than combat ends
bool PhaseRing::extraDamagePhase(int id)
{
if (id != MTG_PHASE_COMBATEND) return false;
if (observer->combatStep != END_FIRST_STRIKE) return false;
for (int j = 0; j < 2; ++j)
{
MTGGameZone * z = observer->players[j]->game->inPlay;
for (int i = 0; i < z->nb_cards; ++i)
{
MTGCardInstance * card = z->cards[i];
if ((card->isAttacker() || card->isDefenser()) && !(card->has(Constants::FIRSTSTRIKE) || card->has(
Constants::DOUBLESTRIKE))) return true;
}
}
return false;
}
const string& PhaseRing::phaseName(int id)
{
static const string combatPhase2("Combat Damage (2)");
if (extraDamagePhase(id)) return combatPhase2;
return Constants::MTGPhaseNames[id];
}
Phase * PhaseRing::getCurrentPhase()
{
if (current == turn.end())
{
turn = nextTurn();
current = turn.begin();
}
return *current;
}
Phase * PhaseRing::forward(bool sendEvents)
{
Phase * cPhaseOld = *current;
//the following is a present event before change
//if we need to remove a phase before it changes the game
//needs to be aware of what phase we're coming from and going to
//before we actually increment the phase iter. {
bool notEnd = false;
size_t turnSteps = turn.size();
if (current != turn.end())
{
current++;
if(current == turn.end())
current--;
else
notEnd = true;
}
//Warn the layers about the current phase before changing
WEvent * e = NEW WEventPhasePreChange(cPhaseOld,*current);
observer->receiveEvent(e);
if(notEnd)
{
current--;
}
size_t turnStepsNow = turn.size();
if(turnSteps != turnStepsNow)
return forward(sendEvents);
if (current != turn.end())
current++;
if (current == turn.end())
{
turn = nextTurn();
current = turn.begin();
}
if (sendEvents)
{
//Warn the layers about the phase Change
WEvent * e = NEW WEventPhaseChange(cPhaseOld, *current);
observer->receiveEvent(e);
}
return *current;
}
Phase * PhaseRing::goToPhase(int id, Player * player, bool sendEvents)
{
Phase * currentPhase = getCurrentPhase();
while (currentPhase->id != id)
{ //Dangerous, risk for inifinte loop !
DebugTrace("PhasingRing: goToPhase called, current phase is " << phaseName(currentPhase->id));
currentPhase = forward(sendEvents);
if(id == MTG_PHASE_INVALID)
{
DebugTrace("stopping on this phase becuase goToPhase was told to go a phase that doesn't exist:" << phaseName(currentPhase->id));
break;
}
if(currentPhase->player == player && currentPhase->id == id)
break;
}
return currentPhase;
}
int PhaseRing::addPhase(Phase * phase)
{
ring.push_back(phase);
return 1;
}
int PhaseRing::addCombatAfter(Player* player, int after_id, bool withMain)
{
list<Phase *>::iterator it;
Phase * beforeLeaving;
for (it = turn.begin(); it != turn.end(); it++)
{
Phase * currentPhase = *it;
if (currentPhase->id == after_id)
{
beforeLeaving = currentPhase;
it++;
Phase * addPhase = NULL;
list<Phase *>::iterator findP;
for(findP = ring.begin();findP != ring.end();findP++)
{
addPhase = *findP;
Phase * toAdd = NULL;
bool add = false;
if(addPhase->player == player)
{
switch(addPhase->id)
{
case MTG_PHASE_COMBATEND:
{
toAdd = NEW Phase(*addPhase);
toAdd->isExtra = true;
turn.insert(it, toAdd);
extraPhases.push_back(toAdd);
observer->combatStep = BLOCKERS;
if(withMain)
{
toAdd = NEW Phase(*getPhase(MTG_PHASE_SECONDMAIN));
toAdd->isExtra = true;
extraPhases.push_back(toAdd);
turn.insert(it, toAdd);
}
Phase * check = getCurrentPhase();
bool checking = false;
if(check != beforeLeaving)
checking = true;
while(checking)
{
current--;//put us back to where we were.
check = getCurrentPhase();
if(check == beforeLeaving)
{
checking = false;
current++; //now move to the next phase, which will be the added phases.
}
}
return 1;
}
case MTG_PHASE_COMBATDAMAGE:
toAdd = NEW Phase(*addPhase);
add = true;
break;
case MTG_PHASE_COMBATBLOCKERS:
toAdd = NEW Phase(*addPhase);
add = true;
break;
case MTG_PHASE_COMBATATTACKERS:
toAdd = NEW Phase(*addPhase);
add = true;
break;
case MTG_PHASE_COMBATBEGIN:
toAdd = NEW Phase(*addPhase);
add = true;
break;
default:
break;
}
if(add)
{
toAdd->isExtra = true;
turn.insert(it, toAdd);
extraPhases.push_back(toAdd);
}
}
}
}
}
return 0;
}
Phase * PhaseRing::getPhase(int _id)
{
list<Phase *>::iterator it;
for (it = turn.begin(); it != turn.end(); it++)
{
Phase * currentPhase = *it;
if (currentPhase->id == _id)
{
return currentPhase;
}
}
return NULL;
}
int PhaseRing::addPhaseAfter(GamePhase id, Player* player, int after_id)
{
list<Phase *>::iterator it;
for (it = turn.begin(); it != turn.end(); it++)
{
Phase * currentPhase = *it;
if (currentPhase->id == after_id)
{
it++;
Phase * addPhase = NULL;
list<Phase *>::iterator findP;
for(findP = ring.begin();findP != ring.end();findP++)
{
addPhase = *findP;
if(addPhase->id == id && addPhase->player == player)
{
Phase * toAdd = NEW Phase(*addPhase);
toAdd->isExtra = true;
turn.insert(it, toAdd);
extraPhases.push_back(toAdd);
return 1;
}
}
}
}
return 0;
}
int PhaseRing::removePhase(int id)
{
list<Phase *>::iterator it = turn.begin();
while (it != turn.end())
{
Phase * currentPhase = *it;
if (currentPhase->id == id)
{
if (current == it)
current++; //Avoid our cursor to get invalidated
turn.erase(it);
return 1;
}
else
{
it++;
}
}
return 0;
}