Logo Search packages:      
Sourcecode: zaz version File versions  Download package

gameloop.cpp

/*
 * Zaz
 * Copyright (C) Remigiusz Dybka 2009 <remigiusz.dybka@gmail.com>
 *
 Zaz is free software: you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
 Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Zaz is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along
 with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "gameloop.h"
#include "level.h"
#include "textureloader.h"
#include "lineeditor.h"
#ifdef WIN32
#include <shlobj.h>
#include <shlwapi.h>
#endif
#include <sstream>
#include <ctime>

GameLoop::GameLoop(Scenes::Settings *settings, SDL_Surface *surf, GLuint *gameTextures, uint startLevel, uint randomSeed)
        : Scene(settings, surf), score(0), lastscore(0), currentLevelName(startLevel), randomSeed((uint)time(0)), gameTextures(gameTextures),
        showMenu(false), gameOver(false), showPauseMenu(false), continueGame(false), showLifeLostMenu(false), pwned(false), hiScore(false), game(0),
        logoTexture(LoadTexture ("logo.png")),screenShotTexture(0), pwnedr(0), editor(settings->get("lastHighscoreName", ""), 60, 50, 16),
        livesLeft(nLives), livesLeftInReplay(nLives)
{
    // create level list
    bool found = true;
    int f = 1;

    while (found)
    {
        std::stringstream ss;
        ss << "level" << f << ".lvl";

        std::ifstream inph(settings->getCFilename(ss.str()));
        if (inph)
        {
            levelNames.push_back(settings->getCFilename(ss.str()));
            ++f;
        }
        else
        {
            found = false;
        }
    };

    pauseMenu.Add(new GenericMenuItem(_("End game"), pauseMenuEndGameHandler, this));
    pauseMenu.Add(new GenericMenuItem(_("Continue"), pauseMenuContinueHandler, this));

    pauseMenu.SetDimensions(30, 40, 40);

    nextLevelMenu.Add(new GenericMenuItem(_("Next level"), nextLevelMenuNextLevelHandler, this));
    nextLevelMenu.Add(new GenericMenuItem(_("End game"), pauseMenuEndGameHandler, this));
    nextLevelMenu.Add(new GenericMenuItem(_("View replay"), nextLevelMenuViewReplayHandler, this));
    nextLevelMenu.Add(new GenericMenuItem(_("Export video"), nextLevelMenuExportVideoHandler, this));

    nextLevelMenu.SetDimensions(30, 40, 40);

    gameOverMenu.Add(new GenericMenuItem(_("Back to main menu"), pauseMenuEndGameHandler, this));
    gameOverMenu.Add(new GenericMenuItem(_("Restart game"), gameOverMenuRestartHandler, this));
    gameOverMenu.Add(new GenericMenuItem(_("View replay"), nextLevelMenuViewReplayHandler, this));
    gameOverMenu.Add(new GenericMenuItem(_("Export video"), nextLevelMenuExportVideoHandler, this));

    gameOverMenu.SetDimensions(30, 40, 40);

    lifeLostMenu.Add(new GenericMenuItem(_("Retry level"), lifeLostMenuRetryLevelHandler, this));
    lifeLostMenu.Add(new GenericMenuItem(_("End game"), pauseMenuEndGameHandler, this));
    lifeLostMenu.Add(new GenericMenuItem(_("View replay"), nextLevelMenuViewReplayHandler, this));
    lifeLostMenu.Add(new GenericMenuItem(_("Export video"), nextLevelMenuExportVideoHandler, this));

    lifeLostMenu.SetDimensions(30, 40, 40);

    pwned = false;

#ifdef WIN32
    tempRecording << " "; // braindead !!!
#endif
}

void GameLoop::ClearGame()
{
    if (game)
    {
        delete game;
        delete level;

        game = 0;
    }
}

void gameOverMenuRestartHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->score = 0;
    p->currentLevelName = 0;
    p->gameOver = false;
};

void GameLoop::ViewReplay()
{
    stringstream rec;
    rec << recording;

    ClearGame();
    level = new Level(levelNames[currentLevelName].c_str());
    game = new Game(settings, surface, *level, gameTextures, randomSeed, livesLeftInReplay, lastscore);
    game->Play(rec);
    ClearGame();
}

void lifeLostMenuRetryLevelHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->showLifeLostMenu = false;
}

void GameLoop::NextLevel()
{
    currentLevelName++;
    showMenu = false;
}

void nextLevelMenuNextLevelHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->NextLevel();
}

void nextLevelMenuViewReplayHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->ViewReplay();
}

void GameLoop::ExportReplay()
{
    ClearGame();

    level = new Level(levelNames[currentLevelName].c_str());
    stringstream rec;
    rec << recording;
    game = new Game(settings, surface, *level, gameTextures, randomSeed, livesLeftInReplay, lastscore);

    time_t theTime;
    time( &theTime );
    tm *t = localtime( &theTime );
    char tempbuff[256];
    char datebuff[256];

    string exportpath = ".";

#ifdef WIN32
    TCHAR path[MAX_PATH];
    if (SUCCEEDED(SHGetFolderPath(NULL,
                                  CSIDL_PERSONAL,
                                  NULL,
                                  0,
                                  path)))
    {
        exportpath = path;
    }
#endif

    sprintf(datebuff, "%04d-%02d-%02d", 1900 + t->tm_year, t->tm_mon + 1, t->tm_mday);

    sprintf(tempbuff, "%s%szaz-%s.ogv", exportpath.c_str(), SEPARATOR, datebuff);
    bool ok = false;
    int f = 1;
    while (!ok)
    {
        ifstream inph(tempbuff);
        if (!inph)
        {
            ok = true;
        }
        else
        {
            sprintf(tempbuff, "%s%szaz-%s-%d.ogv", exportpath.c_str(), SEPARATOR, datebuff, f);
            ++f;
        }
    }

    string exportphname = tempbuff;

    game->Export(exportphname, rec, 4);
    ClearGame();
}

void nextLevelMenuExportVideoHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->ExportReplay();
}

void pauseMenuContinueHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->continueGame = true;
    p->showPauseMenu = false;
};

void pauseMenuEndGameHandler(void *ptr)
{
    GameLoop *p = (GameLoop*)ptr;
    p->quit = true;
};


GameLoop::~GameLoop()
{
    if (screenShotTexture)
        glDeleteTextures(1, &screenShotTexture);

    glDeleteTextures(1, &logoTexture);

}

void GameLoop::GLSetup()
{
    SDL_ShowCursor(SDL_ENABLE);
    SDL_WM_GrabInput(SDL_GRAB_OFF);

    int width = surface->w;
    int height = surface->h;

    //    float ratio = (float) width / (float) height;

    /* Our shading model--Gouraud (smooth). */
    glShadeModel( GL_SMOOTH );

    /* Culling. */
    glCullFace( GL_BACK );
    glFrontFace( GL_CCW );
    glEnable( GL_CULL_FACE );
    glEnable(GL_DEPTH_TEST);
    glEnable( GL_ALPHA_TEST );
    glAlphaFunc(GL_GREATER, 0.0);
    glEnable(GL_LINE_SMOOTH);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

    glClearColor( .1f, .1f, .7f, 1.0f );
    glViewport( 0, 0, width, height);
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );

    vwidth = 100 * (640.0/480.0);
    vleft = (100 - vwidth) / 2;
    vheight = 100.0;

    glOrtho(vleft, vwidth + vleft, 0, 100, -100, 100);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}

