diff --git a/projects/mtg/include/DeckMenu.h b/projects/mtg/include/DeckMenu.h index 8e053284d..5c92574f1 100644 --- a/projects/mtg/include/DeckMenu.h +++ b/projects/mtg/include/DeckMenu.h @@ -5,18 +5,19 @@ #define _DeckMenu_H_ #include -#include #include "WFont.h" #include "hge/hgeparticle.h" #include "DeckMetaData.h" - +#include "TextScroller.h" class DeckMenu:public JGuiController{ - private: + protected: + int mHeight, mWidth, mX, mY; int titleX, titleY, titleWidth; int descX, descY, descHeight, descWidth; int statsX, statsY, statsHeight, statsWidth; + int avatarX, avatarY; int fontId; std::string title; @@ -26,23 +27,23 @@ class DeckMenu:public JGuiController{ float timeOpen; static unsigned int refCount; - JQuad *background; - JTexture *backgroundTexture; static WFont* titleFont; static hgeParticleSystem* stars; // This works only because of no multithreading static PIXEL_TYPE jewelGraphics[9]; - inline void MogrifyJewel(); - public: - + TextScroller * scroller; bool autoTranslate; - DeckMenu(int id, JGuiListener* listener, int fontId, const char * _title = ""); + + DeckMenu(int id, JGuiListener* listener, int fontId, const string _title = ""); + ~DeckMenu(); + void Render(); void Update(float dt); void Add(int id, const char * Text, string desc = "", bool forceFocus = false, DeckMetaData *deckMetaData = NULL); void Close(); + void updateScroller(); float selectionTargetY; bool closed; diff --git a/projects/mtg/include/GameStateDuel.h b/projects/mtg/include/GameStateDuel.h index 256b64fad..69b913575 100644 --- a/projects/mtg/include/GameStateDuel.h +++ b/projects/mtg/include/GameStateDuel.h @@ -7,7 +7,6 @@ #include "DeckMenu.h" #include "MTGDeck.h" #include "GameObserver.h" -#include "TextScroller.h" #define CHOOSE_OPPONENT 7 @@ -33,7 +32,6 @@ class GameStateDuel: public GameState, public JGuiListener DeckMenu * deckmenu; DeckMenu * opponentMenu; SimpleMenu * menu; - TextScroller * scroller; bool premadeDeck; int OpponentsDeckid; string musictrack; diff --git a/projects/mtg/include/TextScroller.h b/projects/mtg/include/TextScroller.h index d5a7e2ae4..4f45486c6 100644 --- a/projects/mtg/include/TextScroller.h +++ b/projects/mtg/include/TextScroller.h @@ -18,6 +18,8 @@ protected: float mY; float start; int timer; + int minimumItems; + vector strings; unsigned int currentId; int mRandom; @@ -27,7 +29,7 @@ public: void Add(string text); void Reset(); void setRandom(int mode = 1); - TextScroller(int fontId, float x, float y, float width, float speed = 30, int scrollerType = 0); + TextScroller(int fontId, float x, float y, float width, float speed = 30, int scrollerType = 0, int _minimumItems = 2); void Render(); void Update(float dt); virtual ostream& toString(ostream& out) const; diff --git a/projects/mtg/include/utils.h b/projects/mtg/include/utils.h index 93d1f98bb..2a24a4576 100644 --- a/projects/mtg/include/utils.h +++ b/projects/mtg/include/utils.h @@ -41,6 +41,7 @@ string& rtrim(string &str); std::vector &split(const std::string &s, char delim, std::vector &elems); std::vector split(const std::string &s, char delim); //splits a string with "delim" and returns a vector of strings. +std::string wordWrap(std::string s, int width); int loadRandValues(string s); diff --git a/projects/mtg/src/DeckMenu.cpp b/projects/mtg/src/DeckMenu.cpp index 41e7cc797..7234d7705 100644 --- a/projects/mtg/src/DeckMenu.cpp +++ b/projects/mtg/src/DeckMenu.cpp @@ -6,13 +6,16 @@ #include "JTypes.h" #include "GameApp.h" #include "Translate.h" - +#include "TextScroller.h" +#include "Tasks.h" +#include namespace { - const unsigned int kPoleWidth = 7; const unsigned int kVerticalMargin = 16; const unsigned int kHorizontalMargin = 30; const signed int kLineHeight = 20; + const signed int kDescriptionVerticalBoxPadding = 5; + const signed int kDescriptionHorizontalBoxPadding = 5; } WFont* DeckMenu::titleFont = NULL; @@ -26,49 +29,64 @@ PIXEL_TYPE DeckMenu::jewelGraphics[9] = {0x3FFFFFFF,0x63645AEA,0x610D0D98, // // For the additional info window, maximum characters per line is roughly 30 characters across. // TODO: figure a way to get incoming text to wrap. -// +// // used fixed locations where the menu, title and descriptive text are located. // * menu at (125, 60 ) // * descriptive information 125 +// *** Need to make this configurable in a file somewhere to allow for class reuse -DeckMenu::DeckMenu(int id, JGuiListener* listener, int fontId, const char * _title) +DeckMenu::DeckMenu(int id, JGuiListener* listener, int fontId, const string _title) : JGuiController(id, listener), fontId(fontId) { - background = NULL; + + mX = 120; + mY = 55; + + titleX = 125; // center point in title box + titleY = 28; + titleWidth = 180; // width of inner box of title + + descX = 230 + kDescriptionVerticalBoxPadding; + descY = 65 + kDescriptionHorizontalBoxPadding; + descHeight = 145; + descWidth = 220; + + statsX = 280; + statsY = 8; + statsHeight = 50; + statsWidth = 227; + + + avatarX = 230; + avatarY = 8; + + int scrollerWidth = 80; + + scroller = NEW TextScroller(Fonts::MAIN_FONT, 40 , 230, scrollerWidth, 100, 1, 1); + autoTranslate = true; maxItems = 7; + mHeight = 2 * kVerticalMargin + ( maxItems * kLineHeight ); mWidth = 0; - mX = 125; - mY = 60; - // where to place the title of the menu - titleX = mX; - titleY = mY - 30; + // we want to cap the deck titles to 15 characters to avoid overflowing deck names title = _(_title); - // where stats information goes - statsX = 280; - statsY = 8 + kVerticalMargin; - statsHeight = 50; - statsWidth = SCREEN_WIDTH / 2 - 40; // 40 is the width of the right border - - // where to place the descripiton information - descX = 229; - descY = 70; - startId = 0; selectionT = 0; timeOpen = 0; closed = false; ++refCount; + selectionTargetY = selectionY = kVerticalMargin; if (NULL == stars) stars = NEW hgeParticleSystem(resources.RetrievePSI("stars.psi", resources.GetQuad("stars"))); - stars->FireAt(mX, mY); + + updateScroller(); } // TODO: Make this configurable, perhaps by user as part of the theme options. @@ -80,10 +98,11 @@ JQuad* getBackground() } -void DeckMenu::Render() { +void DeckMenu::Render() +{ JRenderer * renderer = JRenderer::GetInstance(); - WFont * titleFont = resources.GetWFont(Fonts::SMALLFACE_FONT); + WFont * titleFont = resources.GetWFont(Fonts::MAGIC_FONT); WFont * mFont = resources.GetWFont(fontId); // figure out where to place the stars initially @@ -123,15 +142,15 @@ void DeckMenu::Render() { for (int i = startId; i < startId + maxItems ; i++){ if (i > mCount-1) break; - if ( static_cast(mObjects[i])->mY - kLineHeight * startId < mY + height - kLineHeight + 7) { - DeckMenuItem *currentMenuItem = static_cast(mObjects[i]); + DeckMenuItem *currentMenuItem = static_cast(mObjects[i]); + if ( currentMenuItem->mY - kLineHeight * startId < mY + height - kLineHeight + 7) { if ( currentMenuItem->hasFocus()){ // display the avatar image if ( currentMenuItem->imageFilename.size() > 0 ) { JQuad * quad = resources.RetrieveTempQuad( currentMenuItem->imageFilename, TEXTURE_SUB_AVATAR ); if (quad) { - renderer->RenderQuad(quad, 232, 10, 0, 0.9f, 0.9f); + renderer->RenderQuad(quad, avatarX, avatarY); } } // fill in the description part of the screen @@ -147,11 +166,8 @@ void DeckMenu::Render() { oss << "Deck: " << currentMenuItem->meta->getName() << endl; oss << currentMenuItem->meta->getStatsSummary(); - mainFont->DrawString( oss.str(), statsX, statsY - kVerticalMargin ); + mainFont->DrawString( oss.str(), statsX, statsY ); } - - // fill in the bottom section of the screen. - // TODO: add text scroller of Tasks. } else { mFont->SetColor(ARGB(150,255,255,255)); @@ -160,6 +176,10 @@ void DeckMenu::Render() { } if (!title.empty()) titleFont->DrawString(title.c_str(), titleX, titleY, JGETEXT_CENTER); + + scroller->Render(); + renderer->RenderQuad(getBackground(), 0, 0 ); + } } @@ -181,6 +201,8 @@ void DeckMenu::Update(float dt){ closed = false; timeOpen += dt * 10; } + + scroller->Update(dt); } void DeckMenu::Add(int id, const char * text,string desc, bool forceFocus, DeckMetaData * deckMetaData) { @@ -196,6 +218,22 @@ void DeckMenu::Add(int id, const char * text,string desc, bool forceFocus, DeckM } } + +void DeckMenu::updateScroller() +{ + // add all the items from the Tasks db. + TaskList *taskList = NEW TaskList(); + scroller->Reset(); + for (vector::iterator it = taskList->tasks.begin(); it!=taskList->tasks.end(); it++) + { + ostringstream taskDescription; + taskDescription << "[ " << setw(4) << (*it)->getReward() << " / " << (*it)->getExpiration() << " ] " << (*it)->getDesc() << ". " << endl; + scroller->Add( taskDescription.str() ); + } + SAFE_DELETE(taskList); +} + + void DeckMenu::Close() { timeOpen = -1.0; @@ -206,3 +244,8 @@ void DeckMenu::Close() void DeckMenu::destroy(){ SAFE_DELETE(DeckMenu::stars); } + +DeckMenu::~DeckMenu() +{ + SAFE_DELETE(scroller); +} \ No newline at end of file diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index f8eba12e3..52db82ac6 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -15,7 +15,6 @@ #include "Credits.h" #include "Translate.h" #include "Rules.h" -#include "TextScroller.h" #ifdef TESTSUITE #include "TestSuiteAI.h" @@ -66,12 +65,10 @@ GameStateDuel::GameStateDuel(GameApp* parent): GameState(parent) { credits = NULL; rules = NULL; - initScroller(); } GameStateDuel::~GameStateDuel() { End(); - SAFE_DELETE(scroller); } @@ -97,7 +94,7 @@ void GameStateDuel::Start() if (mParent->players[i] == PLAYER_TYPE_HUMAN){ decksneeded = 1; - deckmenu = NEW DeckMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::MENU_FONT, "Choose a Deck"); + deckmenu = NEW DeckMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::MAGIC_FONT, "Choose a Deck"); DeckManager *deckManager = DeckManager::GetInstance(); vector playerDeckList = getValidDeckMetaData( options.profileFile() ); @@ -242,7 +239,7 @@ bool GameStateDuel::MusicExist(string FileName){ void GameStateDuel::ensureOpponentMenu(){ if (!opponentMenu){ - opponentMenu = NEW DeckMenu(DUEL_MENU_CHOOSE_OPPONENT, this, Fonts::MENU_FONT, "Choose Your Opponent"); + opponentMenu = NEW DeckMenu(DUEL_MENU_CHOOSE_OPPONENT, this, Fonts::MAGIC_FONT, "Choose Your Opponent"); opponentMenu->Add( MENUITEM_RANDOM_AI, "Random"); if (options[Options::EVILTWIN_MODE_UNLOCKED].number) opponentMenu->Add( MENUITEM_EVIL_TWIN, "Evil Twin", _("Can you play against yourself?").c_str()); @@ -254,21 +251,6 @@ void GameStateDuel::ensureOpponentMenu(){ } } -void GameStateDuel::initScroller() -{ - scroller = NEW TextScroller(Fonts::MAIN_FONT, 40 , 230, 400, 100, 1); - // add all the items from the Tasks db. - TaskList *taskList = NEW TaskList(); - scroller->Reset(); - for (vector::iterator it = taskList->tasks.begin(); it!=taskList->tasks.end(); it++) - { - ostringstream taskDescription; - taskDescription << (*it)->getDesc() <Add( taskDescription.str() ); - } - SAFE_DELETE(taskList); -} - void GameStateDuel::Update(float dt) { switch (mGamePhase) @@ -433,7 +415,6 @@ void GameStateDuel::Update(float dt) PlayerData * playerdata = NEW PlayerData(mParent->collection); playerdata->taskList->passOneDay(); playerdata->taskList->save(); - initScroller(); SAFE_DELETE(playerdata); SAFE_DELETE(menu); } @@ -445,9 +426,6 @@ void GameStateDuel::Update(float dt) if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_MENU); } -// Update the scroller - - scroller->Update(dt); } @@ -511,7 +489,6 @@ void GameStateDuel::Render() else if (deckmenu) deckmenu->Render(); - scroller->Render(); } break; case DUEL_STATE_ERROR_NO_DECK: diff --git a/projects/mtg/src/TextScroller.cpp b/projects/mtg/src/TextScroller.cpp index ae895362a..392e5866e 100644 --- a/projects/mtg/src/TextScroller.cpp +++ b/projects/mtg/src/TextScroller.cpp @@ -11,9 +11,10 @@ enum { }; -TextScroller::TextScroller(int fontId, float x, float y, float width, float speed, int scrollerType ): JGuiObject(0), fontId(fontId){ +TextScroller::TextScroller(int fontId, float x, float y, float width, float speed, int scrollerType, int numItems ): JGuiObject(0), fontId(fontId){ mWidth = width; mSpeed = speed; + minimumItems = numItems; mX = x; mY = y; start = -width; @@ -60,18 +61,18 @@ void TextScroller::Update(float dt){ } else { - // we want to display 3 at a time + // we want to display 2 at a time ostringstream scrollerText; if ( timer == 0 ) { - for ( size_t idx = 0; idx < (MIN(2, strings.size())); idx ++ ) + for ( size_t idx = 0; idx < (MIN(minimumItems, strings.size())); idx ++ ) { scrollerText << strings[currentId + idx]; } currentId++; if ( currentId >= (strings.size()-1) ) currentId = 0; - mText = scrollerText.str(); + mText = wordWrap( scrollerText.str(), mWidth ); } timer = ++timer % ((int) mSpeed); } diff --git a/projects/mtg/src/utils.cpp b/projects/mtg/src/utils.cpp index 4ccd294d6..6510b9297 100644 --- a/projects/mtg/src/utils.cpp +++ b/projects/mtg/src/utils.cpp @@ -217,3 +217,42 @@ std::vector split(const std::string &s, char delim) { std::vector elems; return split(s, delim, elems); } + + +std::string wordWrap(std::string sentence, int width) +{ + std::string::iterator it = sentence.begin(); + + //remember how long next word is + int nextWordLength = 0; + int distanceFromWidth = width; + + while (it != sentence.end()) + { + while (*it != ' ') + { + nextWordLength++; + distanceFromWidth--; + + ++it; + + // check if done + if (it == sentence.end()) + { + return sentence; + } + } + + if (nextWordLength > distanceFromWidth) + { + *it = '\n'; + distanceFromWidth = width; + nextWordLength = 0; + } + + //skip the space + ++it; + } + + return sentence; +} \ No newline at end of file