diff --git a/projects/mtg/Android/jni/Android.mk b/projects/mtg/Android/jni/Android.mk index 4a5c8871c..996b008bd 100644 --- a/projects/mtg/Android/jni/Android.mk +++ b/projects/mtg/Android/jni/Android.mk @@ -82,6 +82,7 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.cpp \ $(MTG_PATH)/src/ManaCost.cpp \ $(MTG_PATH)/src/ManaCostHybrid.cpp \ $(MTG_PATH)/src/MenuItem.cpp \ + $(MTG_PATH)/src/ModRules.cpp \ $(MTG_PATH)/src/MTGAbility.cpp \ $(MTG_PATH)/src/MTGCard.cpp \ $(MTG_PATH)/src/MTGCardInstance.cpp \ diff --git a/projects/mtg/Makefile b/projects/mtg/Makefile index 9e950c02d..d027502c6 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/AllAbilities.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/DeckEditorMenu.o objs/DeckMenu.o objs/DeckMenuItem.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/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/ObjectAnalytics.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/PlayRestrictions.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/SimplePopup.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/AllAbilities.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/DeckEditorMenu.o objs/DeckMenu.o objs/DeckMenuItem.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/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/ModRules.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/ObjectAnalytics.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/PlayRestrictions.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/SimplePopup.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) diff --git a/projects/mtg/bin/Res/rules/modrules.xml b/projects/mtg/bin/Res/rules/modrules.xml new file mode 100644 index 000000000..f214c6cb5 --- /dev/null +++ b/projects/mtg/bin/Res/rules/modrules.xml @@ -0,0 +1,16 @@ + + + + +
+ + + + + +
+ + + + +
\ No newline at end of file diff --git a/projects/mtg/include/CardGui.h b/projects/mtg/include/CardGui.h index 4372e8c21..5bfbfc1c1 100644 --- a/projects/mtg/include/CardGui.h +++ b/projects/mtg/include/CardGui.h @@ -43,6 +43,8 @@ public: static const float BigWidth; static const float BigHeight; + PIXEL_TYPE mMask; + MTGCardInstance* card; CardGui(MTGCardInstance* card, float x, float y); CardGui(MTGCardInstance* card, const Pos& ref); @@ -95,4 +97,33 @@ public: TransientCardView(MTGCardInstance* card, const Pos& ref); }; + +class SimpleCardEffect +{ +public: + virtual void doEffect(Pos * card) = 0; + virtual void undoEffect(Pos * card) = 0; +}; + +class SimpleCardEffectRotate:public SimpleCardEffect +{ +protected: + float mRotation; +public: + SimpleCardEffectRotate(float rotation); + void doEffect(Pos * card); + void undoEffect(Pos * card); +}; + +class SimpleCardEffectMask:public SimpleCardEffect +{ +protected: + PIXEL_TYPE mMask; +public: + SimpleCardEffectMask(PIXEL_TYPE mask); + void doEffect(Pos * card); + void undoEffect(Pos * card); +}; + + #endif diff --git a/projects/mtg/include/GameStateMenu.h b/projects/mtg/include/GameStateMenu.h index ec46d8aec..1c6a09132 100644 --- a/projects/mtg/include/GameStateMenu.h +++ b/projects/mtg/include/GameStateMenu.h @@ -22,7 +22,6 @@ private: JTexture * splashTex; float mCreditsYPos; int currentState; - //JMusic * bgMusic; int mVolume; char nbcardsStr[400]; vector langs; @@ -48,7 +47,10 @@ private: void genNbCardsStr(); //computes the contents of nbCardsStr void ensureMGuiController(); //creates the MGuiController if it doesn't exist string loadRandomWallpaper(); //loads a list of string of textures that can be randolmy shown on the loading screen + + void RenderTopMenu(); public: + GameStateMenu(GameApp* parent); virtual ~GameStateMenu(); virtual void Create(); diff --git a/projects/mtg/include/ModRules.h b/projects/mtg/include/ModRules.h new file mode 100644 index 000000000..b543dc314 --- /dev/null +++ b/projects/mtg/include/ModRules.h @@ -0,0 +1,110 @@ +#ifndef _MODRULES_H_ +#define _MODRULES_H_ + +#include +#include +using namespace std; + +#include "CardGui.h" + +class TiXmlElement; + + +enum +{ + SUBMENUITEM_CANCEL = kCancelMenuID, + MENUITEM_PLAY, + MENUITEM_DECKEDITOR, + MENUITEM_SHOP, + MENUITEM_OPTIONS, + MENUITEM_EXIT, + MENUITEM_TROPHIES, + SUBMENUITEM_1PLAYER, +#ifdef NETWORK_SUPPORT + SUBMENUITEM_2PLAYERS, + SUBMENUITEM_HOST_GAME, + SUBMENUITEM_JOIN_GAME, +#endif //NETWORK_SUPPORT + SUBMENUITEM_DEMO, + SUBMENUITEM_TESTSUITE, + SUBMENUITEM_END_OFFSET +}; + +class ModRulesMenuItem +{ +protected: + static int strToAction(string str); +public: + int mActionId; + string mDisplayName; + ModRulesMenuItem(string actionIdStr, string displayName); + //most actionIds are associated to a game state. e.g. MENUITEM_DECKEDITOR <--> GAME_STATE_DECK_VIEWER + //This function returns the game state that matches the actionId, if any + int getMatchingGameState(); + static int getMatchingGameState(int actionId); +}; + +class ModRulesMainMenuItem: public ModRulesMenuItem +{ +public: + int mIconId; + string mParticleFile; + ModRulesMainMenuItem(string actionIdStr, string displayName, int iconId, string particleFile); +}; + +class ModRulesOtherMenuItem: public ModRulesMenuItem +{ +public: + JButton mKey; + ModRulesOtherMenuItem(string actionIdStr, string displayName, string keyStr); + static JButton strToJButton(string keyStr); +}; + +class ModRulesMenu +{ +public: + vector main; + vector other; + + void parse(TiXmlElement* element); + ~ModRulesMenu(); +}; + +class ModRulesGeneral +{ +protected: + bool mHasDeckEditor; + bool mHasShop; +public: + bool hasDeckEditor() {return mHasDeckEditor;}; + bool hasShop() {return mHasShop;}; + ModRulesGeneral(); + void parse(TiXmlElement* element); +}; + +class ModRulesCards +{ +public: + SimpleCardEffect * activateEffect; + static SimpleCardEffect * parseEffect(string str); + ModRulesCards(); + ~ModRulesCards(); + void parse(TiXmlElement* element); +}; + +class ModRules +{ +public: + ModRulesGeneral general; + ModRulesCards cards; + ModRulesMenu menu; + + bool load(string filename); + static int getValueAsInt(TiXmlElement* element, string childName); + +}; + +extern ModRules gModRules; + + +#endif diff --git a/projects/mtg/include/Pos.h b/projects/mtg/include/Pos.h index d2d65646f..76bdaf1ff 100644 --- a/projects/mtg/include/Pos.h +++ b/projects/mtg/include/Pos.h @@ -7,6 +7,7 @@ struct Pos { float actX, actY, actZ, actT, actA; float x, y, zoom, t, alpha; + PIXEL_TYPE mask; Pos(float, float, float, float, float); virtual void Update(float dt); void UpdateNow(); diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index 72b0373a2..2484c6563 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -266,6 +266,10 @@ void CardGui::Render() renderer->RenderQuad(shadow.get(), actX, actY, actT, (28 * actZ + 1) / 16, 40 * actZ / 16); } + // Render a mask over the card, if set + if (mask && quad) + JRenderer::GetInstance()->FillRect(actX - (scale * quad->mWidth / 2),actY - (scale * quad->mHeight / 2), scale * quad->mWidth, scale* quad->mHeight, mask); + PlayGuiObject::Render(); } @@ -866,3 +870,32 @@ ostream& CardGui::toString(ostream& out) const { return (out << "CardGui ::: x,y " << x << "," << y); } + + +SimpleCardEffectRotate::SimpleCardEffectRotate(float rotation): mRotation(rotation) +{ +} + +void SimpleCardEffectRotate::doEffect(Pos * card) +{ + card->t = mRotation; +} + +void SimpleCardEffectRotate::undoEffect(Pos * card) +{ + card->t = 0; +} + +SimpleCardEffectMask::SimpleCardEffectMask(PIXEL_TYPE mask): mMask(mask) +{ +} + +void SimpleCardEffectMask::doEffect(Pos * card) +{ + card->mask = mMask; +} + +void SimpleCardEffectMask::undoEffect(Pos * card) +{ + card->mask = 0; +} \ No newline at end of file diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index 7366f0d36..1372ab537 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -27,6 +27,7 @@ #include "Translate.h" #include "WFilter.h" #include "Rules.h" +#include "ModRules.h" #define DEFAULT_DURATION .25 @@ -117,6 +118,9 @@ void GameApp::Create() LOG("Res Root:"); LOG(JFileSystem::GetInstance()->GetResourceRoot().c_str()); + //Load Mod Rules before everything else + gModRules.load("rules/modrules.xml"); + //Link this to our settings manager. options.theGame = this; diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index 23e225294..f90e702f9 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -14,6 +14,7 @@ #include "Credits.h" #include "Translate.h" #include "Rules.h" +#include "ModRules.h" #ifdef TESTSUITE #include "TestSuiteAI.h" @@ -124,7 +125,7 @@ void GameStateDuel::Start() vector playerDeckList = BuildDeckList(options.profileFile()); int nbDecks = playerDeckList.size(); - if (nbDecks) + if (nbDecks > 1) { decksneeded = 0; deckmenu->Add(MENUITEM_RANDOM_PLAYER, "Random", "Play with a random deck."); @@ -143,17 +144,21 @@ void GameStateDuel::Start() { if (decksneeded) { - //translate deck creating desc - Translator * t = Translator::GetInstance(); - map::iterator it = t->deckValues.find("Create your Deck!"); - if (it != t->deckValues.end()) - deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", it->second); - else - deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", "Highly recommended to get\nthe full Wagic experience!"); + if (gModRules.general.hasDeckEditor()) + { + //translate deck creating desc + Translator * t = Translator::GetInstance(); + string desc = "Highly recommended to get\nthe full Wagic experience!"; + map::iterator it = t->deckValues.find("Create your Deck!"); + if (it != t->deckValues.end()) + desc = it->second; + + deckmenu->Add(MENUITEM_NEW_DECK, "Create your Deck!", desc); + } premadeDeck = true; fillDeckMenu(deckmenu, JGE_GET_RES("player/premade")); } - if (!decksneeded) + else if (gModRules.general.hasDeckEditor()) { deckmenu->Add(MENUITEM_NEW_DECK, "New Deck...", "Create a new deck to play with."); } diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index d416bac11..d0fd7fe33 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -19,6 +19,8 @@ #include "WFont.h" #include #include "Rules.h" +#include "ModRules.h" + #ifdef NETWORK_SUPPORT #include #endif//NETWORK_SUPPORT @@ -49,25 +51,6 @@ enum ENUM_MENU_STATE_MINOR MENU_STATE_MINOR = 0xF00 }; -enum -{ - SUBMENUITEM_CANCEL = kCancelMenuID, - MENUITEM_PLAY, - MENUITEM_DECKEDITOR, - MENUITEM_SHOP, - MENUITEM_OPTIONS, - MENUITEM_EXIT, - SUBMENUITEM_1PLAYER, -#ifdef NETWORK_SUPPORT - SUBMENUITEM_2PLAYERS, - SUBMENUITEM_HOST_GAME, - SUBMENUITEM_JOIN_GAME, -#endif //NETWORK_SUPPORT - SUBMENUITEM_DEMO, - SUBMENUITEM_TESTSUITE, - SUBMENUITEM_END_OFFSET -}; - GameStateMenu::GameStateMenu(GameApp* parent) : GameState(parent) { @@ -150,10 +133,6 @@ void GameStateMenu::Start() hasChosenGameType = false; mParent->gameType = GAME_TYPE_CLASSIC; - /* - if (options[Options::MOMIR_MODE_UNLOCKED].number) hasChosenGameType = 0; - if (options[Options::RANDOMDECK_MODE_UNLOCKED].number) hasChosenGameType = 0; - */ bgTexture = WResourceManager::Instance()->RetrieveTexture("menutitle.png", RETRIEVE_LOCK); mBg = WResourceManager::Instance()->RetrieveQuad("menutitle.png", 0, 0, 256, 166); // Create background quad for rendering. @@ -170,13 +149,25 @@ void GameStateMenu::genNbCardsStr() { //How many cards total ? PlayerData * playerdata = NEW PlayerData(MTGCollection()); - if (playerdata && !options[Options::ACTIVE_PROFILE].isDefault()) - sprintf(nbcardsStr, _("%s: %i cards (%i) (%i unique)").c_str(), options[Options::ACTIVE_PROFILE].str.c_str(), - playerdata->collection->totalCards(), MTGCollection()->totalCards(), - MTGCollection()->primitives.size()); + size_t totalUnique = MTGCollection()->primitives.size(); + size_t totalPrints = MTGCollection()->totalCards(); + + if (totalUnique != totalPrints) + { + if (playerdata && !options[Options::ACTIVE_PROFILE].isDefault()) + sprintf(nbcardsStr, _("%s: %i cards (%i) (%i unique)").c_str(), options[Options::ACTIVE_PROFILE].str.c_str(), + playerdata->collection->totalCards(), totalPrints,totalUnique); + else + sprintf(nbcardsStr, _("%i cards (%i unique)").c_str(),totalPrints,totalUnique); + } else - sprintf(nbcardsStr, _("%i cards (%i unique)").c_str(), MTGCollection()->totalCards(), - MTGCollection()->primitives.size()); + { + if (playerdata && !options[Options::ACTIVE_PROFILE].isDefault()) + sprintf(nbcardsStr, _("%s: %i cards (%i)").c_str(), options[Options::ACTIVE_PROFILE].str.c_str(), + playerdata->collection->totalCards(), totalPrints); + else + sprintf(nbcardsStr, _("%i cards").c_str(),totalPrints); + } SAFE_DELETE(playerdata); } @@ -239,18 +230,22 @@ void GameStateMenu::fillScroller() scroller->Add(buff2); PlayerData * playerdata = NEW PlayerData(MTGCollection()); - int totalCards = playerdata->collection->totalCards(); - if (totalCards) + + if (gModRules.general.hasDeckEditor() && gModRules.general.hasShop()) { - sprintf(buff2, _("You have a total of %i cards in your collection").c_str(), totalCards); - scroller->Add(buff2); + int totalCards = playerdata->collection->totalCards(); + if (totalCards) + { + sprintf(buff2, _("You have a total of %i cards in your collection").c_str(), totalCards); + scroller->Add(buff2); - int estimatedValue = playerdata->collection->totalPrice(); - sprintf(buff2, _("The shopkeeper would buy your entire collection for around %i credits").c_str(), estimatedValue / 2); - scroller->Add(buff2); + int estimatedValue = playerdata->collection->totalPrice(); + sprintf(buff2, _("The shopkeeper would buy your entire collection for around %i credits").c_str(), estimatedValue / 2); + scroller->Add(buff2); - sprintf(buff2, _("The cards in your collection have an average value of %i credits").c_str(), estimatedValue / totalCards); - scroller->Add(buff2); + sprintf(buff2, _("The cards in your collection have an average value of %i credits").c_str(), estimatedValue / totalCards); + scroller->Add(buff2); + } } sprintf(buff2, _("You currently have %i credits").c_str(), playerdata->credits); @@ -400,6 +395,13 @@ void GameStateMenu::listPrimitives() mDip = opendir(JGE_GET_RES("sets/primitives/").c_str()); } + if (!mDip) + { + DebugTrace("GameStateMenu.cpp:WARNING:Primitives folder is missing"); + primitivesLoadCounter = 0; + return; + } + while ((mDit = readdir(mDip))) { string filename = JGE_GET_RES("sets/primitives/"); @@ -424,16 +426,28 @@ void GameStateMenu::ensureMGuiController() { WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MENU_FONT); mFont->SetColor(ARGB(255,255,255,255)); - mGuiController->Add(NEW MenuItem(MENUITEM_PLAY, mFont, "Play", 80, 50 + SCREEN_HEIGHT / 2, mIcons[8].get(), mIcons[9].get(), - "particle1.psi", WResourceManager::Instance()->GetQuad("particles").get(), true)); - mGuiController->Add(NEW MenuItem(MENUITEM_DECKEDITOR, mFont, "Deck Editor", 160, 50 + SCREEN_HEIGHT / 2, mIcons[2].get(), - mIcons[3].get(), "particle2.psi", WResourceManager::Instance()->GetQuad("particles").get())); - mGuiController->Add(NEW MenuItem(MENUITEM_SHOP, mFont, "Shop", 240, 50 + SCREEN_HEIGHT / 2, mIcons[0].get(), mIcons[1].get(), - "particle3.psi", WResourceManager::Instance()->GetQuad("particles").get())); - mGuiController->Add(NEW MenuItem(MENUITEM_OPTIONS, mFont, "Options", 320, 50 + SCREEN_HEIGHT / 2, mIcons[6].get(), mIcons[7].get(), - "particle4.psi", WResourceManager::Instance()->GetQuad("particles").get())); - mGuiController->Add(NEW MenuItem(MENUITEM_EXIT, mFont, "Exit", 400, 50 + SCREEN_HEIGHT / 2, mIcons[4].get(), mIcons[5].get(), - "particle5.psi", WResourceManager::Instance()->GetQuad("particles").get())); + vectoritems = gModRules.menu.main; + + int numItems = (int)items.size(); + float startX = 80.f; + float totalSize = SCREEN_WIDTH_F - (2 * startX); + float space = 0; + if (numItems < 2) + startX = SCREEN_WIDTH_F/2; + else + space = totalSize/(numItems - 1); + + for (size_t i = 0; i < items.size(); ++i) { + ModRulesMainMenuItem * item = items[i]; + int iconId = (item->mIconId - 1) * 2; + mGuiController->Add(NEW MenuItem( + item->mActionId, + mFont, item->mDisplayName, + startX + (i * space), 50 + SCREEN_HEIGHT / 2, + mIcons[iconId].get(), mIcons[iconId + 1].get(), + item->mParticleFile.c_str(), WResourceManager::Instance()->GetQuad("particles").get(), + (i == 0))); + } } } } @@ -527,15 +541,23 @@ void GameStateMenu::Update(float dt) currentState &= MENU_STATE_MAJOR_MAINMENU; options.reloadProfile(); //Handles building a new deck, if needed. break; - case MENU_STATE_MAJOR_MAINMENU: - if (!scrollerSet) - fillScroller(); - ensureMGuiController(); - if (mGuiController) - mGuiController->Update(dt); - if (mEngine->GetButtonState(JGE_BTN_NEXT)) //Hook for GameStateAward state - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_AWARDS); //TODO: A slide transition would be nice. - break; + case MENU_STATE_MAJOR_MAINMENU: + { + if (!scrollerSet) + fillScroller(); + ensureMGuiController(); + if (mGuiController) + mGuiController->Update(dt); + + //Hook for Top Menu actions + vectoritems = gModRules.menu.other; + for (size_t i = 0; i < items.size(); ++i) + { + if (mEngine->GetButtonState(items[i]->mKey) && items[i]->getMatchingGameState()) + mParent->DoTransition(TRANSITION_FADE, items[i]->getMatchingGameState()); //TODO: Add the transition as a parameter in the rules file + } + break; + } #ifdef NETWORK_SUPPORT case MENU_STATE_NETWORK_DEFINE: currentState = MENU_STATE_MAJOR_SUBMENU; @@ -639,6 +661,83 @@ void GameStateMenu::Update(float dt) } } +//Renders the "sub" menu with shoulder button links +void GameStateMenu::RenderTopMenu() +{ + float leftTextPos = 10; + float rightTextPos = SCREEN_WIDTH - 10; + + vectoritems = gModRules.menu.other; + for (size_t i = 0; i < items.size(); ++i) + { + switch(items[i]->mKey) + { + case JGE_BTN_PREV: + leftTextPos += 64; + break; + case JGE_BTN_NEXT: + rightTextPos -= 64; + break; + default: + DebugTrace("not supported yet!"); + break; + } + } + + WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); + mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); + mFont->SetColor(ARGB(128,255,255,255)); + mFont->DrawString(GAME_VERSION, rightTextPos, 5, JGETEXT_RIGHT); + mFont->DrawString(nbcardsStr, leftTextPos, 5); + mFont->SetScale(1.f); + mFont->SetColor(ARGB(255,255,255,255)); + + if (!items.size()) + return; + + JQuadPtr jq = WResourceManager::Instance()->RetrieveTempQuad("button_shoulder.png"); + if (!jq.get()) + return; + + mFont = WResourceManager::Instance()->GetWFont(Fonts::OPTION_FONT); + float olds = mFont->GetScale(); + + for (size_t i = 0; i < items.size(); ++i) + { + ModRulesOtherMenuItem * item = items[i]; + + int alpha = 255; + if (item->mActionId == MENUITEM_TROPHIES && options.newAward()) + alpha = (int) (sin(timeIndex) * 255); + + float xPos = SCREEN_WIDTH - 64; + float xTextPos = xPos + 54; + int textAlign = JGETEXT_RIGHT; + jq->SetHFlip(false); + + switch(item->mKey) + { + case JGE_BTN_PREV: + xPos = 5; + xTextPos = xPos + 10; + textAlign = JGETEXT_LEFT; + jq->SetHFlip(true); + break; + default: + break; + } + + jq->SetColor(ARGB(abs(alpha),255,255,255)); + mFont->SetColor(ARGB(abs(alpha),0,0,0)); + string s = _(item->mDisplayName); + mFont->SetScale(1.0f); + mFont->SetScale(50.0f / mFont->GetStringWidth(s.c_str())); + JRenderer::GetInstance()->RenderQuad(jq.get(), xPos, 2); + mFont->DrawString(s, xTextPos, 9, textAlign); + mFont->SetScale(olds); + } +} + void GameStateMenu::Render() { if ((currentState & MENU_STATE_MINOR) == MENU_STATE_MINOR_FADEIN) @@ -690,38 +789,14 @@ void GameStateMenu::Render() if (mGuiController) mGuiController->Render(); - mFont->SetScale(DEFAULT_MAIN_FONT_SCALE); - mFont->SetColor(ARGB(128,255,255,255)); - mFont->DrawString(GAME_VERSION, SCREEN_WIDTH - 74, 5, JGETEXT_RIGHT); - mFont->DrawString(nbcardsStr, 10, 5); - mFont->SetScale(1.f); - mFont->SetColor(ARGB(255,255,255,255)); - renderer->FillRoundRect(SCREEN_WIDTH / 2 - 100, SCREEN_HEIGHT, 191, 6, 5, ARGB(100,10,5,0)); scroller->Render(); if (mBg.get()) renderer->RenderQuad(mBg.get(), SCREEN_WIDTH / 2, 50); - JQuadPtr jq = WResourceManager::Instance()->RetrieveTempQuad("button_shoulder.png"); - if (jq.get()) - { - int alp = 255; - if (options.newAward()) - alp = (int) (sin(timeIndex) * 255); - float olds = mFont->GetScale(); - mFont = WResourceManager::Instance()->GetWFont(Fonts::OPTION_FONT); - jq->SetColor(ARGB(abs(alp),255,255,255)); - mFont->SetColor(ARGB(abs(alp),0,0,0)); - string s = _("Trophy Room"); - ; - mFont->SetScale(1.0f); - mFont->SetScale(50.0f / mFont->GetStringWidth(s.c_str())); - renderer->RenderQuad(jq.get(), SCREEN_WIDTH - 64, 2); - mFont->DrawString(s, SCREEN_WIDTH - 10, 9, JGETEXT_RIGHT); - mFont = WResourceManager::Instance()->GetWFont(Fonts::MENU_FONT); - mFont->SetScale(olds); - } + RenderTopMenu(); + } if (subMenuController) { @@ -762,20 +837,20 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId) subMenuController->Add(SUBMENUITEM_DEMO, "Demo"); subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel"); #ifdef TESTSUITE - subMenuController->Add(SUBMENUITEM_TESTSUITE, "Test Suite"); + if (Rules::getRulesByFilename("testsuite.txt")) + subMenuController->Add(SUBMENUITEM_TESTSUITE, "Test Suite"); #endif currentState = MENU_STATE_MAJOR_SUBMENU | MENU_STATE_MINOR_NONE; } break; + case MENUITEM_DECKEDITOR: - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_DECK_VIEWER); - break; case MENUITEM_SHOP: - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_SHOP); - break; case MENUITEM_OPTIONS: - mParent->DoTransition(TRANSITION_FADE, GAME_STATE_OPTIONS); + case MENUITEM_TROPHIES: + mParent->DoTransition(TRANSITION_FADE, ModRulesMenuItem::getMatchingGameState(controlId)); break; + case MENUITEM_EXIT: mEngine->End(); break; diff --git a/projects/mtg/src/GuiPlay.cpp b/projects/mtg/src/GuiPlay.cpp index fec6b0d60..af036e1fa 100644 --- a/projects/mtg/src/GuiPlay.cpp +++ b/projects/mtg/src/GuiPlay.cpp @@ -5,6 +5,7 @@ #include "GuiPlay.h" #include "Subtypes.h" #include "Trash.h" +#include "ModRules.h" #define CARD_WIDTH (31) @@ -236,12 +237,12 @@ void GuiPlay::Replace() } } float x = 24 + opponentSpells.nextX(); - //seperated the varible X into 2 different varibles. There are 2 players here!! - //we should not be using a single varible to determine the positioning of cards!! + //seperated the variable X into 2 different variables. There are 2 players here!! + //we should not be using a single variable to determine the positioning of cards!! float myx = 24 + selfSpells.nextX(); opponentLands.reset(opponentLandsN,x, 50); opponentCreatures.reset(opponentCreaturesN, x, 95); - battleField.reset(x, 145);//what does this varible do? i can comment it out with no reprocussions...is this being double handled? + battleField.reset(x, 145);//what does this variable do? I can comment it out with no repercussions...is this being double handled? selfCreatures.reset(selfCreaturesN, myx, 195); selfLands.reset(selfLandsN, myx, 240); @@ -346,7 +347,12 @@ int GuiPlay::receiveEventPlus(WEvent * e) else card = NEW CardView(CardView::playZone, event->card, 0, 0); cards.push_back(card); - card->t = event->card->isTapped() ? M_PI / 2 : 0; + + if (event->card->isTapped()) + gModRules.cards.activateEffect->doEffect(card); + else + gModRules.cards.activateEffect->undoEffect(card); + card->alpha = 255; // Make sure that the card is repositioned before adding it to the CardSelector, as @@ -371,10 +377,20 @@ int GuiPlay::receiveEventPlus(WEvent * e) else if (WEventCardTap* event = dynamic_cast(e)) { if (CardView* cv = dynamic_cast(event->card->view)) - cv->t = event->after ? M_PI / 2 : 0; + { + if (event->after) + gModRules.cards.activateEffect->doEffect(cv); + else + gModRules.cards.activateEffect->undoEffect(cv); + //cv->t = event->after ? M_PI / 2 : 0; + } else if (event->card->view != NULL) { - event->card->view->actT = event->after ? M_PI / 2 : 0; + if (event->after) + gModRules.cards.activateEffect->doEffect(event->card->view); + else + gModRules.cards.activateEffect->undoEffect(event->card->view); + //event->card->view->actT = event->after ? M_PI / 2 : 0; } else { diff --git a/projects/mtg/src/MenuItem.cpp b/projects/mtg/src/MenuItem.cpp index 1aaf70ab0..9f203411b 100644 --- a/projects/mtg/src/MenuItem.cpp +++ b/projects/mtg/src/MenuItem.cpp @@ -10,8 +10,13 @@ MenuItem::MenuItem(int id, WFont *font, string text, float x, float y, JQuad * _ { mText = _(text); updatedSinceLastRender = 1; - mParticleSys = NEW hgeParticleSystem(WResourceManager::Instance()->RetrievePSI(particle, particleTex)); - mParticleSys->MoveTo(mX, mY); + mParticleSys = NULL; + hgeParticleSystemInfo * psi = WResourceManager::Instance()->RetrievePSI(particle, particleTex); + if (psi) + { + mParticleSys = NEW hgeParticleSystem(psi); + mParticleSys->MoveTo(mX, mY); + } mHasFocus = hasFocus; lastDt = 0.001f; @@ -73,20 +78,22 @@ void MenuItem::Update(float dt) mScale = mTargetScale; } - mParticleSys->Update(dt); + if (mParticleSys) + mParticleSys->Update(dt); } void MenuItem::Entering() { - - mParticleSys->Fire(); + if (mParticleSys) + mParticleSys->Fire(); mHasFocus = true; mTargetScale = 1.3f; } bool MenuItem::Leaving(JButton key) { - mParticleSys->Stop(true); + if (mParticleSys) + mParticleSys->Stop(true); mHasFocus = false; mTargetScale = 1.0f; return true; @@ -99,8 +106,7 @@ bool MenuItem::ButtonPressed() MenuItem::~MenuItem() { - if (mParticleSys) - delete mParticleSys; + SAFE_DELETE(mParticleSys); } ostream& MenuItem::toString(ostream& out) const diff --git a/projects/mtg/src/ModRules.cpp b/projects/mtg/src/ModRules.cpp new file mode 100644 index 000000000..acf57f1cf --- /dev/null +++ b/projects/mtg/src/ModRules.cpp @@ -0,0 +1,269 @@ +#include "PrecompiledHeader.h" + +#include "ModRules.h" +#include "utils.h" +#include "GameState.h" +#include "../../../JGE/src/tinyxml/tinyxml.h" + + +ModRules gModRules; + +bool ModRules::load(string filename) +{ + JFileSystem *fileSystem = JFileSystem::GetInstance(); + if (!fileSystem) return false; + + if (!fileSystem->OpenFile(filename.c_str())) + { + DebugTrace("FATAL: " << filename << "Does not exist"); + return false; + } + + int size = fileSystem->GetFileSize(); + char *xmlBuffer = NEW char[size]; + fileSystem->ReadFile(xmlBuffer, size); + + TiXmlDocument doc; + doc.Parse(xmlBuffer); + + fileSystem->CloseFile(); + delete[] xmlBuffer; + + for (TiXmlNode* node = doc.FirstChild(); node; node = node->NextSibling()) + { + TiXmlElement* element = node->ToElement(); + if (element != NULL) + { + if (strcmp(element->Value(), "menu") == 0) + { + menu.parse(element); + } + else if (strcmp(element->Value(), "general") == 0) + { + general.parse(element); + } + else if (strcmp(element->Value(), "cards") == 0) + { + cards.parse(element); + } + } + } + return true; +} + +int ModRulesMenuItem::strToAction(string str) +{ + if (str.compare("playMenu") == 0) + return MENUITEM_PLAY; + if (str.compare("deckEditor") == 0) + return MENUITEM_DECKEDITOR; + if (str.compare("shop") == 0) + return MENUITEM_SHOP; + if (str.compare("options") == 0) + return MENUITEM_OPTIONS; + if (str.compare("quit") == 0) + return MENUITEM_EXIT; + if (str.compare("trophies") == 0) + return MENUITEM_TROPHIES; + + return MENUITEM_PLAY; +} + +ModRulesMenuItem::ModRulesMenuItem(string actionIdStr, string displayName) +{ + mActionId = strToAction(actionIdStr); + mDisplayName = displayName; +} + + +int ModRulesMenuItem::getMatchingGameState() +{ + return getMatchingGameState(mActionId); +} + +int ModRulesMenuItem::getMatchingGameState(int actionId) +{ + switch (actionId) + { + case MENUITEM_DECKEDITOR: + return GAME_STATE_DECK_VIEWER; + case MENUITEM_SHOP: + return GAME_STATE_SHOP; + case MENUITEM_OPTIONS: + return GAME_STATE_OPTIONS; + case MENUITEM_TROPHIES: + return GAME_STATE_AWARDS; + default: + return GAME_STATE_NONE; + } +} + +ModRulesMainMenuItem::ModRulesMainMenuItem(string actionIdStr, string displayName, int iconId, string particleFile): + ModRulesMenuItem(actionIdStr, displayName), mIconId(iconId), mParticleFile(particleFile) +{ +} + +JButton ModRulesOtherMenuItem::strToJButton(string str) +{ + if (str.compare("btn_next") == 0) + return JGE_BTN_NEXT; + if (str.compare("btn_prev") == 0) + return JGE_BTN_PREV; + if (str.compare("btn_ctrl") == 0) + return JGE_BTN_CTRL; + if (str.compare("btn_menu") == 0) + return JGE_BTN_MENU; + if (str.compare("btn_cancel") == 0) + return JGE_BTN_CANCEL; + if (str.compare("btn_pri") == 0) + return JGE_BTN_PRI; + if (str.compare("btn_sec") == 0) + return JGE_BTN_SEC; + + return JGE_BTN_NEXT; +} + + +ModRulesOtherMenuItem::ModRulesOtherMenuItem(string actionIdStr, string displayName, string keyStr): ModRulesMenuItem(actionIdStr, displayName) +{ + mKey = strToJButton(keyStr); +} + +void ModRulesMenu::parse(TiXmlElement* element) +{ + TiXmlNode* mainNode = element->FirstChild("main"); + if (mainNode) { + for (TiXmlNode* node = mainNode->ToElement()->FirstChild("item"); node; node = node->NextSibling("item")) + { + TiXmlElement* element = node->ToElement(); + { + main.push_back(NEW ModRulesMainMenuItem( + element->Attribute("action"), + element->Attribute("displayName"), + atoi(element->Attribute("iconId")), + element->Attribute("particleFile"))); + } + } + } + + TiXmlNode* otherNode = element->FirstChild("other"); + if (otherNode) { + for (TiXmlNode* node = otherNode->ToElement()->FirstChild("item"); node; node = node->NextSibling("item")) + { + TiXmlElement* element = node->ToElement(); + if (element) + { + other.push_back(NEW ModRulesOtherMenuItem( + element->Attribute("action"), + element->Attribute("displayName"), + element->Attribute("key"))); + } + } + } +} + +ModRulesMenu::~ModRulesMenu() +{ + for (size_t i = 0; i < main.size(); ++i) + SAFE_DELETE(main[i]); + + for (size_t i = 0; i < other.size(); ++i) + SAFE_DELETE(other[i]); + + main.clear(); + other.clear(); +} + +ModRulesGeneral::ModRulesGeneral() +{ + mHasDeckEditor = true; + mHasShop = true; +} + +int ModRules::getValueAsInt(TiXmlElement* element, string childName){ + TiXmlNode* node = element->FirstChild(childName.c_str()); + if (node) { + const char* value = node->ToElement()->GetText(); + return atoi(value); + } + return -1; +} + +void ModRulesGeneral::parse(TiXmlElement* element) +{ + int value = ModRules::getValueAsInt(element, "hasDeckEditor"); + if (value != -1) + mHasDeckEditor = value; + + value = ModRules::getValueAsInt(element, "hasShop"); + if (value != -1) + mHasShop = value; + +} + +ModRulesCards::ModRulesCards() +{ + activateEffect = NEW SimpleCardEffectRotate(M_PI/2); //Default activation effect +} + +SimpleCardEffect * ModRulesCards::parseEffect(string s) +{ + size_t limiter = s.find("("); + string function, params; + if (limiter != string::npos) + { + function = s.substr(0, limiter); + params = s.substr(limiter+1, s.size() - 2 - limiter); + } + else + { + function = s; + } + + if (function.compare("rotate") == 0) + { + return NEW SimpleCardEffectRotate(M_PI*atoi(params.c_str())/180); + } + + if (function.compare("mask") == 0) + { + vector argb = split( params, ','); + if (argb.size() < 4) + { + DebugTrace("not enough params in mask"); + return NULL; + } + PIXEL_TYPE mask = ARGB( + atoi(argb[0].c_str()), + atoi(argb[1].c_str()), + atoi(argb[2].c_str()), + atoi(argb[3].c_str()) + ); + return NEW SimpleCardEffectMask(mask); + } + return NULL; +} + +void ModRulesCards::parse(TiXmlElement* element) +{ + TiXmlNode* node = element->FirstChild("general"); + if (node) { + TiXmlElement* generalElement = node->ToElement(); + TiXmlNode* nodeActivation = generalElement->FirstChild("activate"); + if (nodeActivation) { + TiXmlElement* activateElement = nodeActivation->ToElement(); + TiXmlNode* nodeUIEvent = activateElement->FirstChild("uiEvent"); + if (nodeUIEvent) { + const char* event = nodeUIEvent->ToElement()->GetText(); + SAFE_DELETE(activateEffect); + activateEffect = parseEffect(event); + } + } + } + +} + +ModRulesCards::~ModRulesCards() +{ + SAFE_DELETE(activateEffect); +} diff --git a/projects/mtg/src/Pos.cpp b/projects/mtg/src/Pos.cpp index d8f952fd3..88c9ecae2 100644 --- a/projects/mtg/src/Pos.cpp +++ b/projects/mtg/src/Pos.cpp @@ -6,6 +6,7 @@ Pos::Pos(float x, float y, float z, float t, float a) : actX(x), actY(y), actZ(z), actT(t), actA(a), x(x), y(y), zoom(z), t(t), alpha(a) { + mask = 0; } void Pos::Update(float dt) { @@ -32,4 +33,7 @@ void Pos::Render(JQuad* quad) { quad->SetColor(ARGB((int)actA, 255, 255, 255)); JRenderer::GetInstance()->RenderQuad(quad, actX, actY, actT, actZ, actZ); + if (mask && !actT) + JRenderer::GetInstance()->FillRect(actX,actY,actZ * quad->mWidth, actZ* quad->mHeight, mask); + } diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index a35563a45..35bfa1c01 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -555,6 +555,9 @@ bool Rules::canChooseDeck() int Rules::load(string _filename) { + if (_filename.size() < 5 || _filename.find(".txt") == string::npos) + return 0; + if (!filename.size()) //this check is necessary because of the recursive calls (a fil loads other files) filename = _filename; char c_filename[4096]; diff --git a/projects/mtg/template.vcxproj b/projects/mtg/template.vcxproj index 21db2caab..ab4af142b 100644 --- a/projects/mtg/template.vcxproj +++ b/projects/mtg/template.vcxproj @@ -369,6 +369,7 @@ + @@ -483,6 +484,7 @@ + diff --git a/projects/mtg/template.vcxproj.filters b/projects/mtg/template.vcxproj.filters index 7f6da0455..25457ba1e 100644 --- a/projects/mtg/template.vcxproj.filters +++ b/projects/mtg/template.vcxproj.filters @@ -304,6 +304,9 @@ src + + src + @@ -630,6 +633,9 @@ inc + + inc +