void GameLoop::Logic(ulong frame)
{
    if (!events.empty)
    {
        if (events.keyDown.size() > 0)
            for (vector<SDLKey>::iterator i = events.keyDown.begin(); i != events.keyDown.end(); ++i)
            {
                if (*i == SDLK_ESCAPE)
                {
                    if (!showPauseMenu && !hiScore)
                    {
                        quit = true;
                    }
                    else if (showPauseMenu)
                    {
                        continueGame = true;
                        showPauseMenu = false;
                    }

                    if (hiScore)
                    {
                        hiScore = false;
                    }
                }

                if (hiScore)
                    if (*i == SDLK_RETURN || *i == SDLK_KP_ENTER)
                    {
                        hiScores.SubmitHiScore(HiScoreEntry(score, editor.txt, level->name));
                        settings->set("lastHighscoreName", editor.txt);
                        hiScore = false;
                                    SDL_EnableUNICODE(SDL_DISABLE);
                    }
            }

        double mx = (vwidth * events.mouseX) + vleft;
        double my = vheight - (vheight * events.mouseY);
        bool click = false;

        if (events.buttDown[0])
            click = true;

        if (showLifeLostMenu)
            lifeLostMenu.Logic(mx, my, click);

        if (showPauseMenu)
            pauseMenu.Logic(mx, my, click);

        if (showMenu)
            nextLevelMenu.Logic(mx, my, click);

        if (gameOver)
            gameOverMenu.Logic(mx, my, click);
    }

    if (quit)
    {
        ClearGame();
        return;
    }

    if (hiScore)
    {
        editor.Logic(events);
    }

    if (!showLifeLostMenu && !showMenu && !gameOver && !showPauseMenu && !hiScore)
    {
        if (!continueGame)
        {
            ClearGame();
            level = new Level(levelNames[currentLevelName].c_str());
            randomSeed = (uint)time(0);
            tempRecording.clear();
            tempRecording.seekp(0);
            game = new Game(settings, surface, *level, gameTextures, randomSeed, livesLeft, score);
        }

        if (continueGame)
        {
            game->quit = false;
            game->escaped = false;
            game->Record(tempRecording, pausedFrame);
            continueGame = false;
            GenScreenShotTexture();
            GLSetup();
        }
        else
        {
            livesLeftInReplay = livesLeft;
            game->Record(tempRecording, 0);
            GenScreenShotTexture();
            GLSetup();
        }

        if (game->escaped)
        {
            showPauseMenu = true;
            pausedFrame = game->getLastLogicFrame();
        }
        else
        {
            if (!game->gameOver)
            { // finished level
                lastscore = score;
                score=game->score;
                livesLeft = game->lives;

                stringstream cfgs;
                cfgs << "level" << (currentLevelName + 1) << "_completed";

                settings->setb(cfgs.str(), true);

                if (currentLevelName < levelNames.size() - 1)
                {
                    showMenu = true;
                }
                else   // pwned the game !!!
                {
                    gameOver = true;
                    pwned = true;
                    if (hiScores.GoodEnough (score))
                              {
                        hiScore = true;
                                    SDL_EnableUNICODE(SDL_ENABLE);
                              }
                }
                GenScreenShotTexture();
                GLSetup();
                recording = tempRecording.str();
            }
            else
            { // lost a life
                lastscore = score;
                score=game->score;
                livesLeft = (int)game->lives;
                livesLeft--;

                if (livesLeft >= 0)
                {
                    showLifeLostMenu = true;
                    recording = tempRecording.str();
                    return;
                };

                gameOver = true;
                if (hiScores.GoodEnough (score))
                        {
                              SDL_EnableUNICODE(SDL_ENABLE);
                              hiScore = true;
                        }

                livesLeft = nLives;
                recording = tempRecording.str();
            }
        }
    }

    if (pwned)
        pwnedr+=0.01;
}

