Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

#pragma warning(disable:4244)
#pragma warning(disable:4018)


#include "LevelupEffect.h"
#include "Board.h"
#include "Res.h"
#include "SexyAppFramework/SexyAppBase.h"
#include "SexyAppFramework/Graphics.h"
#include "SexyAppFramework/Font.h"

using namespace Sexy;

const int STRIP_WIDTH   = 20;

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
LevelupEffect::LevelupEffect()
{
        Init();
        mActive = false;
        mCoverWidth = 0;
        mStripSizeChange = 60;
        mStripHeight = 0;
        mFadeOutAlpha = 255;
        mStartNextLevel = false;
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void LevelupEffect::Init()
{
        mText.clear();

        //////////////////////////////////////////////////////////////////////////
        //      Each letter, starting with the 'L' in "LEVEL UP!", will drop, delayed
        //      by a height of FONT_HUNGARR->GetHeight() pixels. Each letter will initially
        //      drop at a rate of 5 pixels per update (500 pixels per second). Once they
        //      reach their target Y coordinate (300), the speed will decrease and reverse
        //      to make the letters bounce upward. Gravity is applied each frame, so eventually
        //      the letters return back to Y of 300, where the speed is again decreased and
        //      reversed until it drops below the threshhold speed of 0.1 pixels per update.
        //////////////////////////////////////////////////////////////////////////     

        float x = (GRID_END_X - GRID_START_X) / 2 - FONT_HUNGARR->StringWidth(_S("LEVEL UP!")) / 2;
        float y = FONT_HUNGARR->GetHeight();
        float startingY = y;
        float ydec = y;
        float speed = 5.0f;

        mText.push_back(BouncyChar(_S("L"), x, y, speed));

        x += FONT_HUNGARR->StringWidth(_S("L"));
        y -= ydec;
        mText.push_back(BouncyChar(_S("E"), x, y, speed));

        x += FONT_HUNGARR->StringWidth(_S("E"));
        y -= ydec;
        mText.push_back(BouncyChar(_S("V"), x, y, speed));

        x += FONT_HUNGARR->StringWidth(_S("V"));
        y -= ydec;
        mText.push_back(BouncyChar(_S("E"), x, y, speed));

        x += FONT_HUNGARR->StringWidth(_S("E"));
        y -= ydec;
        mText.push_back(BouncyChar(_S("L"), x, y, speed));



        x += FONT_HUNGARR->StringWidth(_S("L "));
        y -= ydec;
        mText.push_back(BouncyChar(_S("U"), x, y, speed));

        x += FONT_HUNGARR->StringWidth(_S("U"));
        y -= ydec;
        mText.push_back(BouncyChar(_S("P"), x, y, speed));

        x += FONT_HUNGARR->StringWidth(_S("P"));
        y -= ydec;
        mText.push_back(BouncyChar(_S("!"), x, y, speed));
       
        mDone = false;
        mHue = 0;
        mCurtainX = 0;
        mState = LevelupEffect::LEVELUP_TEXT;  
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void LevelupEffect::Activate(LevelupStats ls)
{
        Init();
        mActive = true;
        mStats = ls;

        gSexyAppBase->PlaySample(SOUND_LEVEL_UP1);
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void LevelupEffect::Update(float theFrac)
{

        // HSL is an alternative to specifying an RGB color format.
        // Using HSL lets us easily do the hyper blinking crazy weird
        // flashing effect commonly found in old games, such as Robotron.
        // Below, we increment the value by 7 per update. The &0xFF is an
        // easy way to clamp the value between 0 and 255 instead of having to
        // do a separate if (mHue > 255) mHue -= 255. This lets the value
        // rollover and keep cycling.
        mHue = (mHue + 7) & 0xFF;

        if (mState == LevelupEffect::LEVELUP_TEXT)
        {
                // Move all the letters, applying 0.15 pixels per update of
                // "gravity" to pull the letters down. Once reaching Y of 300,
                // the speed of the letters decreases by 0.75 and is reversed, making
                // them "bounce" in the up direction. Once this bounce speed drops below 0.1
                // pixels per update, the letter is done bouncing. When all letters are done bouncing,
                // switch to the next state.
                bool allDone = true;
                for (int i = 0; i < mText.size(); i++)
                {
                        BouncyChar* c = &mText[i];

                        if (c->mDone)
                                continue;

                        c->mY += c->mBounceSpeed;
                       
                        c->mBounceSpeed += 0.15f;

                        if (c->mY >= 300)
                        {
                                c->mY = 300;

                                c->mOldBounceSpeed -= 0.750f;
                                if (c->mOldBounceSpeed <= 0.1f)
                                {
                                        c->mDone = true;
                                        c->mOldBounceSpeed = 0;
                                }
                                else
                                {
                                        allDone = false;
                                        c->mBounceSpeed = -c->mOldBounceSpeed;
                                }
                        }
                        else
                                allDone = false;
                }

                if (allDone)
                        mState = LevelupEffect::CURTAIN_IN;
        }
        else if (mState == LevelupEffect::CURTAIN_IN)
        {
                // Moves the black rectangles ("curtains") inward to cover up the
                // previous level. We only move the left one. The right one is logically
                // just the same width but starting from the right of the screen instead
                // of the left. The curtain moves 25 pixels per update. Once it reaches
                // the center (and thus fully covers the screen), we switch to the next state.
                if ((mCurtainX += 25) >= gSexyAppBase->mWidth / 2)
                {
                        mCurtainX = gSexyAppBase->mWidth / 2;
                        mState = LevelupEffect::CURTAIN_OUT;
                        gSexyAppBase->PlaySample(SOUND_LEVEL_UP2);
                }
        }
        else if (mState == LevelupEffect::CURTAIN_OUT)
        {
                // Now the curtain is red and slowly moves back out to reveal the
                // stats below it. This works just like above.
                if ((mCurtainX -= 2) <= 0)
                        mState = LevelupEffect::SHOWING_STATS;
        }
        else if (mState == LevelupEffect::COVERING_STATS)
        {
                // This state begins when the user clicks the mouse to dismiss the
                // stats screen. We then make these strips quickly appear. Imagine
                // rectangles of width 20 coming in from the left and right of the screen.
                // The left one starts comign from the top left of the screen, the right
                // from the bottom right. These strips quickly expand to be screen height in size
                // and then move closer inward (by their width of 20) and reverse the direction
                // that they come in at. Once the strips have traveled to the center of the screen,
                // it's fully covered and we then move to the next state. After a strip becomes
                // the height of the screen, we update mCoverWidth, which is just simply the width
                // of the region fully filled in. Again, like with the curtain effects, we only
                // keep track of the left side, since the right moves the same amount and it's
                // easy to compute the right's offsets.
                if (mStripSizeChange > 0)
                {
                        // Left strip is moving downward from Y of 0, right is moving up
                        // from Y of app height
                        if ((mStripHeight += mStripSizeChange) >= gSexyAppBase->mHeight)
                        {
                                // Left strip and right strip are now the height of the screen.
                                // Reverse the direction they come in at and reset their heights.
                                // Then, increment the width of the fully covered region by the
                                // size of one of the strip's width.
                                mStripSizeChange = -mStripSizeChange;
                                mStripHeight = 0;
                                if ((mCoverWidth += STRIP_WIDTH) >= gSexyAppBase->mWidth / 2)
                                {
                                        // The screen is fully covered. Fade out.
                                        mStartNextLevel = true;
                                        mState = LevelupEffect::FADE_OUT_STATS;
                                }
                        }
                }
                else
                {
                        if ((mStripHeight -= mStripSizeChange) >= gSexyAppBase->mHeight)
                        {
                                mStripSizeChange = -mStripSizeChange;
                                mStripHeight = 0;
                                if ((mCoverWidth += STRIP_WIDTH) >= gSexyAppBase->mWidth / 2)
                                {
                                        mStartNextLevel = true;
                                        mState = LevelupEffect::FADE_OUT_STATS;
                                }
                        }
                }                              
        }      
        else if (mState == LevelupEffect::FADE_OUT_STATS)
        {
                //Fade the screen out, with the next level appearing below it.
                if ((mFadeOutAlpha -= 2) <= 0)
                {
                        mDone = true;
                        mActive = false;
                }
        }
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void LevelupEffect::Draw(Graphics* g)
{
        g->SetFont(FONT_HUNGARR);
        if (mState == LevelupEffect::LEVELUP_TEXT)
        {              
                // This is how we convert an HSL value to an RGB value, which we have to
                // do to specify the color for the graphics object. The function HSLToRGB
                // takes as parameters: hue, saturation, luminance. We want to leave the
                // saturation at max and luminance at half for our particular example.
                // The returned value is ANDed with 0xFFFFFFFF to clamp the values for
                // the alpha, red, green, and blue to the valid region of 0 to 255.
                g->SetColor( (gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFFFF) );
                for (int i = 0; i < mText.size(); i++)
                {
                        BouncyChar* c = &mText[i];
                        g->DrawString(c->mChar, c->mX, c->mY);
                }
        }
        else if (mState == LevelupEffect::CURTAIN_IN)
        {
                // The righ tcurtain is just the same width as the left, but starts from the right
                // side instead of X of 0.
                g->SetColor(Color(0, 0, 0));
                g->FillRect(0, 0, mCurtainX, gSexyAppBase->mHeight);
                g->FillRect(gSexyAppBase->mWidth - mCurtainX, 0, mCurtainX, gSexyAppBase->mHeight);
        }
        else if ((mState == LevelupEffect::SHOWING_STATS) || (mState == LevelupEffect::CURTAIN_OUT) ||
                                (mState == LevelupEffect::COVERING_STATS))
        {
                // When just showing the stats normally, fading out the red curtain (to reveal the stats
                // beneath it), or covering up the stats with the effect triggered when the user clicks
                // to begin the next level, we display info on the user's performance from the last level.
                int y = 50;
                g->SetColor(gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFFFF);
                SexyString s = StrFormat(_S("LEVEL %d COMPLETE!"), mStats.mLevelCompleted);
                g->DrawString(s, gSexyAppBase->mWidth / 2 - FONT_HUNGARR->StringWidth(s) / 2, y);

                g->SetColor(Color::White);
                s = _S("POPULATION CONSUMED:");
                int strWidth = FONT_HUNGARR->StringWidth(s);

                int rightX = strWidth + 100;
                y += 50;
                g->DrawString(s, 100, y);
                g->SetColor(Color(255, 0, 0));
                g->DrawString(CommaSeperate(mStats.mPopulationEaten), rightX + 5, y);

                y += FONT_HUNGARR->GetHeight();
                g->SetColor(Color::White);             
                s = _S("SYSTEMS SUBJUGATED:");
                strWidth = FONT_HUNGARR->StringWidth(s);
                g->DrawString(s, rightX - strWidth, y);
                g->SetColor(Color(255, 0, 0));
                g->DrawString(StrFormat(_S("%d%%"), mStats.mPercentComplete), rightX + 5, y);
               
                y += FONT_HUNGARR->GetHeight();
                if (mStats.mPercentComplete >= COMPLETION_BONUS_PCT)
                {
                        s = StrFormat(_S("%d%%+ BONUS:"), COMPLETION_BONUS_PCT);
                        g->SetColor(Color::White);
                        strWidth = FONT_HUNGARR->StringWidth(s);
                        g->DrawString(s, rightX - strWidth, y);
                        g->SetColor(Color(255, 0, 0));
                        g->DrawString(StrFormat(_S("%d"), COMPLETION_BONUS * mStats.mLevelCompleted),
                                                        rightX + 5, y);
                }

                if (mStats.mPlanetsEaten.size() > 0)
                {
                        y += 50;
                        int third =  gSexyAppBase->mWidth / 3;
                        g->SetColor(Color(255, 255, 0));

                        s = _S("PLANET EATEN:");
                        g->DrawString(s, third / 2 - FONT_HUNGARR->StringWidth(s) / 2, y);
                        s = _S("EXPORTS:");
                        g->DrawString(s, third + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
                        s = _S("POPULATION:");
                        g->DrawString(s, third*2 + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
                       
                        y += FONT_HUNGARR->GetHeight();

                        // If the user ate too many planets to fit on screen, we'll just display "..."
                        // to indicate that they ate a bunch but we just can't fit it all on screen.
                        // In reality, it'd be best to either ensure that all the planets fit on screen,
                        // or that there's some sort of scrolling mechanism to allow the user to view all their
                        // stats.
                        bool drawDotDotDot = false;
                        for (int i = 0; i < mStats.mPlanetsEaten.size(); i += 3)
                        {
                                if (y >= gSexyAppBase->mHeight - FONT_HUNGARR->GetHeight() * 2)
                                {
                                        drawDotDotDot = true;
                                        break;
                                }
                               
                                g->SetColor(Color(255, 255, 255));
                                s = mStats.mPlanetsEaten[i];
                                g->DrawString(s, third / 2 - FONT_HUNGARR->StringWidth(s) / 2, y);

                                g->SetColor(Color(128, 255, 0));
                                s = mStats.mPlanetsEaten[i+1];
                                g->DrawString(s, third + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);

                                g->SetColor(Color(255, 128, 0));
                                s = mStats.mPlanetsEaten[i+2];
                                g->DrawString(s, third*2 + (third / 2 - FONT_HUNGARR->StringWidth(s) / 2), y);
                               
                                y += FONT_HUNGARR->GetHeight();

                        }

                        if (drawDotDotDot)
                        {
                                g->SetColor(Color::White);
                                g->DrawString(_S("..."), 5, y);
                        }
                }

                g->SetColor(Color::White);
                s = _S("CLICK TO CONTINUE");
                g->DrawString(s, gSexyAppBase->mWidth / 2 - FONT_HUNGARR->StringWidth(s) / 2, gSexyAppBase->mHeight - 20);             
        }

        if (mState == LevelupEffect::CURTAIN_OUT)
        {
                // Draw a red curtain, whose alpha decreases as it withdrawls more.
                // This lets the stats display underneath the curtain while it moves.
                int alpha = mCurtainX > 255 ? 255 : mCurtainX;
                g->SetColor(Color(255, 0, 0, alpha));
                g->FillRect(0, 0, mCurtainX, gSexyAppBase->mHeight);
                g->FillRect(gSexyAppBase->mWidth - mCurtainX, 0, mCurtainX, gSexyAppBase->mHeight);
        }

        if ((mState == LevelupEffect::COVERING_STATS) || (mState == LevelupEffect::FADE_OUT_STATS))
        {
                // Both the states where we cover up the stats and fade them out are controlled here,
                // since they are functionally the same. Again, with the HSL we do the usual HSLToRGB
                // stuff. However, since the FADE_OUT_STATS state actually fades out the screen and
                // has an alpha value that decreases over time (mFadeOutAlpha), instead of always
                // setting the alpha to 255, we need to set the alpha to mFadeOutAlpha. To do this,
                // we AND with 0xFFFFFF instead of 0xFFFFFFFF. Then, we OR it with the alpha value
                // shifted left 24 bits. This then sticks the alpha value, which changes over time,
                // into our HSL color. As you may recall from previous demos, the actual color
                // structure is 32 bit, and looks like this in binary form:
                //      AAAA RRRR GGGG BBBB  Where A,R,G,B are alpha, red, green, blue.
                //
                // We draw the totally filled in regions separately, since they're easy.
                // The strips then are drawn differently depending on if they are moving up or down.
                // The left and right ones move oppositely.
                g->SetColor( (gSexyAppBase->HSLToRGB(mHue, 255, 128) & 0xFFFFFF) | (mFadeOutAlpha << 24) );
                g->FillRect(0, 0, mCoverWidth, gSexyAppBase->mHeight);
                g->FillRect(gSexyAppBase->mWidth - mCoverWidth, 0, mCoverWidth, gSexyAppBase->mHeight);

                if (mStripSizeChange > 0)
                {
                        g->FillRect(mCoverWidth, 0, STRIP_WIDTH, mStripHeight);
                        g->FillRect(gSexyAppBase->mWidth - mCoverWidth - STRIP_WIDTH,
                                                gSexyAppBase->mHeight - mStripHeight,
                                                STRIP_WIDTH,
                                                mStripHeight);
                }
                else
                {                      
                        g->FillRect(mCoverWidth, gSexyAppBase->mHeight - mStripHeight, STRIP_WIDTH, mStripHeight);
                        g->FillRect(gSexyAppBase->mWidth - mCoverWidth - STRIP_WIDTH, 0, STRIP_WIDTH, mStripHeight);
                }

        }
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void LevelupEffect::DoneViewingStats()
{
        // The user clicked to dismiss the stats screen. Cover it up
        // and begin the transition to the next level.
        mState = LevelupEffect::COVERING_STATS;
        mCoverWidth = 0;
        mStripSizeChange = 90;
        mStripHeight = 0;
        mFadeOutAlpha = 255;
        mStartNextLevel = false;
        gSexyAppBase->PlaySample(SOUND_LEVEL_UP3);
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
bool LevelupEffect::StartNextLevel()
{
        // See function header for a complete description
        if (mStartNextLevel)
        {
                mStartNextLevel = false;
                gSexyAppBase->PlaySample(SOUND_LEVEL_UP4);
                return true;
        }

        return false;
}