diff --git a/asteroids/Model.cc b/asteroids/Model.cc index b6a61e5..e5c619f 100644 --- a/asteroids/Model.cc +++ b/asteroids/Model.cc @@ -38,6 +38,33 @@ int Model::OnInit (int argc, char* argv[]) { /// \TODO use or similar for initialization of mCurrentLevelIndex mCurrentLevelIndex = 99999; + mGameModified = false; + mCurrentLevelModified = false; + + // populate the level hashes + mLevelHashes["level01_lets_get_started.map"] = "1165bac2b862118fb9c830e2f2f87c47782dded737954d81430f93adcadd3567"; + mLevelHashes["level02_sing_along.map"] = "206e1e8b60a75a97de2bd91f5422ccaade43463daf5d5d4df971f0c3d9ef3f28"; + mLevelHashes["level03_spacewalk.map"] = "e6c615af0b7ece9e9c826d2f431a0de080c199e2685b4f0772bb54e16894e9de"; + mLevelHashes["level04_spiessrutenlauf.map"] = "4ba5c830f38e2b07b7b899d744fc4cefbd40921904492dfb396f24897a9925c0"; + mLevelHashes["level05_WolleNew1_might_want.map"] = "7289454d67c74a8d5e1afe02996e786458655182355b19fe2cd1a51f4139d1da"; + mLevelHashes["level06_WolleNew3_watch_your.map"] = "e5e86667623b12a491a2395a9b361617ee961edf8d349b7419942f0dbf76b769"; + mLevelHashes["level07_circled.map"] = "98aa36bf2c8f6be8cd23c7c284d6ff413db992f09e5d5866e5a3aa393a93b367"; + mLevelHashes["level08_highway.map"] = "bf5e678750d3f4d47c7bfec5ae62d852db1f475146ef013040d1e67308708a66"; + mLevelHashes["level09_WolleNew4_wheres_the_brain.map"] = "f3f685f6eb6cc703a5eaa0177472717ea49dddc2099e2bd1865f551f94e8fdf4"; + mLevelHashes["level10_WolleWhatever_whatever.map"] = "2f97984e86bd0969909032fa44bcf883dd181fbe61782ee7dd704b0b63dfd0e1"; + mLevelHashes["level11_Strahlensatz.map"] = "3f293d4b0ea23688c15761a54b2ee097cc6a41b30750cc8fc5fccf94c20bf018"; + mLevelHashes["level12_your_in_my_way.map"] = "d82a4a85a70c3e9e05f771dde2d75597a2336f3165a544ca6dc378b6fd168cce"; + mLevelHashes["level13_WolleHarder1_tribute_to_lw.map"] = "1b52ccfb9f6211eb07d880cab6bf23b3ac05646561b555077bae14ad8f40c80c"; + mLevelHashes["level14_asteroid_field_lets_hide.map"] = "a9e2ddca00eef71a51f564f7d7cdd482e8a4d4fc7b70d4d2bf3d5f496188fce1"; + mLevelHashes["level15_WolleNew6_smack_my.map"] = "1d7e1223bbd8a68492108c2416c1a8ba828d293601c02e489dbf6b5db6a1aaa2"; + mLevelHashes["level16_Wolle7_todesspirale.map"] = "d82d8f6c21806238a7b6a87c1217a0dff42f4e59e73f28e7af3f0c8afd908e38"; + mLevelHashes["level17_WolleEasyNew1_twin_supernova.map"] = "4e177f82a0ba8f909ff1af1adf13caf82ab41cf09d69504c87f3e0551b9b73ed"; + mLevelHashes["level18_WolleNew2_dont_drink.map"] = "3b7b0fa59ee652e763ea43ffd7e572e1bd0436116fd5d5b13ed679fce362d265"; + mLevelHashes["level19_Geisterfahrer.map"] = "2036741d6fd4a863324210e53b903d7a898c4478e5eb9607a43a110bb6999ace"; + mLevelHashes["level20_billiard.map"] = "23dcffbf61bd887db7613b02d0c9ad04d77d800af631edbcf5822a169dcc2a9d"; + mLevelHashes["level21_final.map"] = "6384b1565c0c844d7083e744d6cfbaf9de42f5ad5ecb0cb668c3a2458860c8ac"; + mLevelHashes["level22_bonus.map"] = "a5c9455284fb2311687b5076693ab0df50c7766044561d79f4c46896842a6b44"; + if (InitLevelList() == 0) Engine::LogError ("No levels found!"); @@ -152,6 +179,15 @@ unsigned int Model::InitLevelList () { if (boost::filesystem::is_regular_file (dir_iter->status())) { std::string level_relative_path (level_dir_name); level_relative_path += dir_iter->path().filename(); + + // check whether we found an official level + std::string map_name (level_relative_path); + map_name = map_name.substr(map_name.rfind ('/') + 1, map_name.size()); + if (mLevelHashes.find(map_name) == mLevelHashes.end()) { + Engine::LogDebug ("Skipping unofficial level %s", std::string(level_relative_path).c_str()); + continue; + } + mLevelList.push_back (level_relative_path); Engine::LogDebug ("Found level %s", mLevelList[mLevelList.size()-1].c_str()); } @@ -518,7 +554,17 @@ void Model::SubmitHighscoreEntry (const std::string &name, const unsigned int po } int Model::DoLoadLevel (const char* filename) { - Engine::LogMessage ("Loading level from %s", filename); + // verify the hash of the map + std::string map_name (filename); + map_name = map_name.substr(map_name.rfind ('/') + 1, map_name.size()); + std::string map_hash = sha256_hash_file (filename); + if (map_hash != mLevelHashes[map_name]) { + Engine::LogMessage ("Map verification for file %s failed!", map_name.c_str()); + mGameModified = true; + mCurrentLevelModified = true; + } + Engine::LogDebug ("Verification for level %s OK: loading level."); + std::fstream level_file (filename, std::ios::in); if (!level_file) { @@ -779,6 +825,9 @@ void Model::OnLevelComplete() { mLevelPoints += mLevelTimeBonusPoints; mPoints += mLevelPoints; + + if (mGameModified) + mPoints = 0; } void Model::OnCreateEntity (const int type, const unsigned int id) { diff --git a/asteroids/Model.h b/asteroids/Model.h index 358f334..f95cda7 100644 --- a/asteroids/Model.h +++ b/asteroids/Model.h @@ -88,6 +88,7 @@ class Model : public Engine::ModelBase { return mCurrentLevelIndex; } + bool GetGameModified() { return mGameModified; } protected: /** \brief Initializes the system */ virtual int OnInit (int argc, char* argv[]); @@ -102,10 +103,13 @@ class Model : public Engine::ModelBase { /** \brief Keeps a list of all asteroids */ std::vector mAsteroids; + std::map mLevelHashes; + bool mGameModified; + bool mCurrentLevelModified; int mPlayerLives; unsigned int mPoints; - unsigned int mCurrentLevelIndex; + unsigned int mCurrentLevelIndex; std::string mPlayerName; std::vector mLevelList; diff --git a/asteroids/View.cc b/asteroids/View.cc index 7903283..7247512 100644 --- a/asteroids/View.cc +++ b/asteroids/View.cc @@ -780,6 +780,20 @@ std::string time_seconds_to_string (float time_seconds) { void View::DrawUiLevelComplete() { DrawPageTitle ("Level Complete!"); + if (GetModel()->GetGameModified()) { + SelectFont("console.ttf size=23 color=#cc0000"); + float width, height; + std::string message ("* UNOFFICIAL GAME * UNOFFICIAL GAME * UNOFFICIAL GAME *"); + + float xpos = (screen_left) + 5; + float ypos = 20; + + DrawGLString (xpos, ypos, message.c_str()); + + ypos = screen_bottom - 4; + DrawGLString (xpos, ypos, message.c_str()); + } + SelectFont ("console.ttf size=23 color=#ffffff"); stringstream temp_stream; @@ -1094,19 +1108,24 @@ void View::DrawUiCredits() { SelectFont ("console.ttf size=23"); static std::string credits_content ( -"_Programming,\r\ -_ Design, and Graphics\r\ +"_Programming, Design,\r\ +_ Sounds, and Graphics\r\ Martin Felis\r\ \r\ -_Level Design\r\ +_Top Level Designer\r\ + Sir Wolle\r\ + \r\ + \r\ +_Additional Level Design\r\ Martin Felis\r\ + michi\r\ + Khai-Long Ho Hoang\r\ + Andi\r\ + Sebastian Felis\r\ \r\ _Music\r\ DJad - Space Exploration\r\ \r\ -_Sounds\r\ - Martin Felis\r\ -\r\ _Libraries\r\ libSDL\r\ SDL_mixer\r\ @@ -1145,14 +1164,9 @@ _http://www.fysx.org\r\ \r\ EOF\r\ "); - static float page_duration = 4.; + static float page_duration = 5.; static float page_draw_duration = page_duration; - if (page_draw_duration < 0.) { - mCreditsPageIndex ++; - page_draw_duration = page_duration; - } - stringstream credits_stream (credits_content); std::string line; @@ -1194,6 +1208,17 @@ EOF\r\ } } + if (page_draw_duration < 0.) { + mCreditsPageIndex ++; + + page_draw_duration = page_duration; + + // Level contributors are shown a bit longer + if (mCreditsPageIndex == 1) { + page_draw_duration *= 1.5; + } + } + page_draw_duration -= Engine::GetFrameDuration(); if (Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) diff --git a/asteroids/main.cc b/asteroids/main.cc index b9ba6c8..a48de5d 100644 --- a/asteroids/main.cc +++ b/asteroids/main.cc @@ -150,7 +150,7 @@ int main (int argc, char* argv[]) { else SDL_WM_SetIcon(image,NULL); - SDL_WM_SetCaption("fysxasteroids -BETA 2-","fysxasteroids -BETA 2-"); + SDL_WM_SetCaption("fysxasteroids -RC 1-","fysxasteroids -RC 1-"); engine.GetView()->SetGridSize (8,8); diff --git a/engine/Utils.cc b/engine/Utils.cc index 4f8bf09..b995d53 100644 --- a/engine/Utils.cc +++ b/engine/Utils.cc @@ -53,3 +53,45 @@ std::string sha256_hash (std::string input) { return std::string (result_buf, 64); } + +std::string sha256_hash_file (const char *filename) { + // we simply read the whole file into a string and hash this + std::ifstream file_stream (filename, std::ios_base::binary); + if (!file_stream.is_open()) { + std::cerr << "Could not hash file " << filename << ": could not open file." << std::endl; + return ""; + } + + + file_stream.seekg (0,std::ios_base::end); + std::streampos file_end = file_stream.tellg(); + + int file_size = static_cast (file_end); + if (file_size == 0) { + std::cerr << "Could not hash file " << filename << ": file has no content!" << std::endl; + return ""; + } + + unsigned char *file_buffer = NULL; + file_buffer = new unsigned char[file_size]; + + file_stream.seekg(0, std::ios_base::beg); + file_stream.read ((char*)file_buffer, file_size); + + char result_buf[64]; + + SHA256_CTX ctx256; + + SHA256_Init(&ctx256); + SHA256_Update(&ctx256, file_buffer, file_size); + SHA256_End (&ctx256, result_buf); + + file_stream.close(); + + delete[] file_buffer; + +// std::cerr << "file hash is " << std::string (result_buf, 64) << std::endl; + + return std::string (result_buf, 64); +} + diff --git a/engine/Utils.h b/engine/Utils.h index 365ff1d..bbaea6d 100644 --- a/engine/Utils.h +++ b/engine/Utils.h @@ -6,5 +6,6 @@ std::string strip_whitespaces (const std::string input_str); bool create_dir (const std::string &dir_str); std::string sha256_hash (std::string input); +std::string sha256_hash_file (const char *filename); #endif /* _UTILS_H */