void GameLoop::CenterMsg(string msg, double y, FTFont *font)
{
    glLoadIdentity( );
    FTBBox b = font->BBox(msg.c_str());
    double tw = b.Upper().X() / 5;
    glTranslated((100 - tw) / 2, y, 5);
    glScaled(0.2, 0.2, 0.2);

    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    font->Render(msg.c_str());
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}


void GameLoop::Render(ulong frame)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    if (screenShotTexture != 0)
    {
        // render level background
        glPushMatrix();
        glTranslatef(0.0, 0.0, -5);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, screenShotTexture);
        glBegin(GL_QUADS);
        glTexCoord2d(0, 0);
        glVertex3d(vleft, 100, 0);
        glTexCoord2d(0, 1);
        glVertex3d(vleft, 0, 0);
        glTexCoord2d(1, 1);
        glVertex3d(vleft + vwidth, 0, 0);
        glTexCoord2d(1, 0);
        glVertex3d(vleft + vwidth, 100, 0);
        glEnd();
        glDisable(GL_TEXTURE_2D);
        glPopMatrix();
    }

    if (showLifeLostMenu)
    {
        lifeLostMenu.Render();
        glLoadIdentity( );
        glColor3d(1.0, 1.0, 1.0);

        char msgscore[256];
        sprintf(msgscore, _("Lives left: %d"), livesLeft);
        CenterMsg(msgscore, 50, font);

        sprintf(msgscore, _("Current score: %05d"), score);

        CenterMsg(msgscore, 45, font);
    }

    if (showPauseMenu)
    {
        pauseMenu.Render();
        string msg = _("Game paused");
        glColor3d(1.0, 0.0, 0.0);

        CenterMsg(msg, 45, font);
    }

    if (showMenu)
    {
        nextLevelMenu.Render();

        glLoadIdentity( );

        glColor3d(1.0, 1.0, 1.0);
        CenterMsg(_("Level cleared"), 50, font);

        char msgscore[256];
        sprintf(msgscore, _("Current score: %05d"), score);

        CenterMsg(msgscore, 45, font);
    }


    if (gameOver && !hiScore)
    {
        gameOverMenu.Render();

        glLoadIdentity( );
        string msg = _("Game Over");

        glColor3d(1.0, 0.0, 0.0);

        CenterMsg(msg, 50, font);
        char msgscore[256];
        sprintf(msgscore, _("Score: %05d"), score);
        glColor3d(1.0, 1.0, 1.0);
        CenterMsg(msgscore, 45, font);
    }

    if (pwned && !hiScore)
    {
        glColor3d(1.0, 1.0, 1.0);
        CenterMsg(_("Congratulations !!! You just pwned"), 90, font3);

        // logo
        glLoadIdentity();
        glPopMatrix();
        glEnable(GL_TEXTURE_2D);
        glTranslated(15 + 30 * cos(pwnedr), 90, 5);
        glBindTexture(GL_TEXTURE_2D, logoTexture);
        glScalef(70, 41, 5);
        glBegin(GL_QUADS);
        glTexCoord2d(0, 0);
        glVertex3d(0, 0, 0);
        glTexCoord2d(0, 1);
        glVertex3d(0, -1, 0);
        glTexCoord2d(1, 1);
        glVertex3d(1, -1, 0);
        glTexCoord2d(1, 0);
        glVertex3d(1, 0, 0);
        glEnd();
        glDisable(GL_TEXTURE_2D);
    }

    if (hiScore)
    {
        glColor3d(1.0, 1.0, 1.0);
        CenterMsg(_("You have a new hi score"), 65, font);
        CenterMsg(_("please enter your name"), 60, font);
        editor.Render();
    }
}

