diff --git a/asteroids/Model.cc b/asteroids/Model.cc index dbeddf4..0d5e76e 100644 --- a/asteroids/Model.cc +++ b/asteroids/Model.cc @@ -37,7 +37,6 @@ int Model::OnInit (int argc, char* argv[]) { /// \TODO use or similar for initialization of mCurrentLevelIndex mCurrentLevelIndex = 99999; - mLevelName = ""; if (InitLevelList() == 0) Engine::LogError ("No levels found!"); @@ -55,6 +54,8 @@ int Model::OnInit (int argc, char* argv[]) { mLevelAuthor = ""; mLevelTitle = ""; + mLevelName = ""; + mLevelParTimeSeconds = -1.f; // initialize SDL_net to be able to retrieve highscore from the internet if (SDLNet_Init() == -1) { @@ -104,6 +105,11 @@ bool Model::OnReceiveEvent (const Engine::EventBasePtr &event) { void Model::Process () { if (mLastGameState == mGameState) { if (mGameState == GameStateRunning) { + // Only if we are still controlling the ship we increase the level + // timer + if (Engine::GetPlayerEntityId() != Engine::NullEntityId) + mLevelTimeSeconds += Engine::GetFrameDuration(); + Engine::ModelBase::Process(); } return; @@ -496,6 +502,9 @@ int Model::DoLoadLevel (const char* filename) { int entity_count = 0; SetLevelTitle (""); SetLevelAuthor (""); + mLevelTimeSeconds = 0.f; + mLevelParTimeSeconds = -1.f; + mLevelPoints = 0; while (level_file >> entity_type_str) { if (entity_type_str[0] == '#') { @@ -516,8 +525,23 @@ int Model::DoLoadLevel (const char* filename) { level_author = strip_whitespaces (level_author); SetLevelAuthor (level_author); continue; + } else if (entity_type_str == "ParTime") { + std::string partime_string; + + getline (level_file, partime_string); + partime_string = strip_whitespaces (partime_string); + std::stringstream partime_stream (partime_string); + + float partime = -1.; + partime_stream >> partime; + + if (partime > 0.) + mLevelParTimeSeconds = partime; + + continue; } + GameEntityType entity_type = GameEntityTypeUnknown; if (entity_type_str == "GameEntityTypeShip") @@ -556,6 +580,11 @@ int Model::DoLoadLevel (const char* filename) { entity_count ++; } + if (mLevelParTimeSeconds == -1.f) { + Engine::LogWarning ("Level %s has no par time set. Setting to 120s.", filename); + mLevelParTimeSeconds = 120.f; + } + level_file.close(); Engine::LogDebug ("%d Entities loaded!", mEntities.size()); @@ -660,6 +689,7 @@ void Model::OnNewGame() { mPlayerLives = 3; mCurrentLevelIndex = 0; mPoints = 0; + mLevelPoints = 0; DoLoadLevel (mLevelList[mCurrentLevelIndex].c_str()); } @@ -697,8 +727,9 @@ void Model::OnKillEntity (const Engine::EntityBase *entity) { unsigned int i; const AsteroidEntity *asteroid = static_cast(entity); - if (GetPlayerEntityId() != Engine::NullEntityId) - mPoints += 150 + asteroid->mSubAsteroidsCount * 75; + if (GetPlayerEntityId() != Engine::NullEntityId) { + mLevelPoints += 150 + asteroid->mSubAsteroidsCount * 75; + } for (i = 0; i < mAsteroids.size(); i++) { if (mAsteroids.at(i) == entity->mId) { diff --git a/asteroids/Model.h b/asteroids/Model.h index 02ea4e6..7a06f6b 100644 --- a/asteroids/Model.h +++ b/asteroids/Model.h @@ -31,6 +31,7 @@ class Model : public Engine::ModelBase { int GetPlayerLives () { return mPlayerLives; }; void SetPlayerLives (int lives) { mPlayerLives = lives; }; unsigned int GetPoints () { return mPoints; }; + unsigned int GetLevelPoints () { return mLevelPoints; }; std::string GetPlayerName() { return mPlayerName; }; void SetPlayerName(const std::string &name) { Engine::LogDebug("new player name: %s", name.c_str()); @@ -55,6 +56,9 @@ class Model : public Engine::ModelBase { mLevelTitle = title; } + float GetLevelTimeSeconds() { return mLevelTimeSeconds; }; + float GetLevelParTimeSeconds() { return mLevelParTimeSeconds; }; + /* Highscore */ struct HighscoreEntry { HighscoreEntry(): name ("unknown"), points (0) { }; @@ -99,13 +103,17 @@ class Model : public Engine::ModelBase { int mPlayerLives; unsigned int mPoints; - unsigned int mCurrentLevelIndex; + unsigned int mCurrentLevelIndex; std::string mPlayerName; std::vector mLevelList; std::string mLevelName; std::string mLevelAuthor; std::string mLevelTitle; + unsigned int mLevelPoints; + float mLevelTimeSeconds; + // par time (= my run through, rounded down + 30 seconds + float mLevelParTimeSeconds; static Engine::Variable HighscoreServerName; static Engine::Variable HighscoreServerPath; diff --git a/asteroids/View.cc b/asteroids/View.cc index 3f08ea2..be49684 100644 --- a/asteroids/View.cc +++ b/asteroids/View.cc @@ -480,10 +480,10 @@ void View::DrawPageTitle (const std::string& title) { float xpos = (screen_right - width) * 0.5 - 40; float ypos = 180; - Engine::GUI::Label (4, title.c_str(), xpos - 2, ypos + 2); + DrawGLString (xpos - 2, ypos + 2, title.c_str()); SelectFont("console.ttf size=46 color=#ffffff"); - Engine::GUI::Label (4, title.c_str(), xpos, ypos); + DrawGLString (xpos, ypos, title.c_str()); } void View::DrawUiMainMenu() { @@ -726,11 +726,56 @@ void View::DrawUiLevelIntro() { } } +void split_time_seconds (float time_seconds, int *minutes, int *seconds) { + float current_time = roundf(time_seconds); + + *minutes = static_cast (floor (current_time / 60.f)); + *seconds = static_cast (current_time - *minutes * 60); +} + +std::string time_seconds_to_string (float time_seconds) { + stringstream time_stream; + int minutes, seconds; + split_time_seconds (time_seconds, &minutes, &seconds); + + time_stream << minutes << ":"; + if (seconds < 10) + time_stream << "0"; + time_stream << seconds; + + return time_stream.str(); +} + void View::DrawUiLevelComplete() { DrawPageTitle ("Level Complete!"); - SelectFont ("console.ttf size=23"); + SelectFont ("console.ttf size=23 color=#ffffff"); + stringstream temp_stream; + int minutes, seconds; + split_time_seconds (GetModel()->GetLevelTimeSeconds(), &minutes, &seconds); + + int level_time_xpos, level_time_ypos; + + temp_stream << "Your time: " << time_seconds_to_string (GetModel()->GetLevelTimeSeconds()); + + level_time_xpos = (screen_right - screen_left) * 0.5 - 120; + level_time_ypos = 250; + + Engine::GUI::Label (1, temp_stream.str().c_str(), + level_time_xpos, level_time_ypos + 3 + ); + + temp_stream.str(""); + temp_stream << "PAR time: " << time_seconds_to_string (GetModel()->GetLevelParTimeSeconds()); + + level_time_xpos = (screen_right - screen_left) * 0.5 - 120; + level_time_ypos += 32; + + Engine::GUI::Label (1, temp_stream.str().c_str(), + level_time_xpos, level_time_ypos + 3 + ); + if(Engine::GUI::Button (1, "Next level ...", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 60, button_width, button_height)) { PopViewState(); // we have to take care when we are testing the level to not proceed to diff --git a/engine/IMGUIControls.cc b/engine/IMGUIControls.cc index 6047d48..b2cdb30 100644 --- a/engine/IMGUIControls.cc +++ b/engine/IMGUIControls.cc @@ -128,6 +128,10 @@ void Label (int id, const char* caption, int x, int y) { assert (view); view->DrawGLStringMeasure(caption, &width, &height); + + SelectFont("console.ttf size=23 color=#808080"); + view->DrawGLString(x - 1 , y + height * 0.5 + 1, caption); + SelectFont("console.ttf size=23 color=#ffffff"); view->DrawGLString(x , y + height * 0.5, caption); } }