diff --git a/projects/mtg/Makefile b/projects/mtg/Makefile index cc69ee93a..2cf036426 100644 --- a/projects/mtg/Makefile +++ b/projects/mtg/Makefile @@ -1,4 +1,4 @@ -OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardPrimitive.o objs/CardSelector.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DeckDataWrapper.o objs/DeckMetaData.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateAwards.o objs/GameStateDeckViewer.o objs/GameStateDuel.o objs/DeckManager.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GameStateStory.o objs/GameStateTransitions.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/Logger.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGPack.o objs/MTGRules.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/Pos.o objs/PrecompiledHeader.o objs/PriceList.o objs/ReplacementEffects.o objs/Rules.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/SimplePad.o objs/StoryFlow.o objs/StyleManager.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/ThisDescriptor.o objs/Token.o objs/Translate.o objs/TranslateKeys.o objs/Trash.o objs/utils.o objs/WEvent.o objs/WResourceManager.o objs/WCachedResource.o objs/WDataSrc.o objs/WGui.o objs/WFilter.o objs/Tasks.o objs/WFont.o +OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardPrimitive.o objs/CardSelector.o objs/CardSelectorSingleton.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DeckDataWrapper.o objs/DeckMetaData.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateAwards.o objs/GameStateDeckViewer.o objs/GameStateDuel.o objs/DeckManager.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GameStateStory.o objs/GameStateTransitions.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/Logger.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGPack.o objs/MTGRules.o objs/Navigator.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/Pos.o objs/PrecompiledHeader.o objs/PriceList.o objs/ReplacementEffects.o objs/Rules.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/SimplePad.o objs/StoryFlow.o objs/StyleManager.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/ThisDescriptor.o objs/Token.o objs/Translate.o objs/TranslateKeys.o objs/Trash.o objs/utils.o objs/WEvent.o objs/WResourceManager.o objs/WCachedResource.o objs/WDataSrc.o objs/WGui.o objs/WFilter.o objs/Tasks.o objs/WFont.o DEPS = $(patsubst objs/%.o, deps/%.d, $(OBJS)) RESULT = $(shell psp-config --psp-prefix 2> Makefile.cache) @@ -89,7 +89,7 @@ clean: endif -PrecompiledHeader.h.gch: ../../projects/mtg/include/PrecompiledHeader.h +PrecompiledHeader.h.gch: ../../projects/mtg/include/PrecompiledHeader.h $(CXX) -c $(CXXFLAGS) $< $(OBJS): objs/%.o: src/%.cpp PrecompiledHeader.h.gch diff --git a/projects/mtg/include/CardGui.h b/projects/mtg/include/CardGui.h index f030c810a..cc2ae653f 100644 --- a/projects/mtg/include/CardGui.h +++ b/projects/mtg/include/CardGui.h @@ -8,7 +8,6 @@ #include "Pos.h" #include "PlayGuiObject.h" #include "MTGCardInstance.h" -#include "CardSelector.h" class MTGCardInstance; class PlayGuiObject; @@ -37,13 +36,19 @@ struct CardGui : public PlayGuiObject { virtual ostream& toString(ostream&) const; }; + class CardView : public CardGui { public: - const CardSelector::SelectorZone owner; + + typedef enum { + nullZone, handZone, playZone + } SelectorZone; + + const SelectorZone owner; MTGCardInstance* getCard(); // remove this when possible - CardView(const CardSelector::SelectorZone, MTGCardInstance* card, float x, float y); - CardView(const CardSelector::SelectorZone, MTGCardInstance* card, const Pos& ref); + CardView(const SelectorZone, MTGCardInstance* card, float x, float y); + CardView(const SelectorZone, MTGCardInstance* card, const Pos& ref); void Render(){CardGui::Render();}; void Render(JQuad* q){Pos::Render(q);}; virtual ostream& toString(ostream&) const; diff --git a/projects/mtg/include/CardSelector.h b/projects/mtg/include/CardSelector.h index 2351a8d73..4d95d5a04 100644 --- a/projects/mtg/include/CardSelector.h +++ b/projects/mtg/include/CardSelector.h @@ -3,6 +3,7 @@ #include #include +#include "CardGui.h" #include "GuiLayers.h" #include "Pos.h" @@ -11,6 +12,7 @@ using std::vector; class PlayGuiObject; class DuelLayers; + enum { BIG_MODE_SHOW = 0, BIG_MODE_TEXT = 1, @@ -26,38 +28,57 @@ struct LimitorFunctor typedef T Target; }; -template -class ObjectSelector : public GuiLayer +class CardSelectorBase : public GuiLayer +{ +public: + + CardSelectorBase(int inDrawMode) : mDrawMode(inDrawMode) {}; + virtual void Add(PlayGuiObject*) = 0; + virtual void Remove(PlayGuiObject*) = 0; + virtual bool CheckUserInput(JButton key) = 0; + virtual bool CheckUserInput(int x, int y) = 0; + virtual void PushLimitor() = 0; + virtual void PopLimitor() = 0; + virtual void Limit(LimitorFunctor* inLimitor, CardView::SelectorZone inZone) = 0; + virtual void Push() = 0; + virtual void Pop() = 0; + virtual int GetDrawMode() + { + return mDrawMode; + } + +protected: + int mDrawMode; +}; + + +class CardSelector : public CardSelectorBase { public: - typedef enum { - nullZone, handZone, playZone - } SelectorZone; struct SelectorMemory { - T* object; + PlayGuiObject* object; float x, y; - SelectorMemory(T* object) : object(object) { if (object) { x = object->x; y = object->y; } }; - SelectorMemory() { object = NULL; x = y = 0; }; + SelectorMemory(PlayGuiObject* object); + SelectorMemory(); }; protected: - vector cards; - T* active; + vector cards; + PlayGuiObject* active; DuelLayers* duel; - LimitorFunctor* limitor; + LimitorFunctor* limitor; Pos bigpos; - map lasts; - stack< pair*, SelectorZone> > limitorStack; + map lasts; + stack< pair*, CardView::SelectorZone> > limitorStack; stack memoryStack; - T* fetchMemory(SelectorMemory&); + PlayGuiObject* fetchMemory(SelectorMemory&); public: - ObjectSelector(DuelLayers*); - int bigMode; - void Add(T*); - void Remove(T*); + CardSelector(DuelLayers*); + void Add(PlayGuiObject*); + void Remove(PlayGuiObject*); bool CheckUserInput(JButton key); bool CheckUserInput(int x, int y); void Update(float dt); @@ -65,39 +86,15 @@ public: void Push(); void Pop(); - void Limit(LimitorFunctor* limitor, SelectorZone); + void Limit(LimitorFunctor* limitor, CardView::SelectorZone); void PushLimitor(); void PopLimitor(); - typedef T Target; + typedef PlayGuiObject Target; }; -typedef ObjectSelector<> CardSelector; typedef LimitorFunctor Limitor; - -namespace CardSelectorSingleton -{ - /* - ** CardSelector is essentially a singleton in its usage - ** It's not enforced, but it needs to eventually migrate to the real thing - ** For now, this function will fake it out - it's up to the client caller to make sure - ** that this gets destroyed via a Terminate call (this is currently handled in DualLayers's destructor) - */ - CardSelector* Instance(); - - /* - ** Create the singleton pointer. Instance() isn't valid until this is called. - */ - CardSelector* Create(DuelLayers* inDuelLayers); - - /* - ** Teardown the singleton pointer instance. - */ - void Terminate(); -} - - struct Exp { static inline bool test(CardSelector::Target*, CardSelector::Target*); diff --git a/projects/mtg/include/CardSelectorSingleton.h b/projects/mtg/include/CardSelectorSingleton.h new file mode 100644 index 000000000..22c76e0d1 --- /dev/null +++ b/projects/mtg/include/CardSelectorSingleton.h @@ -0,0 +1,30 @@ +#ifndef CARDSELECTORSINGLETON_H +#define CARDSELECTORSINGLETON_H + +#include "CardSelector.h" + +class DuelLayers; + +namespace CardSelectorSingleton +{ + /* + ** CardSelector is essentially a singleton in its usage + ** It's not enforced, but it needs to eventually migrate to the real thing + ** For now, this function will fake it out - it's up to the client caller to make sure + ** that this gets destroyed via a Terminate call (this is currently handled in DualLayers's destructor) + */ + CardSelectorBase* Instance(); + + /* + ** Create the singleton pointer. Instance() isn't valid until this is called. + */ + CardSelectorBase* Create(DuelLayers* inDuelLayers); + + /* + ** Teardown the singleton pointer instance. + */ + void Terminate(); +} + + +#endif //CARDSELECTORSINGLETON_H \ No newline at end of file diff --git a/projects/mtg/include/DuelLayers.h b/projects/mtg/include/DuelLayers.h index 24f349014..5a053d7c9 100644 --- a/projects/mtg/include/DuelLayers.h +++ b/projects/mtg/include/DuelLayers.h @@ -2,7 +2,6 @@ #define _DUELLAYERS_H_ #include "GuiLayers.h" -#include "CardSelector.h" class MTGGuiHand; class MTGGuiPlay; @@ -13,6 +12,7 @@ class GuiHandSelf; class GuiHandOpponent; class GuiCombat; class GuiAvatars; +class CardSelectorBase; struct Pos; class DuelLayers { @@ -43,7 +43,7 @@ public: int receiveEvent(WEvent * e); float RightBoundary(); - CardSelector* mCardSelector; + CardSelectorBase* mCardSelector; }; #include "ActionLayer.h" diff --git a/projects/mtg/include/GuiAvatars.h b/projects/mtg/include/GuiAvatars.h index 770ce173c..2cd73e782 100644 --- a/projects/mtg/include/GuiAvatars.h +++ b/projects/mtg/include/GuiAvatars.h @@ -2,7 +2,6 @@ #define _GUIAVATARS_H_ #include "GuiLayers.h" -#include "CardSelector.h" struct GuiAvatar; class GuiGraveyard; diff --git a/projects/mtg/include/GuiHand.h b/projects/mtg/include/GuiHand.h index 106401830..5f2f4aa55 100644 --- a/projects/mtg/include/GuiHand.h +++ b/projects/mtg/include/GuiHand.h @@ -6,7 +6,6 @@ #include "MTGGameZones.h" #include "CardGui.h" #include "GuiHand.h" -#include "CardSelector.h" class GuiHand; diff --git a/projects/mtg/include/Navigator.h b/projects/mtg/include/Navigator.h new file mode 100644 index 000000000..54e6da981 --- /dev/null +++ b/projects/mtg/include/Navigator.h @@ -0,0 +1,60 @@ +#ifndef NAVIGATOR_H +#define NAVIGATOR_H + +#include "JTypes.h" + +#include "CardSelector.h" +#include "DuelLayers.h" + +#include +#include + + +// private class only used by Navigator, see implementation file +class CardZone; + +class Navigator : public CardSelectorBase +{ +public: + + Navigator(DuelLayers* inDuelLayers); + virtual ~Navigator(); + + // Inherited functions from GuiLayer + bool CheckUserInput(JButton inKey); + bool CheckUserInput(int x, int y); + void Update(float dt); + void Render(); + + //Limitor operations + void PushLimitor(); + void PopLimitor(); + void Limit(LimitorFunctor* inLimitor, CardView::SelectorZone inZone); + + virtual void Add(PlayGuiObject*); + virtual void Remove(PlayGuiObject*); + virtual void Push() {} + virtual void Pop() {} + +protected: + PlayGuiObject* GetCurrentCard(); + + /** + ** Helper function that translates a card type into an internal zone ID (used as the index for the card zone map) + */ + int CardToCardZone(PlayGuiObject* card); + + void HandleKeyStroke(JButton inKey); + +private: + std::map mCardZones; + CardZone* mCurrentZone; + Pos mDrawPosition; + + DuelLayers* mDuelLayers; + + bool mLimitorEnabled; + std::stack mCurrentZoneStack; +}; + +#endif //NAVIGATOR_H diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 62a591cf0..a2783d6aa 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -4,15 +4,16 @@ #include "PrecompiledHeader.h" #include "ActionStack.h" -#include "MTGAbility.h" -#include "GameObserver.h" -#include "Damage.h" -#include "ManaCost.h" -#include "GameOptions.h" -#include "WResourceManager.h" -#include "TargetChooser.h" #include "CardGui.h" +#include "CardSelectorSingleton.h" +#include "Damage.h" +#include "GameObserver.h" +#include "GameOptions.h" +#include "ManaCost.h" +#include "MTGAbility.h" +#include "TargetChooser.h" #include "Translate.h" +#include "WResourceManager.h" #include @@ -83,7 +84,7 @@ void Interruptible::Render(MTGCardInstance * source, JQuad * targetQuad, string } if (bigQuad){ - int showMode = CardSelectorSingleton::Instance()->bigMode; + int showMode = CardSelectorSingleton::Instance()->GetDrawMode(); Pos pos = Pos(CardGui::BigWidth / 2, CardGui::BigHeight / 2 - 10, 1.0, 0.0, 220); switch(showMode){ case BIG_MODE_SHOW: @@ -601,7 +602,7 @@ void ActionStack::Update(float dt){ for (int i = 0; i < mCount ; i++){ Interruptible * current = (Interruptible *)mObjects[i]; if (tc->canTarget(current)){ - if (mObjects[mCurr]) mObjects[mCurr]->Leaving(JGE_BTN_UP); + if (mCurr < (int)mObjects.size() && mObjects[mCurr]) mObjects[mCurr]->Leaving(JGE_BTN_UP); current->display = 1; mCurr = i; mObjects[mCurr]->Entering(); diff --git a/projects/mtg/src/CardDisplay.cpp b/projects/mtg/src/CardDisplay.cpp index 49a3a86af..75bc61423 100644 --- a/projects/mtg/src/CardDisplay.cpp +++ b/projects/mtg/src/CardDisplay.cpp @@ -2,6 +2,7 @@ #include "CardDisplay.h" #include "CardGui.h" +#include "CardSelectorSingleton.h" #include "TargetChooser.h" #include "MTGGameZones.h" #include "GameObserver.h" @@ -27,7 +28,7 @@ CardDisplay::CardDisplay(int id, GameObserver* game, int _x, int _y, JGuiListene } void CardDisplay::AddCard(MTGCardInstance * _card){ - CardGui * card = NEW CardView(CardSelector::nullZone, _card, static_cast(x + 20 + (mCount - start_item) * 30), static_cast(y + 25)); + CardGui * card = NEW CardView(CardView::nullZone, _card, static_cast(x + 20 + (mCount - start_item) * 30), static_cast(y + 25)); Add(card); } @@ -218,7 +219,7 @@ void CardDisplay::Render(){ Pos pos = Pos(CardGui::BigWidth / 2, CardGui::BigHeight / 2 - 10, 1.0, 0.0, 220); int showMode = BIG_MODE_SHOW; if (game){ - showMode = CardSelectorSingleton::Instance()->bigMode; + showMode = CardSelectorSingleton::Instance()->GetDrawMode(); pos.actY = 150; if (x < (CardGui::BigWidth / 2)) pos.actX = SCREEN_WIDTH - 10 - CardGui::BigWidth / 2; } diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index 0737ea486..6cdd57938 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -38,7 +38,7 @@ namespace CardGui::CardGui(MTGCardInstance* card, float x, float y) : PlayGuiObject(Height, x, y, false), card(card) {} CardGui::CardGui(MTGCardInstance* card, const Pos& ref) : PlayGuiObject(Height, ref, false), card(card) {} -CardView::CardView(const CardSelector::SelectorZone owner, MTGCardInstance* card, float x, float y) : CardGui(card, x, y), owner(owner) { +CardView::CardView(const SelectorZone owner, MTGCardInstance* card, float x, float y) : CardGui(card, x, y), owner(owner) { const Pos* ref = card->view; while (card) { @@ -47,7 +47,7 @@ CardView::CardView(const CardSelector::SelectorZone owner, MTGCardInstance* card } } -CardView::CardView(const CardSelector::SelectorZone owner, MTGCardInstance* card, const Pos& ref) : CardGui(card, ref), owner(owner) { +CardView::CardView(const SelectorZone owner, MTGCardInstance* card, const Pos& ref) : CardGui(card, ref), owner(owner) { const Pos* r = card->view; while (card) { diff --git a/projects/mtg/src/CardSelector.cpp b/projects/mtg/src/CardSelector.cpp index 014cd25d5..47a0d3c5f 100644 --- a/projects/mtg/src/CardSelector.cpp +++ b/projects/mtg/src/CardSelector.cpp @@ -29,10 +29,13 @@ struct Diff : public Exp { static inline bool test(CardSelector::Target* ref, Ca struct True : public Exp { static inline bool test(CardSelector::Target* ref, CardSelector::Target* test) { return true; } }; -template<> -CardSelector::ObjectSelector(DuelLayers* duel) : active(NULL), duel(duel), limitor(NULL), bigpos(300, 150, 1.0, 0.0, 220), bigMode(BIG_MODE_SHOW) {} -template<> +CardSelector::SelectorMemory::SelectorMemory(PlayGuiObject* object) : object(object) { if (object) { x = object->x; y = object->y; } } +CardSelector::SelectorMemory::SelectorMemory() { object = NULL; x = y = 0; } + + +CardSelector::CardSelector(DuelLayers* duel) : CardSelectorBase(BIG_MODE_SHOW), active(NULL), duel(duel), limitor(NULL), bigpos(300, 150, 1.0, 0.0, 220) {} + void CardSelector::Add(CardSelector::Target* target) { if (NULL == active) @@ -44,25 +47,24 @@ void CardSelector::Add(CardSelector::Target* target) if (c) c->zoom = 1.4f; cards.push_back(target); } -template<> + void CardSelector::Remove(CardSelector::Target* card) { for (vector::iterator it = cards.begin(); it != cards.end(); ++it) if (card == *it) + { + if (active == *it) { - if (active == *it) - { - CardView* c = dynamic_cast(active); if (c) c->zoom = 1.0f; - active = closest(cards, limitor, active); - c = dynamic_cast(active); if (c) c->zoom = 1.4f; - } - if (active == *it) active = NULL; - cards.erase(it); - return; + CardView* c = dynamic_cast(active); if (c) c->zoom = 1.0f; + active = closest(cards, limitor, active); + c = dynamic_cast(active); if (c) c->zoom = 1.4f; } + if (active == *it) active = NULL; + cards.erase(it); + return; + } } -template<> CardSelector::Target* CardSelector::fetchMemory(SelectorMemory& memory) { if (NULL == memory.object) return NULL; for (vector::iterator it = cards.begin(); it != cards.end(); ++it) @@ -75,19 +77,19 @@ CardSelector::Target* CardSelector::fetchMemory(SelectorMemory& memory) { // it is there but it is now refused by the limitor. return closest(cards, limitor, memory.x, memory.y); } -template<> + void CardSelector::Push() { memoryStack.push(SelectorMemory(active)); } -template<> + void CardSelector::Pop() { Target* oldactive = active; if (!memoryStack.empty()) { active = fetchMemory(memoryStack.top()); memoryStack.pop(); - SelectorZone oldowner; - if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = nullZone; - if (nullZone != oldowner) lasts[oldowner] = SelectorMemory(oldactive); + CardView::SelectorZone oldowner; + if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = CardView::nullZone; + if (CardView::nullZone != oldowner) lasts[oldowner] = SelectorMemory(oldactive); } if (active != oldactive) { { CardView* c = dynamic_cast(oldactive); if (c) c->zoom = 1.0f; } //Is this needed, I think it is one in Leaving(0) ? @@ -97,7 +99,6 @@ void CardSelector::Pop() { } } -template<> bool CardSelector::CheckUserInput(JButton key) { if (!active) { @@ -131,8 +132,8 @@ bool CardSelector::CheckUserInput(JButton key) active = closest(cards, limitor, active); break; case JGE_BTN_CANCEL: - bigMode = (bigMode+1) % NB_BIG_MODES; - if(bigMode == BIG_MODE_TEXT) + mDrawMode = (mDrawMode+1) % NB_BIG_MODES; + if(mDrawMode == BIG_MODE_TEXT) options[Options::DISABLECARDS].number = 1; else options[Options::DISABLECARDS].number = 0; @@ -141,11 +142,11 @@ bool CardSelector::CheckUserInput(JButton key) return false; } if (active != oldactive) { - SelectorZone oldowner, owner; - if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = nullZone; - if (CardView *q = dynamic_cast(active)) owner = q->owner; else owner = nullZone; + CardView::SelectorZone oldowner, owner; + if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = CardView::nullZone; + if (CardView *q = dynamic_cast(active)) owner = q->owner; else owner = CardView::nullZone; if (oldowner != owner) { - if (nullZone != owner) { + if (CardView::nullZone != owner) { if (PlayGuiObject* old = fetchMemory(lasts[owner])) switch (key) { @@ -185,8 +186,6 @@ bool CardSelector::CheckUserInput(JButton key) return true; } - -template<> bool CardSelector::CheckUserInput(int x, int y) { if (!active) { @@ -202,11 +201,11 @@ bool CardSelector::CheckUserInput(int x, int y) active = closest(cards, limitor, x, y); if (active != oldactive) { - SelectorZone oldowner, owner; - if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = nullZone; - if (CardView *q = dynamic_cast(active)) owner = q->owner; else owner = nullZone; + CardView::SelectorZone oldowner, owner; + if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = CardView::nullZone; + if (CardView *q = dynamic_cast(active)) owner = q->owner; else owner = CardView::nullZone; if (oldowner != owner) { - if (nullZone != owner) { + if (CardView::nullZone != owner) { if (PlayGuiObject* old = fetchMemory(lasts[owner])) if (old) active = old; } @@ -222,25 +221,23 @@ bool CardSelector::CheckUserInput(int x, int y) return true; } -template<> void CardSelector::Update(float dt) { float boundary = duel->RightBoundary(); float position = boundary - CardGui::BigWidth / 2; if (CardView* c = dynamic_cast(active)) if ((c->x + CardGui::Width / 2 > position - CardGui::BigWidth / 2) && - (c->x - CardGui::Width / 2 < position + CardGui::BigWidth / 2)) + (c->x - CardGui::Width / 2 < position + CardGui::BigWidth / 2)) position = CardGui::BigWidth / 2 - 10; if (position < CardGui::BigWidth / 2) position = CardGui::BigWidth / 2; bigpos.x = position; bigpos.Update(dt); } -template<> void CardSelector::Render() { if (active) { active->Render(); if (CardView* c = dynamic_cast(active)) { - switch(bigMode) { + switch(mDrawMode) { case BIG_MODE_SHOW: c->RenderBig(bigpos); break; @@ -254,15 +251,14 @@ void CardSelector::Render() { } } -template<> -void CardSelector::Limit(LimitorFunctor* limitor, SelectorZone destzone) { +void CardSelector::Limit(LimitorFunctor* limitor, CardView::SelectorZone destzone) { this->limitor = limitor; if (limitor && !limitor->select(active)) { - Target* oldactive = active; - SelectorZone oldowner; - if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = nullZone; + PlayGuiObject* oldactive = active; + CardView::SelectorZone oldowner; + if (CardView *q = dynamic_cast(oldactive)) oldowner = q->owner; else oldowner = CardView::nullZone; if (oldowner != destzone) { - if (nullZone != destzone) + if (CardView::nullZone != destzone) if (PlayGuiObject* old = fetchMemory(lasts[destzone])) active = old; lasts[oldowner] = SelectorMemory(oldactive); @@ -270,7 +266,7 @@ void CardSelector::Limit(LimitorFunctor* limitor, SelectorZone destzone) if (limitor && !limitor->select(active)) { active = NULL; - for (vector::iterator it = cards.begin(); it != cards.end(); ++it) + for (vector::iterator it = cards.begin(); it != cards.end(); ++it) if (limitor->select(*it)) { active = *it; break; @@ -286,43 +282,15 @@ void CardSelector::Limit(LimitorFunctor* limitor, SelectorZone destzone) } } -template<> void CardSelector::PushLimitor() { if (NULL == limitor) return; - SelectorZone owner; - if (CardView *q = dynamic_cast(active)) owner = q->owner; else owner = nullZone; + CardView::SelectorZone owner; + if (CardView *q = dynamic_cast(active)) owner = q->owner; else owner = CardView::nullZone; limitorStack.push(make_pair(limitor, owner)); } -template<> void CardSelector::PopLimitor() { if (limitorStack.empty()) return; Limit(limitorStack.top().first, limitorStack.top().second); limitorStack.pop(); } - - -namespace CardSelectorSingleton -{ - static CardSelector* sCardSelectorInstance = NULL; - - CardSelector* Create(DuelLayers* inDuelLayers) - { - if (sCardSelectorInstance == NULL) - sCardSelectorInstance = NEW CardSelector(inDuelLayers); - - return sCardSelectorInstance; - } - - CardSelector* Instance() - { - assert(sCardSelectorInstance); - return sCardSelectorInstance; - } - - void Terminate() - { - SAFE_DELETE(sCardSelectorInstance); - sCardSelectorInstance = NULL; - } -} diff --git a/projects/mtg/src/CardSelectorSingleton.cpp b/projects/mtg/src/CardSelectorSingleton.cpp new file mode 100644 index 000000000..2e31abcec --- /dev/null +++ b/projects/mtg/src/CardSelectorSingleton.cpp @@ -0,0 +1,36 @@ +#include "PrecompiledHeader.h" + +#include "CardSelectorSingleton.h" + +#include "DuelLayers.h" +#include "Navigator.h" + +/* +** +*/ +namespace CardSelectorSingleton +{ + static CardSelectorBase* sCardSelectorInstance = NULL; + + CardSelectorBase* Create(DuelLayers* inDuelLayers) + { + if (sCardSelectorInstance == NULL) + sCardSelectorInstance = NEW CardSelector(inDuelLayers); + //sCardSelectorInstance = NEW Navigator(inDuelLayers); + + return sCardSelectorInstance; + } + + CardSelectorBase* Instance() + { + assert(sCardSelectorInstance); + return sCardSelectorInstance; + } + + void Terminate() + { + SAFE_DELETE(sCardSelectorInstance); + sCardSelectorInstance = NULL; + } +} + diff --git a/projects/mtg/src/DuelLayers.cpp b/projects/mtg/src/DuelLayers.cpp index 9445c5eae..81929eedc 100644 --- a/projects/mtg/src/DuelLayers.cpp +++ b/projects/mtg/src/DuelLayers.cpp @@ -1,6 +1,7 @@ #include "PrecompiledHeader.h" #include "MTGRules.h" +#include "CardSelectorSingleton.h" #include "GuiCombat.h" #include "GuiBackground.h" #include "GuiFrame.h" diff --git a/projects/mtg/src/GuiAvatars.cpp b/projects/mtg/src/GuiAvatars.cpp index 2daeb5c46..bc6c02b5b 100644 --- a/projects/mtg/src/GuiAvatars.cpp +++ b/projects/mtg/src/GuiAvatars.cpp @@ -1,5 +1,6 @@ #include "PrecompiledHeader.h" +#include "CardSelectorSingleton.h" #include "GameApp.h" #include "GuiAvatars.h" #include "GameObserver.h" diff --git a/projects/mtg/src/GuiCombat.cpp b/projects/mtg/src/GuiCombat.cpp index eee5c2529..7f0ce332b 100644 --- a/projects/mtg/src/GuiCombat.cpp +++ b/projects/mtg/src/GuiCombat.cpp @@ -5,6 +5,7 @@ #include "AIPlayer.h" #include "GameObserver.h" #include "Trash.h" +#include "CardSelector.h" #include "Closest.cpp" static const float MARGIN = 70; diff --git a/projects/mtg/src/GuiHand.cpp b/projects/mtg/src/GuiHand.cpp index e3110e28f..7434f2499 100644 --- a/projects/mtg/src/GuiHand.cpp +++ b/projects/mtg/src/GuiHand.cpp @@ -1,5 +1,7 @@ #include "PrecompiledHeader.h" +#include "CardSelectorSingleton.h" +#include "CardSelector.h" #include "GameApp.h" #include "Trash.h" #include "GuiHand.h" @@ -136,7 +138,7 @@ bool GuiHandSelf::CheckUserInput(JButton key) { state = (Open == state ? Closed : Open); if (Open == state) CardSelectorSingleton::Instance()->Push(); - CardSelectorSingleton::Instance()->Limit(Open == state ? limitor : NULL, CardSelector::handZone); + CardSelectorSingleton::Instance()->Limit(Open == state ? limitor : NULL, CardView::handZone); if (Closed == state) CardSelectorSingleton::Instance()->Pop(); if (OptionHandDirection::HORIZONTAL == options[Options::HANDDIRECTION].number) backpos.y = Open == state ? OpenY : ClosedY; @@ -212,10 +214,10 @@ int GuiHandSelf::receiveEventPlus(WEvent* e) // We don't want a card in the hand to have an alpha of 0 ev->card->view->alpha = 255; - card = NEW CardView(CardSelector::handZone, ev->card, *(ev->card->view)); + card = NEW CardView(CardView::handZone, ev->card, *(ev->card->view)); } else - card = NEW CardView(CardSelector::handZone, ev->card, ClosedRowX, 0); + card = NEW CardView(CardView::handZone, ev->card, ClosedRowX, 0); card->t = 6*M_PI; cards.push_back(card); CardSelectorSingleton::Instance()->Add(card); @@ -251,9 +253,9 @@ int GuiHandOpponent::receiveEventPlus(WEvent* e) { CardView* card; if (event->card->view) - card = NEW CardView(CardSelector::handZone, event->card, *(event->card->view)); + card = NEW CardView(CardView::handZone, event->card, *(event->card->view)); else - card = NEW CardView(CardSelector::handZone, event->card, ClosedRowX, 0); + card = NEW CardView(CardView::handZone, event->card, ClosedRowX, 0); card->alpha = 255; card->t = -4*M_PI; cards.push_back(card); return 1; diff --git a/projects/mtg/src/GuiPlay.cpp b/projects/mtg/src/GuiPlay.cpp index 9c6d57237..0ac3e4129 100644 --- a/projects/mtg/src/GuiPlay.cpp +++ b/projects/mtg/src/GuiPlay.cpp @@ -1,5 +1,6 @@ #include "PrecompiledHeader.h" +#include "CardSelectorSingleton.h" #include "GameApp.h" #include "GuiPlay.h" #include "Trash.h" @@ -232,15 +233,18 @@ int GuiPlay::receiveEventPlus(WEvent * e) // We don't want a card in the hand to have an alpha of 0 event->card->view->alpha = 255; - card = NEW CardView(CardSelector::playZone, event->card, *(event->card->view)); + card = NEW CardView(CardView::playZone, event->card, *(event->card->view)); } else - card = NEW CardView(CardSelector::playZone, event->card, 0, 0); + card = NEW CardView(CardView::playZone, event->card, 0, 0); cards.push_back(card); card->t = event->card->isTapped() ? M_PI / 2 : 0; card->alpha = 255; - CardSelectorSingleton::Instance()->Add(card); + + // Make sure that the card is repositioned before adding it to the CardSelector, as + // the card's position is a cue for certain CardSelector variants as to what zone the card is placed in Replace(); + CardSelectorSingleton::Instance()->Add(card); return 1; } } diff --git a/projects/mtg/src/GuiStatic.cpp b/projects/mtg/src/GuiStatic.cpp index c95e4acb5..c61fd8957 100644 --- a/projects/mtg/src/GuiStatic.cpp +++ b/projects/mtg/src/GuiStatic.cpp @@ -233,9 +233,9 @@ int GuiGraveyard::receiveEventPlus(WEvent* e) { CardView* t; if (event->card->view) - t = NEW CardView(CardSelector::nullZone, event->card, *(event->card->view)); + t = NEW CardView(CardView::nullZone, event->card, *(event->card->view)); else - t = NEW CardView(CardSelector::nullZone, event->card, x, y); + t = NEW CardView(CardView::nullZone, event->card, x, y); t->x = x + Width / 2; t->y = y + Height / 2; t->zoom = 0.6; t->alpha = 0; cards.push_back(t); return 1; @@ -276,9 +276,9 @@ int GuiOpponentHand::receiveEventPlus(WEvent* e) { CardView* t; if (event->card->view) - t = NEW CardView(CardSelector::nullZone, event->card, *(event->card->view)); + t = NEW CardView(CardView::nullZone, event->card, *(event->card->view)); else - t = NEW CardView(CardSelector::nullZone, event->card, x, y); + t = NEW CardView(CardView::nullZone, event->card, x, y); t->x = x + Width / 2; t->y = y + Height / 2; t->zoom = 0.6; t->alpha = 0; cards.push_back(t); return 1; diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index e3731d89f..3f7424b11 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -1,5 +1,6 @@ #include "PrecompiledHeader.h" +#include "CardSelectorSingleton.h" #include "MTGRules.h" #include "Translate.h" #include "Subtypes.h" @@ -726,9 +727,9 @@ int MTGAttackRule::reactToClick(MTGCardInstance * card){ //Graphically select the next card that can attack if(!card->isAttacker()){ CardSelectorSingleton::Instance()->PushLimitor(); - CardSelectorSingleton::Instance()->Limit(this,CardSelector::playZone); + CardSelectorSingleton::Instance()->Limit(this, CardView::playZone); CardSelectorSingleton::Instance()->CheckUserInput(JGE_BTN_RIGHT); - CardSelectorSingleton::Instance()->Limit(NULL,CardSelector::playZone); + CardSelectorSingleton::Instance()->Limit(NULL, CardView::playZone); CardSelectorSingleton::Instance()->PopLimitor(); } card->toggleAttacker(); diff --git a/projects/mtg/src/Navigator.cpp b/projects/mtg/src/Navigator.cpp new file mode 100644 index 000000000..ff1656221 --- /dev/null +++ b/projects/mtg/src/Navigator.cpp @@ -0,0 +1,773 @@ +#include "PrecompiledHeader.h" + +#include "CardGui.h" +#include "Navigator.h" + +namespace +{ + const Pos kDefaultCardPosition(300, 150, 1.0, 0.0, 220); + + 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 mCards; + size_t mCurrentCard; + + // you'll typically have up to 4 neighbours, ie left/right/up/down + std::map 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); + if (distance < minDistance) + { + 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(mNeighbours[JGE_BTN_DOWN]); + if (landZone == NULL) + { + landZone = dynamic_cast(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(mNeighbours[JGE_BTN_DOWN]); + if (creatureZone == NULL) + { + creatureZone = dynamic_cast(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) + : CardSelectorBase(BIG_MODE_SHOW), mDrawPosition(kDefaultCardPosition), mDuelLayers(inDuelLayers), mLimitorEnabled(false) +{ + assert(mDuelLayers); + + // initialize the cardZone layout + mCardZones.insert(std::pair(kCardZone_PlayerHand, NEW HandCardZone())); + mCardZones.insert(std::pair(kCardZone_PlayerAvatar, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_PlayerLibrary, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_PlayerGraveyard, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_PlayerLands, NEW LandCardZone())); + mCardZones.insert(std::pair(kCardZone_PlayerCreatures, NEW CreatureCardZone())); + mCardZones.insert(std::pair(kCardZone_PlayerEnchantmentsAndArtifacts, NEW GridCardZone())); + mCardZones.insert(std::pair(kCardZone_AIHand, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_AIAvatar, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_AILibrary, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_AIGraveyard, NEW CardZone())); + mCardZones.insert(std::pair(kCardZone_AILands, NEW LandCardZone())); + mCardZones.insert(std::pair(kCardZone_AICreatures, NEW CreatureCardZone())); + mCardZones.insert(std::pair(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::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) % NB_BIG_MODES; + if(mDrawMode == BIG_MODE_TEXT) + 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(GetCurrentCard()); + if (card) + { + switch(mDrawMode) + { + case BIG_MODE_SHOW: + card->RenderBig(mDrawPosition); + break; + case BIG_MODE_TEXT: + card->alternateRenderBig(mDrawPosition); + break; + default: + break; + } + } + } +} + +/* +** +*/ +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* 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(inCard); + if (avatar) + { + if (avatar->player->isAI()) + { + result = kCardZone_AIAvatar; + } + else + { + result = kCardZone_PlayerAvatar; + } + } + + GuiGraveyard* graveyard = dynamic_cast(inCard); + if (graveyard) + { + if (graveyard->player->isAI()) + { + result = kCardZone_AIGraveyard; + } + else + { + result = kCardZone_PlayerGraveyard; + } + } + + GuiLibrary* library = dynamic_cast(inCard); + if (library) + { + if (library->player->isAI()) + { + result = kCardZone_AILibrary; + } + else + { + result = kCardZone_PlayerLibrary; + } + } + + GuiOpponentHand* opponentHand = dynamic_cast(inCard); + if (opponentHand) + { + result = kCardZone_AIHand; + } + + CardView* card = dynamic_cast(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 < SCREEN_HEIGHT / 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); + } +} diff --git a/projects/mtg/template.vcxproj b/projects/mtg/template.vcxproj index 60f6f80d5..de27ee7d9 100644 --- a/projects/mtg/template.vcxproj +++ b/projects/mtg/template.vcxproj @@ -120,6 +120,7 @@ true Use PrecompiledHeader.h + true NDEBUG;%(PreprocessorDefinitions) @@ -169,6 +170,7 @@ false Use PrecompiledHeader.h + false _DEBUG;%(PreprocessorDefinitions) @@ -220,6 +222,7 @@ ProgramDatabase Use PrecompiledHeader.h + true NDEBUG;%(PreprocessorDefinitions) @@ -270,6 +273,7 @@ EditAndContinue Use PrecompiledHeader.h + true _DEBUG;%(PreprocessorDefinitions) @@ -306,6 +310,7 @@ + @@ -371,6 +376,7 @@ + @@ -431,6 +437,7 @@ + @@ -480,6 +487,7 @@ +