void GameLoop::GenScreenShotTexture()
{
    if (screenShotTexture)
    {
        glDeleteTextures(1, &screenShotTexture);
    }

    unsigned char *pixels;
    unsigned char *temp;

    glFlush();

    pixels = (unsigned char *)malloc(3 * surface->w * surface->h);
    temp = (unsigned char *)malloc(3 * screenShotTextureSize * screenShotTextureSize);

    glReadPixels(0, 0, surface->w, surface->h,
                 GL_RGB, GL_UNSIGNED_BYTE, pixels);

    double sx = (double)surface->w / (double)screenShotTextureSize;
    double sy = (double)surface->h / (double)screenShotTextureSize;

    for (uint y = 0; y < screenShotTextureSize; ++y)
        for (uint x = 0; x < screenShotTextureSize; ++x)
        {
            uint yy = (uint)iround(double(y) * sy);
            uint xx = (uint)iround(double(x) * sx);
            unsigned char *p = pixels + (((surface->h - 1) - yy) * 3 * surface->w) + (xx * 3);
            unsigned char *pt = temp + (y * 3 * screenShotTextureSize) + (x * 3);

            unsigned char r = p[0];
            unsigned char g = p[1];
            unsigned char b = p[2];

            int newcol = (((int)r + (int)g + (int)b) / 3) - 10;
            if (newcol < 0)
                newcol = 0;

            unsigned char nc = (unsigned char)newcol;

            pt[0] = 0;
            pt[1] = 0;
            pt[2] = nc;
        };

    glGenTextures( 1, &screenShotTexture);

    glBindTexture( GL_TEXTURE_2D, screenShotTexture);

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

    glTexImage2D( GL_TEXTURE_2D, 0, 3, screenShotTextureSize, screenShotTextureSize, 0,
                  GL_RGB, GL_UNSIGNED_BYTE, temp);

    free(pixels);
    free(temp);
}


Generated by  Doxygen 1.6.0   Back to index