779 lines
25 KiB
C++
779 lines
25 KiB
C++
#include "PrecompiledHeader.h"
|
|
|
|
#include "CardGui.h"
|
|
#include "Navigator.h"
|
|
|
|
namespace
|
|
{
|
|
const Pos kDefaultCardPosition(300, 150, 1.0, 0.0, 220);
|
|
// the diagonal length of a card, doubled
|
|
const float kOverrideDistance = sqrtf(powf(CardGui::Width, 2) + powf(CardGui::Height, 2)) * 2;
|
|
|
|
enum
|
|
{
|
|
kCardZone_Unknown = -1,
|
|
kCardZone_PlayerHand = 0,
|
|
kCardZone_PlayerAvatar,
|
|
kCardZone_PlayerLibrary,
|
|
kCardZone_PlayerGraveyard,
|
|
kCardZone_PlayerLands,
|
|
kCardZone_PlayerCreatures,
|
|
kCardZone_PlayerEnchantmentsAndArtifacts,
|
|
kCardZone_AIHand,
|
|
kCardZone_AIAvatar,
|
|
kCardZone_AILibrary,
|
|
kCardZone_AIGraveyard,
|
|
kCardZone_AILands,
|
|
kCardZone_AICreatures,
|
|
kCardZone_AIEnchantmentsAndArtifacts
|
|
};
|
|
}
|
|
|
|
/**
|
|
** Helper class to Navigator. Represents a group of cards on the battlefield.
|
|
*/
|
|
class CardZone
|
|
{
|
|
public:
|
|
|
|
/*
|
|
**
|
|
*/
|
|
CardZone() :
|
|
mCurrentCard(0)
|
|
{
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void AddCard(PlayGuiObject* inCard)
|
|
{
|
|
mCards.push_back(inCard);
|
|
inCard->zoom = 1.0f;
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void RemoveCard(PlayGuiObject* inCard)
|
|
{
|
|
bool found = false;
|
|
for (size_t index = 0; index < mCards.size(); ++index)
|
|
{
|
|
if (mCards[index] == inCard)
|
|
{
|
|
// if mCurrentCard points to a card at the end of an item but we're
|
|
// about to delete something earlier in the container, mCurrentCard
|
|
// won't be pointing anymore to the same element, so shift it
|
|
if (mCurrentCard >= index)
|
|
{
|
|
if (mCurrentCard > 0)
|
|
--mCurrentCard;
|
|
}
|
|
mCards[index]->zoom = 1.0f;
|
|
|
|
mCards.erase(mCards.begin() + index);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(found);
|
|
}
|
|
|
|
/*
|
|
** Generic handling of navigation - left/right moves through the container,
|
|
** up/down is rejected & moves to the next zone
|
|
*/
|
|
virtual bool HandleSelection(JButton inKey)
|
|
{
|
|
bool changeZone = true;
|
|
size_t oldIndex = mCurrentCard;
|
|
if (inKey == JGE_BTN_LEFT)
|
|
{
|
|
if (mCurrentCard > 0)
|
|
{
|
|
--mCurrentCard;
|
|
changeZone = false;
|
|
}
|
|
}
|
|
|
|
if (inKey == JGE_BTN_RIGHT)
|
|
{
|
|
if (mCurrentCard + 1 < mCards.size())
|
|
{
|
|
++mCurrentCard;
|
|
changeZone = false;
|
|
}
|
|
}
|
|
|
|
if (oldIndex != mCurrentCard)
|
|
{
|
|
AnimateSelectionChange(oldIndex, true);
|
|
AnimateSelectionChange(mCurrentCard, false);
|
|
}
|
|
return changeZone;
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void AnimateSelectionChange(size_t inIndex, bool inLeaving)
|
|
{
|
|
if (inIndex < mCards.size())
|
|
{
|
|
if (inLeaving)
|
|
{
|
|
mCards[inIndex]->zoom = 1.0f;
|
|
mCards[inIndex]->Leaving(JGE_BTN_NONE);
|
|
}
|
|
else
|
|
{
|
|
mCards[inIndex]->zoom = 1.4f;
|
|
mCards[inIndex]->Entering();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Return a neighbour CardZone (ie where to navigate to given a direction)
|
|
** If there is no neighbour in that direction, return self (this ensures that
|
|
** the parent Navigator class always has a legal currentZone pointer)
|
|
*/
|
|
CardZone* GetNeighbour(JButton inDirection)
|
|
{
|
|
CardZone* neighbour = this;
|
|
if (mNeighbours[inDirection])
|
|
neighbour = mNeighbours[inDirection];
|
|
|
|
return neighbour;
|
|
}
|
|
|
|
/*
|
|
** When a zone change occurs, this will be called. This allows a zone
|
|
** to 'pass through' so to speak, if a zone is empty, allow the navigation to
|
|
** travel to the next neighbour
|
|
*/
|
|
virtual CardZone* EnterZone(JButton inDirection)
|
|
{
|
|
if (mCards.empty())
|
|
{
|
|
if (inDirection != JGE_BTN_NONE)
|
|
{
|
|
CardZone* nextNeighbour = GetNeighbour(inDirection);
|
|
if (nextNeighbour)
|
|
return nextNeighbour->EnterZone(inDirection);
|
|
}
|
|
}
|
|
|
|
// when entering a zone, animate the selection of the current card
|
|
AnimateSelectionChange(mCurrentCard, false);
|
|
return this;
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void LeaveZone(JButton inDirection)
|
|
{
|
|
AnimateSelectionChange(mCurrentCard, true);
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
PlayGuiObject* GetCurrentCard()
|
|
{
|
|
PlayGuiObject* current = NULL;
|
|
if (mCards.size())
|
|
{
|
|
if (mCurrentCard < mCards.size())
|
|
{
|
|
current = mCards[mCurrentCard];
|
|
}
|
|
}
|
|
return current;
|
|
}
|
|
|
|
std::vector<PlayGuiObject*> mCards;
|
|
size_t mCurrentCard;
|
|
|
|
// you'll typically have up to 4 neighbours, ie left/right/up/down
|
|
std::map<JButton, CardZone*> mNeighbours;
|
|
};
|
|
|
|
/*
|
|
** Derivation of CardZone, but with special key handling for the grid style layout,
|
|
** where we need to navigate up/down as well as left/right
|
|
*/
|
|
class GridCardZone: public CardZone
|
|
{
|
|
public:
|
|
GridCardZone(bool inEnforceAxisAlignment = false) :
|
|
mEnforceAxisAlignment(inEnforceAxisAlignment)
|
|
{
|
|
}
|
|
|
|
virtual bool HandleSelection(JButton inKey)
|
|
{
|
|
size_t oldIndex = mCurrentCard;
|
|
|
|
float minDistance = 100000;
|
|
int selectedCardIndex = -1;
|
|
bool isHorizontal = (inKey == JGE_BTN_LEFT || inKey == JGE_BTN_RIGHT);
|
|
|
|
for (size_t index = 0; index < mCards.size(); ++index)
|
|
{
|
|
// skip yourself
|
|
if (mCurrentCard == index)
|
|
continue;
|
|
|
|
// skip if the card isn't on the same axis that we're stepping in
|
|
// this flag is an optional override. If enabled, it forces you to only be able to thumb over to the next card
|
|
// that is exactly on the same x or y coordinate axis - any card not strictly parallel is ignored.
|
|
if (mEnforceAxisAlignment)
|
|
{
|
|
if ((isHorizontal && mCards[mCurrentCard]->y != mCards[index]->y) || (!isHorizontal && mCards[mCurrentCard]->x
|
|
!= mCards[index]->x))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// if it's going in the wrong direction, skip
|
|
if (inKey == JGE_BTN_RIGHT && mCards[index]->x <= mCards[mCurrentCard]->x)
|
|
continue;
|
|
if (inKey == JGE_BTN_LEFT && mCards[index]->x >= mCards[mCurrentCard]->x)
|
|
continue;
|
|
if (inKey == JGE_BTN_DOWN && mCards[index]->y <= mCards[mCurrentCard]->y)
|
|
continue;
|
|
if (inKey == JGE_BTN_UP && mCards[index]->y >= mCards[mCurrentCard]->y)
|
|
continue;
|
|
|
|
// we've found a card on the same axis, stash its value & compare against the previous
|
|
float yDiff = fabs(mCards[mCurrentCard]->y - mCards[index]->y);
|
|
float xDiff = fabs(mCards[mCurrentCard]->x - mCards[index]->x);
|
|
float distance = sqrtf(yDiff * yDiff + xDiff * xDiff);
|
|
|
|
// CardSelector does this thing where if the distance in the axis you're moving is less than the distance od the card on the opposite axis,
|
|
// it would ignore the move - this made for some weird behavior where the UI wouldn't let you move in certain directions when a card looked reachable.
|
|
// instead, I'm using a different logic - if there's a card in the direction that you're stepping, and it's within a defined radius, go for it.
|
|
if (distance < minDistance && distance < kOverrideDistance)
|
|
{
|
|
minDistance = distance;
|
|
selectedCardIndex = index;
|
|
}
|
|
}
|
|
|
|
bool changeZone = true;
|
|
if (selectedCardIndex != -1)
|
|
{
|
|
mCurrentCard = selectedCardIndex;
|
|
changeZone = false;
|
|
|
|
if (oldIndex != mCurrentCard)
|
|
{
|
|
AnimateSelectionChange(oldIndex, true);
|
|
AnimateSelectionChange(mCurrentCard, false);
|
|
}
|
|
}
|
|
|
|
return changeZone;
|
|
}
|
|
|
|
protected:
|
|
bool mEnforceAxisAlignment;
|
|
};
|
|
|
|
/*
|
|
**
|
|
*/
|
|
class HandCardZone: public GridCardZone
|
|
{
|
|
public:
|
|
|
|
/*
|
|
** the card hand zone operates slightly differently than the default zones:
|
|
** if entering via up/down,
|
|
** set the current card selection to the bottom/top card
|
|
*/
|
|
virtual CardZone* EnterZone(JButton inDirection)
|
|
{
|
|
// TODO, check if the hand is flattened
|
|
if (mCards.size())
|
|
{
|
|
if (inDirection == JGE_BTN_UP)
|
|
mCurrentCard = mCards.size() - 1;
|
|
else if (inDirection == JGE_BTN_DOWN)
|
|
mCurrentCard = 0;
|
|
}
|
|
|
|
return CardZone::EnterZone(inDirection);
|
|
}
|
|
};
|
|
|
|
/*
|
|
**
|
|
*/
|
|
class LandCardZone: public GridCardZone
|
|
{
|
|
public:
|
|
virtual CardZone* EnterZone(JButton inDirection);
|
|
};
|
|
|
|
/*
|
|
**
|
|
*/
|
|
class CreatureCardZone: public GridCardZone
|
|
{
|
|
public:
|
|
virtual CardZone* EnterZone(JButton inDirection);
|
|
};
|
|
|
|
/*
|
|
** The base class dictates normally, if you enter a zone and it's empty, move to
|
|
** the next zone in the same direction.
|
|
** Adding an override here - if there are no creatures in play but there are land,
|
|
** and we're moving horizontally, jump up to the land instead
|
|
*/
|
|
CardZone* CreatureCardZone::EnterZone(JButton inDirection)
|
|
{
|
|
if ((inDirection == JGE_BTN_LEFT || inDirection == JGE_BTN_RIGHT) && mCards.empty())
|
|
{
|
|
LandCardZone* landZone = dynamic_cast<LandCardZone*> (mNeighbours[JGE_BTN_DOWN]);
|
|
if (landZone == NULL)
|
|
{
|
|
landZone = dynamic_cast<LandCardZone*> (mNeighbours[JGE_BTN_UP]);
|
|
}
|
|
|
|
if (landZone && !landZone->mCards.empty())
|
|
{
|
|
return landZone->EnterZone(inDirection);
|
|
}
|
|
}
|
|
|
|
return CardZone::EnterZone(inDirection);
|
|
}
|
|
|
|
/*
|
|
** Same pattern to the CreatureCardZone pattern - if moving through an empty land zone,
|
|
** set the focus on the land zone if it has cards
|
|
*/
|
|
CardZone* LandCardZone::EnterZone(JButton inDirection)
|
|
{
|
|
if ((inDirection == JGE_BTN_LEFT || inDirection == JGE_BTN_RIGHT) && mCards.empty())
|
|
{
|
|
CreatureCardZone* creatureZone = dynamic_cast<CreatureCardZone*> (mNeighbours[JGE_BTN_DOWN]);
|
|
if (creatureZone == NULL)
|
|
{
|
|
creatureZone = dynamic_cast<CreatureCardZone*> (mNeighbours[JGE_BTN_UP]);
|
|
}
|
|
|
|
if (creatureZone && !creatureZone->mCards.empty())
|
|
{
|
|
return creatureZone->EnterZone(inDirection);
|
|
}
|
|
}
|
|
|
|
return CardZone::EnterZone(inDirection);
|
|
}
|
|
|
|
/*
|
|
** Constructor. All the navigation logic is initialized here, by pairing up each card zone with a set of neighbours.
|
|
*/
|
|
Navigator::Navigator(DuelLayers* inDuelLayers) :
|
|
mDrawPosition(kDefaultCardPosition), mDuelLayers(inDuelLayers), mLimitorEnabled(false)
|
|
{
|
|
assert(mDuelLayers);
|
|
|
|
// initialize the cardZone layout
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerHand, NEW HandCardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerAvatar, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerLibrary, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerGraveyard, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerLands, NEW LandCardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerCreatures, NEW CreatureCardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_PlayerEnchantmentsAndArtifacts, NEW GridCardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AIHand, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AIAvatar, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AILibrary, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AIGraveyard, NEW CardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AILands, NEW LandCardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AICreatures, NEW CreatureCardZone()));
|
|
mCardZones.insert(std::pair<int, CardZone*>(kCardZone_AIEnchantmentsAndArtifacts, NEW GridCardZone()));
|
|
|
|
// navigation rules: each zone has up to 4 neighbours, specified here
|
|
mCardZones[kCardZone_PlayerHand]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_PlayerHand]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerAvatar];
|
|
mCardZones[kCardZone_PlayerHand]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerCreatures];
|
|
mCardZones[kCardZone_PlayerHand]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_AIAvatar];
|
|
|
|
mCardZones[kCardZone_PlayerAvatar]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_PlayerHand];
|
|
mCardZones[kCardZone_PlayerAvatar]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerLibrary];
|
|
mCardZones[kCardZone_PlayerAvatar]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts];
|
|
mCardZones[kCardZone_PlayerAvatar]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerLands];
|
|
|
|
mCardZones[kCardZone_PlayerLibrary]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_PlayerGraveyard];
|
|
mCardZones[kCardZone_PlayerLibrary]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerAvatar];
|
|
mCardZones[kCardZone_PlayerLibrary]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerLands];
|
|
mCardZones[kCardZone_PlayerLibrary]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerAvatar];
|
|
|
|
mCardZones[kCardZone_PlayerGraveyard]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_PlayerHand];
|
|
mCardZones[kCardZone_PlayerGraveyard]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerLibrary];
|
|
mCardZones[kCardZone_PlayerGraveyard]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerCreatures];
|
|
mCardZones[kCardZone_PlayerGraveyard]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerAvatar];
|
|
|
|
mCardZones[kCardZone_PlayerLands]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_PlayerCreatures];
|
|
mCardZones[kCardZone_PlayerLands]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerAvatar];
|
|
mCardZones[kCardZone_PlayerLands]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts];
|
|
mCardZones[kCardZone_PlayerLands]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerAvatar];
|
|
|
|
mCardZones[kCardZone_PlayerCreatures]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AICreatures];
|
|
mCardZones[kCardZone_PlayerCreatures]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerLands];
|
|
mCardZones[kCardZone_PlayerCreatures]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts];
|
|
mCardZones[kCardZone_PlayerCreatures]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerHand];
|
|
|
|
mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_PlayerCreatures];
|
|
mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerLands];
|
|
// experiment, allow round tripping from the left edge over to the right side
|
|
mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerAvatar];
|
|
mCardZones[kCardZone_PlayerEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerCreatures];
|
|
|
|
mCardZones[kCardZone_AIHand]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_AIHand]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_AIEnchantmentsAndArtifacts];
|
|
mCardZones[kCardZone_AIHand]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_AILibrary];
|
|
|
|
mCardZones[kCardZone_AIAvatar]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AILands];
|
|
mCardZones[kCardZone_AIAvatar]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_AIHand];
|
|
mCardZones[kCardZone_AIAvatar]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_AILibrary];
|
|
mCardZones[kCardZone_AIAvatar]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerHand];
|
|
|
|
mCardZones[kCardZone_AILibrary]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AIGraveyard];
|
|
mCardZones[kCardZone_AILibrary]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_AILands];
|
|
mCardZones[kCardZone_AILibrary]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_AILibrary]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_AILands];
|
|
|
|
mCardZones[kCardZone_AIGraveyard]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_AIGraveyard]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_AILibrary];
|
|
mCardZones[kCardZone_AIGraveyard]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_AIGraveyard]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_AILands];
|
|
|
|
mCardZones[kCardZone_AILands]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_AILands]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_AICreatures];
|
|
mCardZones[kCardZone_AILands]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_AIEnchantmentsAndArtifacts];
|
|
mCardZones[kCardZone_AILands]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerHand];
|
|
|
|
mCardZones[kCardZone_AICreatures]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AILands];
|
|
mCardZones[kCardZone_AICreatures]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_PlayerCreatures];
|
|
mCardZones[kCardZone_AICreatures]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_AIEnchantmentsAndArtifacts];
|
|
mCardZones[kCardZone_AICreatures]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_PlayerHand];
|
|
|
|
mCardZones[kCardZone_AIEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_UP] = mCardZones[kCardZone_AIAvatar];
|
|
mCardZones[kCardZone_AIEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_DOWN] = mCardZones[kCardZone_AICreatures];
|
|
// experiment, allow round tripping from the left edge over to the right side
|
|
mCardZones[kCardZone_AIEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_LEFT] = mCardZones[kCardZone_PlayerHand];
|
|
mCardZones[kCardZone_AIEnchantmentsAndArtifacts]->mNeighbours[JGE_BTN_RIGHT] = mCardZones[kCardZone_AICreatures];
|
|
|
|
mCurrentZone = mCardZones[kCardZone_PlayerAvatar];
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
Navigator::~Navigator()
|
|
{
|
|
std::map<int, CardZone*>::iterator iter = mCardZones.begin();
|
|
for (; iter != mCardZones.end(); ++iter)
|
|
{
|
|
SAFE_DELETE(iter->second);
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
bool Navigator::CheckUserInput(JButton inKey)
|
|
{
|
|
bool result = true;
|
|
|
|
switch (inKey)
|
|
{
|
|
case JGE_BTN_SEC:
|
|
GameObserver::GetInstance()->cancelCurrentAction();
|
|
return true;
|
|
case JGE_BTN_OK:
|
|
GameObserver::GetInstance()->ButtonPressed(GetCurrentCard());
|
|
return true;
|
|
break;
|
|
case JGE_BTN_LEFT:
|
|
case JGE_BTN_RIGHT:
|
|
case JGE_BTN_UP:
|
|
case JGE_BTN_DOWN:
|
|
HandleKeyStroke(inKey);
|
|
break;
|
|
case JGE_BTN_CANCEL:
|
|
mDrawMode = (mDrawMode + 1) % DrawMode::kNumDrawModes;
|
|
if (mDrawMode == DrawMode::kText)
|
|
options[Options::DISABLECARDS].number = 1;
|
|
else
|
|
options[Options::DISABLECARDS].number = 0;
|
|
break;
|
|
default:
|
|
result = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool Navigator::CheckUserInput(int x, int y)
|
|
{
|
|
// TODO - figure out what to do with mouse support
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
** reposition the selected card's draw location
|
|
*/
|
|
void Navigator::Update(float dt)
|
|
{
|
|
float boundary = mDuelLayers->RightBoundary();
|
|
float position = boundary - CardGui::BigWidth / 2;
|
|
if (GetCurrentCard() != NULL)
|
|
{
|
|
if ((GetCurrentCard()->x + CardGui::Width / 2 > position - CardGui::BigWidth / 2) && (GetCurrentCard()->x - CardGui::Width
|
|
/ 2 < position + CardGui::BigWidth / 2))
|
|
{
|
|
position = CardGui::BigWidth / 2 - 10;
|
|
}
|
|
}
|
|
|
|
if (position < CardGui::BigWidth / 2)
|
|
position = CardGui::BigWidth / 2;
|
|
|
|
mDrawPosition.x = position;
|
|
mDrawPosition.Update(dt);
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
PlayGuiObject* Navigator::GetCurrentCard()
|
|
{
|
|
return mCurrentZone ? mCurrentZone->GetCurrentCard() : NULL;
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Navigator::Render()
|
|
{
|
|
if (GetCurrentCard() != NULL)
|
|
{
|
|
GetCurrentCard()->Render();
|
|
|
|
CardView* card = dynamic_cast<CardView*> (GetCurrentCard());
|
|
if (card)
|
|
{
|
|
card->DrawCard(mDrawPosition, mDrawMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Navigator::HandleKeyStroke(JButton inKey)
|
|
{
|
|
assert(mCurrentZone);
|
|
if (mCurrentZone)
|
|
{
|
|
bool changeZone = mCurrentZone->HandleSelection(inKey);
|
|
|
|
if (changeZone && !mLimitorEnabled)
|
|
{
|
|
mCurrentZone->LeaveZone(inKey);
|
|
mCurrentZone = mCurrentZone->GetNeighbour(inKey);
|
|
mCurrentZone = mCurrentZone->EnterZone(inKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** unused. This is CardSelector specific.
|
|
*/
|
|
void Navigator::PopLimitor()
|
|
{
|
|
}
|
|
|
|
/*
|
|
** same as above.
|
|
*/
|
|
void Navigator::PushLimitor()
|
|
{
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Navigator::Limit(LimitorFunctor<PlayGuiObject>* inLimitor, CardView::SelectorZone inZone)
|
|
{
|
|
mLimitorEnabled = (inLimitor != NULL);
|
|
if (inZone == CardView::handZone)
|
|
{
|
|
mCurrentZone->LeaveZone(JGE_BTN_NONE);
|
|
|
|
if (mLimitorEnabled)
|
|
{
|
|
mCurrentZoneStack.push(mCurrentZone);
|
|
mCurrentZone = mCardZones[kCardZone_PlayerHand];
|
|
}
|
|
else
|
|
{
|
|
mCurrentZone = mCurrentZoneStack.top();
|
|
mCurrentZoneStack.pop();
|
|
assert(mCurrentZone);
|
|
if (mCurrentZone == NULL)
|
|
{
|
|
mCurrentZone = mCardZones[kCardZone_PlayerHand];
|
|
}
|
|
}
|
|
|
|
mCurrentZone->EnterZone(JGE_BTN_NONE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
int Navigator::CardToCardZone(PlayGuiObject* inCard)
|
|
{
|
|
int result = kCardZone_Unknown;
|
|
GuiAvatar* avatar = dynamic_cast<GuiAvatar*> (inCard);
|
|
if (avatar)
|
|
{
|
|
if (avatar->player->isAI())
|
|
{
|
|
result = kCardZone_AIAvatar;
|
|
}
|
|
else
|
|
{
|
|
result = kCardZone_PlayerAvatar;
|
|
}
|
|
}
|
|
|
|
GuiGraveyard* graveyard = dynamic_cast<GuiGraveyard*> (inCard);
|
|
if (graveyard)
|
|
{
|
|
if (graveyard->player->isAI())
|
|
{
|
|
result = kCardZone_AIGraveyard;
|
|
}
|
|
else
|
|
{
|
|
result = kCardZone_PlayerGraveyard;
|
|
}
|
|
}
|
|
|
|
GuiLibrary* library = dynamic_cast<GuiLibrary*> (inCard);
|
|
if (library)
|
|
{
|
|
if (library->player->isAI())
|
|
{
|
|
result = kCardZone_AILibrary;
|
|
}
|
|
else
|
|
{
|
|
result = kCardZone_PlayerLibrary;
|
|
}
|
|
}
|
|
|
|
GuiOpponentHand* opponentHand = dynamic_cast<GuiOpponentHand*> (inCard);
|
|
if (opponentHand)
|
|
{
|
|
result = kCardZone_AIHand;
|
|
}
|
|
|
|
CardView* card = dynamic_cast<CardView*> (inCard);
|
|
{
|
|
if (card)
|
|
{
|
|
if (card->owner == CardView::handZone)
|
|
{
|
|
result = kCardZone_PlayerHand;
|
|
}
|
|
else if (card->owner == CardView::playZone)
|
|
{
|
|
int isAI = card->getCard()->owner->isAI();
|
|
|
|
if (card->getCard()->isCreature())
|
|
{
|
|
result = isAI ? kCardZone_AICreatures : kCardZone_PlayerCreatures;
|
|
}
|
|
else if (card->getCard()->isLand())
|
|
{
|
|
result = isAI ? kCardZone_AILands : kCardZone_PlayerLands;
|
|
}
|
|
else if (card->getCard()->isSpell())
|
|
{
|
|
|
|
if (card->getCard()->target != NULL)
|
|
isAI = card->getCard()->target->owner->isAI();
|
|
|
|
// nasty hack: the lines above don't always work, as when an enchantment comes into play, its ability hasn't been activated yet,
|
|
// so it doesn't yet have a target. Instead, we now look at the card's position, if it's in the top half of the screen, it goes into an AI zone
|
|
//isAI = card->y < JRenderer::GetInstance()->GetActualHeight() / 2;
|
|
|
|
// enchantments that target creatures are treated as part of the creature zone
|
|
if (card->getCard()->spellTargetType.find("creature") != string::npos)
|
|
{
|
|
result = isAI ? kCardZone_AICreatures : kCardZone_PlayerCreatures;
|
|
}
|
|
else if (card->getCard()->spellTargetType.find("land") != string::npos)
|
|
{
|
|
result = isAI ? kCardZone_AILands : kCardZone_PlayerLands;
|
|
}
|
|
else
|
|
{
|
|
result = isAI ? kCardZone_AIEnchantmentsAndArtifacts : kCardZone_PlayerEnchantmentsAndArtifacts;
|
|
}
|
|
}
|
|
else
|
|
assert(false);
|
|
}
|
|
else
|
|
{
|
|
assert(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
assert(result != kCardZone_Unknown);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Navigator::Add(PlayGuiObject* card)
|
|
{
|
|
// figure out what card's been added, add it to the appropriate pile
|
|
int zone = CardToCardZone(card);
|
|
if (zone != kCardZone_Unknown)
|
|
{
|
|
mCardZones[zone]->AddCard(card);
|
|
}
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Navigator::Remove(PlayGuiObject* card)
|
|
{
|
|
int zone = CardToCardZone(card);
|
|
if (zone != kCardZone_Unknown)
|
|
{
|
|
mCardZones[zone]->RemoveCard(card);
|
|
}
|
|
}
|