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
+