diff --git a/.gitignore b/.gitignore index 231c609..f3ca6de 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ nbproject !.dockerignore *.patch Game/blockattack* +Game/mods/1.3.0.bricks.data cmake_install.cmake CMake* -CMakeLists.txt diff --git a/Game/mods/1.3.0.bricks_unpacked.data/modinfo/1.3.0.bricks.json b/Game/mods/1.3.0.bricks_unpacked.data/modinfo/1.3.0.bricks.json new file mode 100644 index 0000000..7045190 --- /dev/null +++ b/Game/mods/1.3.0.bricks_unpacked.data/modinfo/1.3.0.bricks.json @@ -0,0 +1,5 @@ +{ + "name" : "1.3.0.bricks", + "description" : "Uses the bricks from version 1.3.0", + "sprites" : "bricks1.3.0" +} diff --git a/Game/mods/1.3.0.bricks_unpacked.data/sprites/bricks1.3.0.sprite b/Game/mods/1.3.0.bricks_unpacked.data/sprites/bricks1.3.0.sprite new file mode 100644 index 0000000..23d5c16 --- /dev/null +++ b/Game/mods/1.3.0.bricks_unpacked.data/sprites/bricks1.3.0.sprite @@ -0,0 +1,73 @@ +{ + + "block_blue" : { + "texture" : "bricks130", + "topx" : 0, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + }, + + "block_green" : { + "texture" : "bricks130", + "topx" : 50, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + }, + + "block_gray" : { + "texture" : "bricks130", + "topx" : 100, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + }, + + "block_purple" : { + "texture" : "bricks130", + "topx" : 150, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + }, + + "block_red" : { + "texture" : "bricks130", + "topx" : 200, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + }, + + "block_turkish" : { + "texture" : "bricks130", + "topx" : 250, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + }, + + "block_yellow" : { + "texture" : "bricks130", + "topx" : 300, + "topy" : 0, + "height" : 50, + "width" : 50, + "number_of_frames" : 1, + "frame_time" : 1 + } + +} diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_blue.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_blue.png new file mode 100755 index 0000000..22e30f8 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_blue.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_gray.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_gray.png new file mode 100755 index 0000000..89d2ca6 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_gray.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_green.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_green.png new file mode 100755 index 0000000..b5dba0c Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_green.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_purple.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_purple.png new file mode 100755 index 0000000..7b4d0b1 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_purple.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_red.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_red.png new file mode 100755 index 0000000..2729ff6 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_red.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_turkish.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_turkish.png new file mode 100755 index 0000000..fd56426 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_turkish.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_yellow.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_yellow.png new file mode 100755 index 0000000..6fdaf69 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/ball_yellow.png differ diff --git a/Game/mods/1.3.0.bricks_unpacked.data/textures/bricks130.png b/Game/mods/1.3.0.bricks_unpacked.data/textures/bricks130.png new file mode 100644 index 0000000..6e252c9 Binary files /dev/null and b/Game/mods/1.3.0.bricks_unpacked.data/textures/bricks130.png differ diff --git a/packdata.sh b/packdata.sh index 2212130..f71c41f 100755 --- a/packdata.sh +++ b/packdata.sh @@ -1,11 +1,17 @@ #!/bin/bash set -e zip -9jX Game/blockattack.data source/AUTH -cd Game/data +pushd Game/data zip -9X $(find ../blockattack.data * | sort) -x \*svn* -cd ../../man +popd +pushd Game/mods/1.3.0.bricks_unpacked.data/ +zip -9X ../1.3.0.bricks.data $(find ./* | sort) +popd +pushd man gzip -9n -c blockattack.man > blockattack.6.gz -cd ../source/misc/translation/ +popd +pushd source/misc/translation/ ./build_mo_all.sh +popd exit 0 diff --git a/source/code/ModConfigMenuState.cpp b/source/code/ModConfigMenuState.cpp new file mode 100644 index 0000000..0845360 --- /dev/null +++ b/source/code/ModConfigMenuState.cpp @@ -0,0 +1,124 @@ +/* +=========================================================================== +blockattack - Block Attack - Rise of the Blocks +Copyright (C) 2005-2020 Poul Sander + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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/ + +Source information and contacts persons can be found at +https://blockattack.net +=========================================================================== +*/ + +#include "ModConfigMenuState.hpp" +#include "MenuSystem.h" +#include "global.hpp" +#include "MenuSystem.h" +#include "sago/SagoMisc.hpp" +#include "os.hpp" +#include + +const int buttonOffset = 160; +extern sago::SagoSprite bExit; + +bool sort_mods_enabled_order (const Mod& i,const Mod& j) { + if (i.enabled && !j.enabled) { + //Enabled mods always goes before disabled ones + return true; + } + if (i.enabled) { + return i.order < j.order; + } + return i.name < j.name; +} + +static void initMods(std::vector& mod_list) { + for (size_t i=0; i < globalData.modList.size(); ++i) { + for (Mod& m : mod_list) { + if (m.name == globalData.modList[i]) { + m.order = i; + m.enabled = true; + } + } + } + std::sort(mod_list.begin(), mod_list.end(), sort_mods_enabled_order); +} + +static void appendMods(const std::vector& mod_files, const std::string& dir, std::vector& mods_available) { + for (const std::string& mod : mod_files) { + if (!boost::ends_with(mod, ".data")) { + continue; + } + Mod m; + m.name = mod.substr(0, mod.length()-5); + m.filename = dir + "/" + mod; + mods_available.push_back(m); + } +} + + +ModConfigMenuState::ModConfigMenuState() { + mods_available.clear(); + std::string baseMods = std::string(PHYSFS_getBaseDir())+ "/mods"; + std::vector baseModFiles = OsGetDirFileList(baseMods); + appendMods(baseModFiles, baseMods, mods_available); + std::string userMods = getPathToSaveFiles()+"/mods"; + std::vector userModFiles = OsGetDirFileList(userMods); + appendMods(userModFiles, userMods, mods_available); + initMods(mods_available); +} + +ModConfigMenuState::~ModConfigMenuState() {} + +bool ModConfigMenuState::IsActive() { + return isActive; +} + +void ModConfigMenuState::Draw(SDL_Renderer* target) { + DrawBackground(target); + standardButton.getLabel(_("Mod config"))->Draw(target, 50, 50); + for (size_t i = 0; i < mods_available.size(); ++i) { + standardButton.getLabel(mods_available[i].name)->Draw(target, 60, 160+30*i); + standardButton.getLabel(mods_available[i].enabled ? _("Yes") : _("No"))->Draw(target, 600, 160+30*i); + if (mods_available[i].enabled) { + standardButton.getLabel(std::to_string(mods_available[i].order))->Draw(target, 700, 160+30*i); + } + } + bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffset, globalData.ysize-buttonOffset); +} + +void ModConfigMenuState::ProcessInput(const SDL_Event& event, bool& processed) { + if (isEscapeEvent(event)) { + isActive = false; + processed = true; + } +} + +void ModConfigMenuState::Update() { + // If the mouse button is released, make bMouseUp equal true + if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) { + bMouseUp=true; + } + + if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) { + bMouseUp = false; + + //The Score button: + if ((globalData.mousex>globalData.xsize-buttonOffset) && (globalData.mousexglobalData.ysize-buttonOffset) && (globalData.mousey mods_available; +}; + +#endif /* MODCONFIG_HPP */ diff --git a/source/code/ModInfo.cpp b/source/code/ModInfo.cpp new file mode 100644 index 0000000..da0b3f1 --- /dev/null +++ b/source/code/ModInfo.cpp @@ -0,0 +1,60 @@ +/* +=========================================================================== +blockattack - Block Attack - Rise of the Blocks +Copyright (C) 2005-2020 Poul Sander + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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/ + +Source information and contacts persons can be found at +http://blockattack.net +=========================================================================== +*/ + +#include "ModInfo.hpp" +#include "sago/SagoMisc.hpp" +#include "rapidjson/document.h" +#include +#include + +void ModInfo::InitModList(const std::vector& modlist) { + this->mod_list = modlist; + sprite_filename_list.clear(); + for (const std::string& s : mod_list) { + std::string filename_info = std::string("modinfo/") + s + ".json"; + if (sago::FileExists(filename_info.c_str())) { + std::string content = sago::GetFileContent(filename_info.c_str()); + rapidjson::Document document; + document.Parse(content.c_str()); + if ( !document.IsObject() ) { + std::cerr << "Failed to parse: " << filename_info << "\n"; + continue; + } + const auto& t = document.GetObject().FindMember("sprites"); + if (t != document.MemberEnd() && t->value.IsString()) { + std::string sprites = t->value.GetString(); + std::vector sprites_vector; + boost::split(sprites_vector, sprites, boost::is_any_of(",")); + sprite_filename_list.insert(sprite_filename_list.end(), sprites_vector.begin(), sprites_vector.end()); + } + } + } +} + +const std::vector& ModInfo::getModList() { + return this->mod_list; +} + +const std::vector& ModInfo::getModSpriteFiles() { + return this->sprite_filename_list; +} diff --git a/source/code/ModInfo.hpp b/source/code/ModInfo.hpp new file mode 100644 index 0000000..0a94001 --- /dev/null +++ b/source/code/ModInfo.hpp @@ -0,0 +1,42 @@ +/* +=========================================================================== +blockattack - Block Attack - Rise of the Blocks +Copyright (C) 2005-2020 Poul Sander + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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/ + +Source information and contacts persons can be found at +http://blockattack.net +=========================================================================== +*/ + + +#ifndef MODINFO_HPP +#define MODINFO_HPP + +#include +#include + +class ModInfo { +public: + ModInfo() = default; + void InitModList(const std::vector& modlist); + const std::vector& getModList(); + const std::vector& getModSpriteFiles(); +private: + std::vector mod_list; + std::vector sprite_filename_list; +}; + +#endif \ No newline at end of file diff --git a/source/code/global.hpp b/source/code/global.hpp index 351cbfb..9a583ae 100644 --- a/source/code/global.hpp +++ b/source/code/global.hpp @@ -31,6 +31,7 @@ http://www.blockattack.net #include "TextManager.hpp" #include "ExplosionManager.hpp" #include "sago/SagoTextField.hpp" +#include "ModInfo.hpp" void MainMenu(); void SafeModeMenu(); @@ -75,6 +76,8 @@ struct GlobalData { bool alwaysSixteenNine = false; int verboseLevel = 0; std::unique_ptr spriteHolder; + std::vector modList; + ModInfo modinfo; TextManager theTextManager; diff --git a/source/code/main.cpp b/source/code/main.cpp index 83dc0ba..caf8c18 100644 --- a/source/code/main.cpp +++ b/source/code/main.cpp @@ -64,6 +64,8 @@ https://blockattack.net #define PACKAGE "blockattack_roftb" #endif +#define MODLIST_TXT "modList.txt" + #include "highscore.h" //Stores highscores #include "ReadKeyboard.h" //Reads text from keyboard #include "stats.h" //Saves general stats @@ -71,6 +73,7 @@ https://blockattack.net #include "common.h" #include "gamecontroller.h" +#include #include #include #include "levelselect.hpp" @@ -90,6 +93,15 @@ static void FsSearchParthMainAppend(std::vector& paths) { paths.push_back((std::string)PHYSFS_getBaseDir()+"/data"); } +static void FsSearchPathModAppend(std::vector& paths, const std::vector& modlist) { + for (const std::string& mod : modlist) { + std::string filename = std::string(SHAREDIR)+"/mods/"+mod+".data"; + paths.push_back(filename); + filename = std::string(PHYSFS_getBaseDir())+"/mods/"+mod+".data"; + paths.push_back(filename); + } +} + static void PhysFsSetSearchPath(const std::vector& paths, const std::string& savepath) { for (const std::string& path : paths) { PHYSFS_mount(path.c_str(), "/", 0); @@ -264,6 +276,7 @@ void ResetFullscreen() { SDL_RenderSetLogicalSize(globalData.screen, globalData.xsize, globalData.ysize); dataHolder.invalidateAll(globalData.screen); globalData.spriteHolder.reset(new sago::SagoSpriteHolder( dataHolder ) ); + globalData.spriteHolder->ReadSprites(globalData.modinfo.getModSpriteFiles()); InitImages(*(globalData.spriteHolder.get()) ); SDL_ShowCursor(SDL_DISABLE); } @@ -866,6 +879,7 @@ static void ParseArguments(int argc, char* argv[], globalConfig& conf) { "Default: \"%s\"", LOCALEDIR).c_str()) ("homepath", boost::program_options::value(), SPrintStringF("Set the home folder where settings are saved. The directory will be created if it does not exist." " Default: \"%s\"", getPathToSaveFiles().c_str()).c_str()) + ("mod,m", boost::program_options::value >(), "Loads a mod. Later mods have preference") ; boost::program_options::variables_map vm; @@ -957,9 +971,17 @@ static void ParseArguments(int argc, char* argv[], globalConfig& conf) { if (vm.count("play-replay")) { globalData.replayArgument = vm["play-replay"].as(); } + if (vm.count("mod")) { + globalData.modList = vm["mod"].as >(); + } } +//Physfs 2.0.z does not have PHYSFS_unmount +#if (PHYSFS_VER_MAJOR <= 2) && (PHYSFS_VER_MINOR < 1) +#define PHYSFS_unmount PHYSFS_removeFromSearchPath +#endif + //Warning: the arguments to main must be "int argc, char* argv[]" NO CONST! or SDL_main will fail to find it int main(int argc, char* argv[]) { try { @@ -979,6 +1001,16 @@ int main(int argc, char* argv[]) { ParseArguments(argc, argv, config); OsCreateSaveFolder(); PhysFsSetSearchPath(config.search_paths, config.savepath); + if (globalData.modList.empty() && sago::FileExists(MODLIST_TXT)) { + std::string modString = sago::GetFileContent(MODLIST_TXT); + boost::split(globalData.modList, modString, boost::is_any_of(",")); + } + if (globalData.modList.size()>0) { + PHYSFS_unmount(config.savepath.c_str()); + FsSearchPathModAppend(config.search_paths, globalData.modList); + globalData.modinfo.InitModList(globalData.modList); + PhysFsSetSearchPath(config.search_paths, config.savepath); + } //Os create folders must be after the parameters because they can change the home folder PhysFsCreateFolders(); bool gameShutdownProperly = true; @@ -1245,11 +1277,19 @@ int main(int argc, char* argv[]) { std::cout << SPrintStringF("Block Attack - Rise of the Blocks ran for: %i hours %i mins and %i secs", ct.hours, ct.minutes, ct.seconds) << "\n"; } + std::string modListString; + if (globalData.modList.size()>0) { + modListString = globalData.modList.at(0); + for (size_t i = 1; i < globalData.modList.size(); ++i) { + modListString += std::string(",")+globalData.modList[i]; + } + } ct = TimeHandler::addTime("totalTime",ct); if (globalData.verboseLevel) { std::cout << "Total run time is now: " << ct.days << " days " << ct.hours << " hours " << ct.minutes << " mins and " << ct.seconds << " secs" << "\n"; + std::cout << "Mods loaded: " << modListString << "\n"; } - + sago::WriteFileContent(MODLIST_TXT, modListString); Stats::getInstance()->save(); Config::getInstance()->save(); } diff --git a/source/code/menudef.cpp b/source/code/menudef.cpp index 293ab75..04a61f2 100644 --- a/source/code/menudef.cpp +++ b/source/code/menudef.cpp @@ -29,6 +29,7 @@ http://blockattack.net #include "HelpGamepadState.hpp" #include "HelpAboutState.hpp" #include "ShowFileState.hpp" +#include "ModConfigMenuState.hpp" #if 0 @@ -293,34 +294,52 @@ static void ChangeKeysMenu2() { ChangeKeysMenu(2); } +static void PlayerConfigMenu() { + Menu pcm(globalData.screen,_("Player configuration"),true); + Button bPlayer1Name, bPlayer2Name; + Button bPlayer1Keys, bPlayer2Keys; + bPlayer1Name.setAction(buttonActionPlayer1Name); + bPlayer1Name.setLabel(_("Change player 1's name") ); + bPlayer2Name.setAction(buttonActionPlayer2Name); + bPlayer2Name.setLabel(_("Change player 2's name") ); + bPlayer1Keys.setAction(ChangeKeysMenu1); + bPlayer1Keys.setLabel(_("Change player 1's keys") ); + bPlayer2Keys.setAction(ChangeKeysMenu2); + bPlayer2Keys.setLabel(_("Change player 2's keys") ); + pcm.addButton(&bPlayer1Name); + pcm.addButton(&bPlayer2Name); + pcm.addButton(&bPlayer1Keys); + pcm.addButton(&bPlayer2Keys); + RunGameState(pcm); +} + +static void runModConfigMenu() { + ModConfigMenuState modmenu; + RunGameState(modmenu); +} + static void ConfigureMenu() { Menu cm(globalData.screen,_("Configuration"),true); - Button bPlayer1Name,bPlayer2Name; - Button bPlayer1Keys, bPlayer2Keys; AlwaysSoftwareRenderButton bSoftware; MusicButton bMusic; SoundButton bSound; FullscreenButton buttonFullscreen; + Button bPlayerConfig; + Button bModConfig; + bPlayerConfig.setLabel(_("Player configuration") ); + bPlayerConfig.setAction(PlayerConfigMenu); + bModConfig.setLabel(_("Configure mods")); + bModConfig.setAction(&runModConfigMenu); SetAlwaysSoftwareLabel(&bSoftware); SetMusicLabel(&bMusic); SetSoundLabel(&bSound); SetFullscreenLabel(&buttonFullscreen); - bPlayer1Name.setAction(buttonActionPlayer1Name); - bPlayer1Name.setLabel(_("Change player 1's name") ); - bPlayer2Name.setAction(buttonActionPlayer2Name); - bPlayer2Name.setLabel(_("Change player 2's name") ); - bPlayer1Keys.setAction(ChangeKeysMenu1); - bPlayer1Keys.setLabel(_("Change player 1's keys") ); - bPlayer2Keys.setAction(ChangeKeysMenu2); - bPlayer2Keys.setLabel(_("Change player 2's keys") ); cm.addButton(&bMusic); cm.addButton(&bSound); cm.addButton(&bSoftware); cm.addButton(&buttonFullscreen); - cm.addButton(&bPlayer1Name); - cm.addButton(&bPlayer2Name); - cm.addButton(&bPlayer1Keys); - cm.addButton(&bPlayer2Keys); + cm.addButton(&bPlayerConfig); + cm.addButton(&bModConfig); RunGameState(cm); } diff --git a/source/code/os.cpp b/source/code/os.cpp index 626c968..d821fb6 100644 --- a/source/code/os.cpp +++ b/source/code/os.cpp @@ -33,6 +33,8 @@ https://blockattack.net #include #endif +#include + static sago::PlatformFolders pf; static std::string overrideSavePath = ""; @@ -132,3 +134,23 @@ void OsCreateSaveFolder() { std::string path = getPathToSaveFiles(); OsCreateFolder(path); } + +std::vector OsGetDirFileList(const std::string& path) { + //At the moment dirent.h is used for all OS. Should have a Unicode version on Windows. + std::vector ret; + DIR* dir = opendir(path.c_str()); + struct dirent* ent; + if (dir) { + while ((ent = readdir (dir)) ) { + if (ent->d_name[0] == '.') { + continue; + } + ret.push_back(ent->d_name); + } + closedir (dir); + } + else { + std::cerr << "Failed to list: " << path+"/" << "\n"; + } + return ret; +} diff --git a/source/code/os.hpp b/source/code/os.hpp index 42627bf..d0f60df 100644 --- a/source/code/os.hpp +++ b/source/code/os.hpp @@ -29,11 +29,9 @@ https://blockattack.net #include "shlobj.h" #endif #include +#include std::string getPathToSaveFiles(); -#if defined(_WIN32) -std::string getMyDocumentsPath(); -#endif std::string defaultPlayerName(); @@ -43,6 +41,21 @@ void OsCreateSaveFolder(); bool OsPathIsRelative(const std::string& path); +/** + * Create a folder + * The folder path is created recursively + * Fails silently if failing to create the path + * @param path The folder to create + */ void OsCreateFolder(const std::string& path); +/** + * Lists the content of a directory. + * Ignores files starting with a dot (".") + * + * @param path The path to list + * @return std::vector Files names in directory + */ +std::vector OsGetDirFileList(const std::string& path); + #endif /* OS_HPP */ diff --git a/source/code/sago/SagoDataHolder.hpp b/source/code/sago/SagoDataHolder.hpp index 0abace8..9fbd9cd 100644 --- a/source/code/sago/SagoDataHolder.hpp +++ b/source/code/sago/SagoDataHolder.hpp @@ -117,7 +117,7 @@ public: * @return A globally unique number. */ Uint64 getVersion() const; - + ~SagoDataHolder(); private: SagoDataHolder(const SagoDataHolder& base) = delete; diff --git a/source/code/sago/SagoSpriteHolder.cpp b/source/code/sago/SagoSpriteHolder.cpp index 1e30d63..94c4c1c 100644 --- a/source/code/sago/SagoSpriteHolder.cpp +++ b/source/code/sago/SagoSpriteHolder.cpp @@ -131,6 +131,13 @@ void SagoSpriteHolder::ReadSprites() { } } +void SagoSpriteHolder::ReadSprites(const std::vector& extra_sprites) { + for (std::string item : extra_sprites) { + item+=".sprite"; + ReadSpriteFile(item); + } +} + const sago::SagoSprite& SagoSpriteHolder::GetSprite(const std::string& spritename) const { std::unordered_map>::const_iterator got = data->sprites.find (spritename); if ( got == data->sprites.end() ) { diff --git a/source/code/sago/SagoSpriteHolder.hpp b/source/code/sago/SagoSpriteHolder.hpp index 21b093e..be76b51 100644 --- a/source/code/sago/SagoSpriteHolder.hpp +++ b/source/code/sago/SagoSpriteHolder.hpp @@ -27,6 +27,7 @@ SOFTWARE. #include "SagoDataHolder.hpp" #include "SagoSprite.hpp" +#include namespace sago { @@ -34,7 +35,14 @@ class SagoSpriteHolder final { public: explicit SagoSpriteHolder(const SagoDataHolder &texHolder); ~SagoSpriteHolder(); + /** + * Reads all the sprites from the "sprites" directory in alphabetical order + **/ void ReadSprites(); + /** + * Reads an additional sprites. Used to append mod data. + **/ + void ReadSprites(const std::vector& extra_sprites); const sago::SagoSprite& GetSprite(const std::string &spritename) const; const SagoDataHolder& GetDataHolder() const; private: diff --git a/source/misc/translation/po/da.po b/source/misc/translation/po/da.po index 204dbca..2dda38c 100644 --- a/source/misc/translation/po/da.po +++ b/source/misc/translation/po/da.po @@ -7,15 +7,15 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-27 14:06+0200\n" -"PO-Revision-Date: 2020-06-27 14:08+0200\n" +"POT-Creation-Date: 2020-12-27 11:03+0100\n" +"PO-Revision-Date: 2020-12-27 11:04+0100\n" "Last-Translator: Poul Sander \n" "Language-Team: \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.6\n" +"X-Generator: Poedit 2.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../../code/DialogBox.cpp:94 @@ -26,90 +26,90 @@ msgstr "Bekræft med Enter" msgid "Esc to cancel" msgstr "Annuller med Esc" -#: ../../code/HelpAboutState.cpp:68 +#: ../../code/HelpAboutState.cpp:62 msgid "No audio driver" msgstr "Ingen lyd driver" -#: ../../code/HelpAboutState.cpp:71 +#: ../../code/HelpAboutState.cpp:65 msgid "Name:" msgstr "Navn:" -#: ../../code/HelpAboutState.cpp:71 ../../code/main.cpp:329 +#: ../../code/HelpAboutState.cpp:65 ../../code/main.cpp:336 msgid "Block Attack - Rise of the Blocks" msgstr "Block Attack - Blokkenes opstand" -#: ../../code/HelpAboutState.cpp:72 +#: ../../code/HelpAboutState.cpp:66 msgid "Original name:" msgstr "Originalt navn:" -#: ../../code/HelpAboutState.cpp:73 +#: ../../code/HelpAboutState.cpp:67 msgid "Version:" msgstr "Version:" -#: ../../code/HelpAboutState.cpp:74 +#: ../../code/HelpAboutState.cpp:68 msgid "Homepage:" msgstr "Hjemmeside:" -#: ../../code/HelpAboutState.cpp:75 +#: ../../code/HelpAboutState.cpp:69 msgid "Github page:" msgstr "Github side:" -#: ../../code/HelpAboutState.cpp:76 +#: ../../code/HelpAboutState.cpp:70 msgid "SDL render:" msgstr "SDL render:" -#: ../../code/HelpAboutState.cpp:77 +#: ../../code/HelpAboutState.cpp:71 msgid "SDL audio driver:" msgstr "SDL lyd driver:" -#: ../../code/HelpAboutState.cpp:78 +#: ../../code/HelpAboutState.cpp:72 msgid "SDL compiled version:" msgstr "SDL kompileret version:" -#: ../../code/HelpAboutState.cpp:79 +#: ../../code/HelpAboutState.cpp:73 msgid "SDL linked version:" msgstr "SDL lænket version:" -#: ../../code/HelpAboutState.cpp:80 +#: ../../code/HelpAboutState.cpp:74 msgid "Save folder:" msgstr "Mappe til gemte spil:" -#: ../../code/HelpAboutState.cpp:81 +#: ../../code/HelpAboutState.cpp:75 msgid "Locale:" msgstr "Lokalitet:" -#: ../../code/HelpAboutState.cpp:82 ../../code/menudef.cpp:414 +#: ../../code/HelpAboutState.cpp:76 ../../code/menudef.cpp:428 msgid "About" msgstr "Om" -#: ../../code/HelpGamepadState.cpp:52 +#: ../../code/HelpGamepadState.cpp:35 +msgid "" +"Only SDL2 compatible controllers are supported!\n" +"Supported controllers: " +msgstr "" +"Kun SDL2 kompatible kontrollere er understøttet!\n" +"Understøttede kontrollere: " + +#: ../../code/HelpGamepadState.cpp:47 msgid "Move cursor" msgstr "Flyt markøren" -#: ../../code/HelpGamepadState.cpp:53 +#: ../../code/HelpGamepadState.cpp:48 msgid "Push line" msgstr "Skub linje" -#: ../../code/HelpGamepadState.cpp:54 +#: ../../code/HelpGamepadState.cpp:49 msgid "Back (Menu)" msgstr "Tilbage (Menu)" -#: ../../code/HelpGamepadState.cpp:55 +#: ../../code/HelpGamepadState.cpp:50 msgid "Switch" msgstr "Skift" -#: ../../code/HelpGamepadState.cpp:56 +#: ../../code/HelpGamepadState.cpp:51 msgid "Confirm" msgstr "Bekræft" -#: ../../code/HelpGamepadState.cpp:57 -msgid "" -"Only SDL2 compatible controllers are supported!\n" -"Supported controllers: " -msgstr "" -"Kun SDL2 kompatible kontrollere er understøttet!\n" -"Understøttede kontrollere: " - #: ../../code/HelpHowtoState.cpp:125 msgid "Switch block horizontally" msgstr "Skift blokke horisontalt" @@ -130,392 +130,412 @@ msgstr "Lad blokke falde!" msgid "Create a chain effect" msgstr "Lav en kæde effekt" -#: ../../code/levelselect.cpp:86 +#: ../../code/levelselect.cpp:84 msgid "Select Puzzle" msgstr "Vælg gåde" -#: ../../code/levelselect.cpp:89 +#: ../../code/levelselect.cpp:87 msgid "Stage Clear Level Select" msgstr "Vælg Stage Clear-bane" -#: ../../code/levelselect.cpp:195 +#: ../../code/levelselect.cpp:193 #, c-format msgid "Best score: %i" msgstr "Bedste resultat: %i" -#: ../../code/levelselect.cpp:196 +#: ../../code/levelselect.cpp:194 #, c-format msgid "Time used: %s" msgstr "Tid brugt: %s" -#: ../../code/levelselect.cpp:199 +#: ../../code/levelselect.cpp:197 #, c-format msgid "Time used: %d : %02d" msgstr "Tid brugt: %d : %02d" -#: ../../code/levelselect.cpp:204 +#: ../../code/levelselect.cpp:202 #, c-format msgid "Total score: %i in %i:%02i" msgstr "Sammenlagt: %i på %i:%02i" -#: ../../code/main.cpp:158 +#: ../../code/main.cpp:164 msgid "GAME OVER" msgstr "SPILLET ER SLUT" -#: ../../code/main.cpp:159 +#: ../../code/main.cpp:165 msgid "WINNER" msgstr "VINDER" -#: ../../code/main.cpp:160 +#: ../../code/main.cpp:166 msgid "DRAW" msgstr "UAFGJORT" -#: ../../code/main.cpp:497 ../../code/main.cpp:628 +#: ../../code/main.cpp:504 ../../code/main.cpp:635 msgid "AI" msgstr "Computer" -#: ../../code/main.cpp:500 +#: ../../code/main.cpp:507 msgid "Playing field" msgstr "Spilleflade" -#: ../../code/main.cpp:574 +#: ../../code/main.cpp:581 msgid "Time Trial" msgstr "På tid" -#: ../../code/main.cpp:575 +#: ../../code/main.cpp:582 msgid "Score as much as possible in 2 minutes" msgstr "Se hvor mange point du kan opnå på 2 minutter" -#: ../../code/main.cpp:579 +#: ../../code/main.cpp:586 msgid "Stage Clear" msgstr "Stage Clear" -#: ../../code/main.cpp:580 +#: ../../code/main.cpp:587 msgid "You must clear a number of lines. Speed is rapidly increased." msgstr "Fjern et specifik antal linjer. Hastigheden stiger hurtigt." -#: ../../code/main.cpp:583 +#: ../../code/main.cpp:590 msgid "Puzzle" msgstr "Gåde" -#: ../../code/main.cpp:584 +#: ../../code/main.cpp:591 msgid "Clear the entire board with a limited number of moves." msgstr "Fjern alle blokke med et begrænset antal flyt." -#: ../../code/main.cpp:587 +#: ../../code/main.cpp:594 msgid "Endless" msgstr "Evighed" -#: ../../code/main.cpp:588 +#: ../../code/main.cpp:595 msgid "Score as much as possible. No time limit." msgstr "Opnå så mange point som muligt. Ingen tidsbegrænsning." -#: ../../code/main.cpp:598 +#: ../../code/main.cpp:605 msgid "Objective:" msgstr "Formål:" -#: ../../code/main.cpp:608 +#: ../../code/main.cpp:615 msgid "Movement keys:" msgstr "Bevægelsestaster:" -#: ../../code/main.cpp:610 +#: ../../code/main.cpp:617 msgid "Switch: " msgstr "Skift: " -#: ../../code/main.cpp:612 +#: ../../code/main.cpp:619 msgid "Restart: " msgstr "Genstart: " -#: ../../code/main.cpp:615 +#: ../../code/main.cpp:622 msgid "Push line: " msgstr "Skub linje: " -#: ../../code/main.cpp:1050 +#: ../../code/main.cpp:1076 msgid "Player 2" msgstr "Spiller 2" -#: ../../code/menudef.cpp:62 +#: ../../code/menudef.cpp:59 msgid "Up arrow" msgstr "Pil op" -#: ../../code/menudef.cpp:65 +#: ../../code/menudef.cpp:62 msgid "Down arrow" msgstr "Pil ned" -#: ../../code/menudef.cpp:68 +#: ../../code/menudef.cpp:65 msgid "Left arrow" msgstr "Pil venstre" -#: ../../code/menudef.cpp:71 +#: ../../code/menudef.cpp:68 msgid "Right arrow" msgstr "Pil højre" -#: ../../code/menudef.cpp:74 +#: ../../code/menudef.cpp:71 msgid "Right Ctrl" msgstr "Højre Ctrl" -#: ../../code/menudef.cpp:77 +#: ../../code/menudef.cpp:74 msgid "Left Ctrl" msgstr "Venstre Ctrl" -#: ../../code/menudef.cpp:80 +#: ../../code/menudef.cpp:77 msgid "Right shift" msgstr "Højre skift" -#: ../../code/menudef.cpp:83 +#: ../../code/menudef.cpp:80 msgid "Left shift" msgstr "Venstre skift" -#: ../../code/menudef.cpp:86 +#: ../../code/menudef.cpp:83 msgid "Right alt" msgstr "AltGr" -#: ../../code/menudef.cpp:89 +#: ../../code/menudef.cpp:86 msgid "Left alt" msgstr "Alt" -#: ../../code/menudef.cpp:92 +#: ../../code/menudef.cpp:89 msgid "Return" msgstr "Enter" -#: ../../code/menudef.cpp:95 +#: ../../code/menudef.cpp:92 msgid "Space" msgstr "Mellemrum" -#: ../../code/menudef.cpp:162 +#: ../../code/menudef.cpp:158 msgid "Single Player Endless" msgstr "En spiller - Evighed" -#: ../../code/menudef.cpp:169 +#: ../../code/menudef.cpp:165 msgid "Slow" msgstr "Langsom" -#: ../../code/menudef.cpp:170 +#: ../../code/menudef.cpp:166 msgid "Fast" msgstr "Hurtig" -#: ../../code/menudef.cpp:171 +#: ../../code/menudef.cpp:167 msgid "Faster" msgstr "Hurtigere" -#: ../../code/menudef.cpp:172 +#: ../../code/menudef.cpp:168 msgid "Even faster" msgstr "Endnu hurtigere" -#: ../../code/menudef.cpp:173 +#: ../../code/menudef.cpp:169 msgid "Fastest" msgstr "Hurtigst" -#: ../../code/menudef.cpp:215 +#: ../../code/menudef.cpp:211 msgid "Always use software render: On" msgstr "Brug altid software tilstand: Til" -#: ../../code/menudef.cpp:216 +#: ../../code/menudef.cpp:212 msgid "Always use software render: Off" msgstr "Brug altid software tilstand: Fra" -#: ../../code/menudef.cpp:220 +#: ../../code/menudef.cpp:216 msgid "Music: On" msgstr "Musik: Til" -#: ../../code/menudef.cpp:220 +#: ../../code/menudef.cpp:216 msgid "Music: Off" msgstr "Musik: Fra" -#: ../../code/menudef.cpp:224 +#: ../../code/menudef.cpp:220 msgid "Sound: On" msgstr "Lyd: Til" -#: ../../code/menudef.cpp:224 +#: ../../code/menudef.cpp:220 msgid "Sound: Off" msgstr "Lyd: Fra" -#: ../../code/menudef.cpp:228 +#: ../../code/menudef.cpp:224 msgid "Fullscreen: On" msgstr "Fuldskærm: Til" -#: ../../code/menudef.cpp:228 +#: ../../code/menudef.cpp:224 msgid "Fullscreen: Off" msgstr "Fuldskærm: Fra" -#: ../../code/menudef.cpp:261 +#: ../../code/menudef.cpp:257 msgid "Enter player 1 name:" msgstr "Indtast navnet på spiller 1:" -#: ../../code/menudef.cpp:267 +#: ../../code/menudef.cpp:263 msgid "Enter player 2 name:" msgstr "Indtast navnet på spiller 2:" -#: ../../code/menudef.cpp:277 +#: ../../code/menudef.cpp:273 msgid "Change key bindings" msgstr "Skift taster" -#: ../../code/menudef.cpp:278 +#: ../../code/menudef.cpp:274 msgid "Left" msgstr "Venstre" -#: ../../code/menudef.cpp:279 +#: ../../code/menudef.cpp:275 msgid "Right" msgstr "Højre" -#: ../../code/menudef.cpp:280 +#: ../../code/menudef.cpp:276 msgid "Up" msgstr "Op" -#: ../../code/menudef.cpp:281 +#: ../../code/menudef.cpp:277 msgid "Down" msgstr "Ned" -#: ../../code/menudef.cpp:282 +#: ../../code/menudef.cpp:278 msgid "Push" msgstr "Skub" -#: ../../code/menudef.cpp:283 +#: ../../code/menudef.cpp:279 msgid "Change" msgstr "Skift" -#: ../../code/menudef.cpp:302 -msgid "Configuration" -msgstr "Konfiguration" +#: ../../code/menudef.cpp:298 ../../code/menudef.cpp:329 +msgid "Player configuration" +msgstr "Spiller konfiguration" -#: ../../code/menudef.cpp:314 +#: ../../code/menudef.cpp:302 msgid "Change player 1's name" msgstr "Skift navn på spiller 1" -#: ../../code/menudef.cpp:316 +#: ../../code/menudef.cpp:304 msgid "Change player 2's name" msgstr "Skift navn på spiller 2" -#: ../../code/menudef.cpp:318 +#: ../../code/menudef.cpp:306 msgid "Change player 1's keys" msgstr "Tildel taster til spiller 1" -#: ../../code/menudef.cpp:320 +#: ../../code/menudef.cpp:308 msgid "Change player 2's keys" msgstr "Tildel taster til spiller 2" -#: ../../code/menudef.cpp:333 +#: ../../code/menudef.cpp:322 +msgid "Configuration" +msgstr "Konfiguration" + +#: ../../code/menudef.cpp:331 +msgid "Configure mods" +msgstr "Mods" + +#: ../../code/menudef.cpp:347 msgid "Single player VS" msgstr "En spiller - VS" -#: ../../code/menudef.cpp:349 +#: ../../code/menudef.cpp:363 msgid "Very easy" msgstr "Meget let" -#: ../../code/menudef.cpp:350 +#: ../../code/menudef.cpp:364 msgid "Easy" msgstr "Let" -#: ../../code/menudef.cpp:351 +#: ../../code/menudef.cpp:365 msgid "Below normal" msgstr "Under normal" -#: ../../code/menudef.cpp:352 +#: ../../code/menudef.cpp:366 msgid "Normal" msgstr "Normal" -#: ../../code/menudef.cpp:353 +#: ../../code/menudef.cpp:367 msgid "Above normal" msgstr "Over normal" -#: ../../code/menudef.cpp:354 +#: ../../code/menudef.cpp:368 msgid "Hard" msgstr "Svær" -#: ../../code/menudef.cpp:355 +#: ../../code/menudef.cpp:369 msgid "Hardest" msgstr "Meget svær" -#: ../../code/menudef.cpp:367 +#: ../../code/menudef.cpp:381 msgid "Multiplayer" msgstr "Flerspiller" -#: ../../code/menudef.cpp:369 +#: ../../code/menudef.cpp:383 msgid "Two player - time trial" msgstr "To spillere - På tid" -#: ../../code/menudef.cpp:371 +#: ../../code/menudef.cpp:385 msgid "Two player - vs" msgstr "To spillere - VS" -#: ../../code/menudef.cpp:395 ../../code/menudef.cpp:410 +#: ../../code/menudef.cpp:409 ../../code/menudef.cpp:424 msgid "Credits" msgstr "Bidragydere" -#: ../../code/menudef.cpp:400 ../../code/menudef.cpp:471 +#: ../../code/menudef.cpp:414 ../../code/menudef.cpp:487 msgid "Help" msgstr "Hjælp" -#: ../../code/menudef.cpp:402 +#: ../../code/menudef.cpp:416 msgid "How to" msgstr "Guide" -#: ../../code/menudef.cpp:406 +#: ../../code/menudef.cpp:420 msgid "Gamepad" msgstr "Spilkontroller" -#: ../../code/menudef.cpp:421 ../../code/menudef.cpp:463 +#: ../../code/menudef.cpp:435 ../../code/menudef.cpp:479 msgid "Single player" msgstr "Enkeltspiller" -#: ../../code/menudef.cpp:423 +#: ../../code/menudef.cpp:437 msgid "Single player - endless" msgstr "En spiller - Evighed" -#: ../../code/menudef.cpp:425 +#: ../../code/menudef.cpp:439 msgid "Single player - time trial" msgstr "En spiller - På tid" -#: ../../code/menudef.cpp:427 +#: ../../code/menudef.cpp:441 msgid "Single player - stage clear" msgstr "En spiller - Stage Clear" -#: ../../code/menudef.cpp:429 +#: ../../code/menudef.cpp:443 msgid "Single player - puzzle mode" msgstr "En spiller - Gåde" -#: ../../code/menudef.cpp:431 +#: ../../code/menudef.cpp:445 msgid "Single player - vs" msgstr "En spiller - VS" -#: ../../code/menudef.cpp:446 +#: ../../code/menudef.cpp:460 msgid "Game did not shutdown as it should" msgstr "Spillet blev ikke afsluttet korrekt" -#: ../../code/menudef.cpp:449 +#: ../../code/menudef.cpp:463 msgid "Use software renderer this time" msgstr "Brug software tilstand denne gang" -#: ../../code/menudef.cpp:450 +#: ../../code/menudef.cpp:464 msgid "Always use software renderer" msgstr "Start altid i software tilstand" -#: ../../code/menudef.cpp:461 +#: ../../code/menudef.cpp:477 msgid "Block Attack - Rise of the blocks" msgstr "Block Attack - Blokkenes opstand" -#: ../../code/menudef.cpp:465 +#: ../../code/menudef.cpp:481 msgid "Multi player" msgstr "Flere spillere" -#: ../../code/menudef.cpp:467 +#: ../../code/menudef.cpp:483 msgid "Configure" msgstr "Instillinger" -#: ../../code/menudef.cpp:469 +#: ../../code/menudef.cpp:485 msgid "Highscores" msgstr "Bedste resultater" -#: ../../code/MenuSystem.cpp:159 ../../code/MenuSystem.cpp:167 -#: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:220 +#: ../../code/MenuSystem.cpp:146 ../../code/MenuSystem.cpp:151 +#: ../../code/MenuSystem.cpp:160 ../../code/ScoresDisplay.cpp:220 msgid "Back" msgstr "Tilbage" -#: ../../code/MenuSystem.cpp:170 ../../code/MenuSystem.cpp:182 +#: ../../code/MenuSystem.cpp:154 ../../code/MenuSystem.cpp:163 msgid "Exit" msgstr "Afslut" -#: ../../code/os.cpp:101 +#: ../../code/ModConfigMenuState.cpp:84 +msgid "Mod config" +msgstr "Mods" + +#: ../../code/ModConfigMenuState.cpp:87 +msgid "Yes" +msgstr "Ja" + +#: ../../code/ModConfigMenuState.cpp:87 +msgid "No" +msgstr "Nej" + +#: ../../code/os.cpp:103 msgid "Player 1" msgstr "Spiller 1" @@ -624,15 +644,15 @@ msgstr "Prøv igen" msgid "Skip" msgstr "Spring over" -#: ../../code/BlockGameSdl.inc:328 +#: ../../code/BlockGameSdl.inc:318 msgid "Moves left: " msgstr "Træk tilbage: " -#: ../../code/BlockGameSdl.inc:351 +#: ../../code/BlockGameSdl.inc:341 msgid "Last puzzle" msgstr "Sidste gåde" -#: ../../code/BlockGameSdl.inc:371 +#: ../../code/BlockGameSdl.inc:361 msgid "Last stage" msgstr "Sidste bane" diff --git a/source/misc/translation/template/blockattack_roftb.pot b/source/misc/translation/template/blockattack_roftb.pot index ac49a7a..818399d 100644 --- a/source/misc/translation/template/blockattack_roftb.pot +++ b/source/misc/translation/template/blockattack_roftb.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-06-27 14:06+0200\n" +"POT-Creation-Date: 2020-12-27 11:03+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -25,88 +25,88 @@ msgstr "" msgid "Esc to cancel" msgstr "" -#: ../../code/HelpAboutState.cpp:68 +#: ../../code/HelpAboutState.cpp:62 msgid "No audio driver" msgstr "" -#: ../../code/HelpAboutState.cpp:71 +#: ../../code/HelpAboutState.cpp:65 msgid "Name:" msgstr "" -#: ../../code/HelpAboutState.cpp:71 ../../code/main.cpp:329 +#: ../../code/HelpAboutState.cpp:65 ../../code/main.cpp:336 msgid "Block Attack - Rise of the Blocks" msgstr "" -#: ../../code/HelpAboutState.cpp:72 +#: ../../code/HelpAboutState.cpp:66 msgid "Original name:" msgstr "" -#: ../../code/HelpAboutState.cpp:73 +#: ../../code/HelpAboutState.cpp:67 msgid "Version:" msgstr "" -#: ../../code/HelpAboutState.cpp:74 +#: ../../code/HelpAboutState.cpp:68 msgid "Homepage:" msgstr "" -#: ../../code/HelpAboutState.cpp:75 +#: ../../code/HelpAboutState.cpp:69 msgid "Github page:" msgstr "" -#: ../../code/HelpAboutState.cpp:76 +#: ../../code/HelpAboutState.cpp:70 msgid "SDL render:" msgstr "" -#: ../../code/HelpAboutState.cpp:77 +#: ../../code/HelpAboutState.cpp:71 msgid "SDL audio driver:" msgstr "" -#: ../../code/HelpAboutState.cpp:78 +#: ../../code/HelpAboutState.cpp:72 msgid "SDL compiled version:" msgstr "" -#: ../../code/HelpAboutState.cpp:79 +#: ../../code/HelpAboutState.cpp:73 msgid "SDL linked version:" msgstr "" -#: ../../code/HelpAboutState.cpp:80 +#: ../../code/HelpAboutState.cpp:74 msgid "Save folder:" msgstr "" -#: ../../code/HelpAboutState.cpp:81 +#: ../../code/HelpAboutState.cpp:75 msgid "Locale:" msgstr "" -#: ../../code/HelpAboutState.cpp:82 ../../code/menudef.cpp:414 +#: ../../code/HelpAboutState.cpp:76 ../../code/menudef.cpp:428 msgid "About" msgstr "" -#: ../../code/HelpGamepadState.cpp:52 +#: ../../code/HelpGamepadState.cpp:35 +msgid "" +"Only SDL2 compatible controllers are supported!\n" +"Supported controllers: " +msgstr "" + +#: ../../code/HelpGamepadState.cpp:47 msgid "Move cursor" msgstr "" -#: ../../code/HelpGamepadState.cpp:53 +#: ../../code/HelpGamepadState.cpp:48 msgid "Push line" msgstr "" -#: ../../code/HelpGamepadState.cpp:54 +#: ../../code/HelpGamepadState.cpp:49 msgid "Back (Menu)" msgstr "" -#: ../../code/HelpGamepadState.cpp:55 +#: ../../code/HelpGamepadState.cpp:50 msgid "Switch" msgstr "" -#: ../../code/HelpGamepadState.cpp:56 +#: ../../code/HelpGamepadState.cpp:51 msgid "Confirm" msgstr "" -#: ../../code/HelpGamepadState.cpp:57 -msgid "" -"Only SDL2 compatible controllers are supported!\n" -"Supported controllers: " -msgstr "" - #: ../../code/HelpHowtoState.cpp:125 msgid "Switch block horizontally" msgstr "" @@ -127,392 +127,412 @@ msgstr "" msgid "Create a chain effect" msgstr "" -#: ../../code/levelselect.cpp:86 +#: ../../code/levelselect.cpp:84 msgid "Select Puzzle" msgstr "" -#: ../../code/levelselect.cpp:89 +#: ../../code/levelselect.cpp:87 msgid "Stage Clear Level Select" msgstr "" -#: ../../code/levelselect.cpp:195 +#: ../../code/levelselect.cpp:193 #, c-format msgid "Best score: %i" msgstr "" -#: ../../code/levelselect.cpp:196 +#: ../../code/levelselect.cpp:194 #, c-format msgid "Time used: %s" msgstr "" -#: ../../code/levelselect.cpp:199 +#: ../../code/levelselect.cpp:197 #, c-format msgid "Time used: %d : %02d" msgstr "" -#: ../../code/levelselect.cpp:204 +#: ../../code/levelselect.cpp:202 #, c-format msgid "Total score: %i in %i:%02i" msgstr "" -#: ../../code/main.cpp:158 +#: ../../code/main.cpp:164 msgid "GAME OVER" msgstr "" -#: ../../code/main.cpp:159 +#: ../../code/main.cpp:165 msgid "WINNER" msgstr "" -#: ../../code/main.cpp:160 +#: ../../code/main.cpp:166 msgid "DRAW" msgstr "" -#: ../../code/main.cpp:497 ../../code/main.cpp:628 +#: ../../code/main.cpp:504 ../../code/main.cpp:635 msgid "AI" msgstr "" -#: ../../code/main.cpp:500 +#: ../../code/main.cpp:507 msgid "Playing field" msgstr "" -#: ../../code/main.cpp:574 +#: ../../code/main.cpp:581 msgid "Time Trial" msgstr "" -#: ../../code/main.cpp:575 +#: ../../code/main.cpp:582 msgid "Score as much as possible in 2 minutes" msgstr "" -#: ../../code/main.cpp:579 +#: ../../code/main.cpp:586 msgid "Stage Clear" msgstr "" -#: ../../code/main.cpp:580 +#: ../../code/main.cpp:587 msgid "You must clear a number of lines. Speed is rapidly increased." msgstr "" -#: ../../code/main.cpp:583 +#: ../../code/main.cpp:590 msgid "Puzzle" msgstr "" -#: ../../code/main.cpp:584 +#: ../../code/main.cpp:591 msgid "Clear the entire board with a limited number of moves." msgstr "" -#: ../../code/main.cpp:587 +#: ../../code/main.cpp:594 msgid "Endless" msgstr "" -#: ../../code/main.cpp:588 +#: ../../code/main.cpp:595 msgid "Score as much as possible. No time limit." msgstr "" -#: ../../code/main.cpp:598 +#: ../../code/main.cpp:605 msgid "Objective:" msgstr "" -#: ../../code/main.cpp:608 +#: ../../code/main.cpp:615 msgid "Movement keys:" msgstr "" -#: ../../code/main.cpp:610 +#: ../../code/main.cpp:617 msgid "Switch: " msgstr "" -#: ../../code/main.cpp:612 +#: ../../code/main.cpp:619 msgid "Restart: " msgstr "" -#: ../../code/main.cpp:615 +#: ../../code/main.cpp:622 msgid "Push line: " msgstr "" -#: ../../code/main.cpp:1050 +#: ../../code/main.cpp:1076 msgid "Player 2" msgstr "" -#: ../../code/menudef.cpp:62 +#: ../../code/menudef.cpp:59 msgid "Up arrow" msgstr "" -#: ../../code/menudef.cpp:65 +#: ../../code/menudef.cpp:62 msgid "Down arrow" msgstr "" -#: ../../code/menudef.cpp:68 +#: ../../code/menudef.cpp:65 msgid "Left arrow" msgstr "" -#: ../../code/menudef.cpp:71 +#: ../../code/menudef.cpp:68 msgid "Right arrow" msgstr "" -#: ../../code/menudef.cpp:74 +#: ../../code/menudef.cpp:71 msgid "Right Ctrl" msgstr "" -#: ../../code/menudef.cpp:77 +#: ../../code/menudef.cpp:74 msgid "Left Ctrl" msgstr "" -#: ../../code/menudef.cpp:80 +#: ../../code/menudef.cpp:77 msgid "Right shift" msgstr "" -#: ../../code/menudef.cpp:83 +#: ../../code/menudef.cpp:80 msgid "Left shift" msgstr "" -#: ../../code/menudef.cpp:86 +#: ../../code/menudef.cpp:83 msgid "Right alt" msgstr "" -#: ../../code/menudef.cpp:89 +#: ../../code/menudef.cpp:86 msgid "Left alt" msgstr "" -#: ../../code/menudef.cpp:92 +#: ../../code/menudef.cpp:89 msgid "Return" msgstr "" -#: ../../code/menudef.cpp:95 +#: ../../code/menudef.cpp:92 msgid "Space" msgstr "" -#: ../../code/menudef.cpp:162 +#: ../../code/menudef.cpp:158 msgid "Single Player Endless" msgstr "" -#: ../../code/menudef.cpp:169 +#: ../../code/menudef.cpp:165 msgid "Slow" msgstr "" -#: ../../code/menudef.cpp:170 +#: ../../code/menudef.cpp:166 msgid "Fast" msgstr "" -#: ../../code/menudef.cpp:171 +#: ../../code/menudef.cpp:167 msgid "Faster" msgstr "" -#: ../../code/menudef.cpp:172 +#: ../../code/menudef.cpp:168 msgid "Even faster" msgstr "" -#: ../../code/menudef.cpp:173 +#: ../../code/menudef.cpp:169 msgid "Fastest" msgstr "" -#: ../../code/menudef.cpp:215 +#: ../../code/menudef.cpp:211 msgid "Always use software render: On" msgstr "" -#: ../../code/menudef.cpp:216 +#: ../../code/menudef.cpp:212 msgid "Always use software render: Off" msgstr "" -#: ../../code/menudef.cpp:220 +#: ../../code/menudef.cpp:216 msgid "Music: On" msgstr "" -#: ../../code/menudef.cpp:220 +#: ../../code/menudef.cpp:216 msgid "Music: Off" msgstr "" -#: ../../code/menudef.cpp:224 +#: ../../code/menudef.cpp:220 msgid "Sound: On" msgstr "" -#: ../../code/menudef.cpp:224 +#: ../../code/menudef.cpp:220 msgid "Sound: Off" msgstr "" -#: ../../code/menudef.cpp:228 +#: ../../code/menudef.cpp:224 msgid "Fullscreen: On" msgstr "" -#: ../../code/menudef.cpp:228 +#: ../../code/menudef.cpp:224 msgid "Fullscreen: Off" msgstr "" -#: ../../code/menudef.cpp:261 +#: ../../code/menudef.cpp:257 msgid "Enter player 1 name:" msgstr "" -#: ../../code/menudef.cpp:267 +#: ../../code/menudef.cpp:263 msgid "Enter player 2 name:" msgstr "" -#: ../../code/menudef.cpp:277 +#: ../../code/menudef.cpp:273 msgid "Change key bindings" msgstr "" -#: ../../code/menudef.cpp:278 +#: ../../code/menudef.cpp:274 msgid "Left" msgstr "" -#: ../../code/menudef.cpp:279 +#: ../../code/menudef.cpp:275 msgid "Right" msgstr "" -#: ../../code/menudef.cpp:280 +#: ../../code/menudef.cpp:276 msgid "Up" msgstr "" -#: ../../code/menudef.cpp:281 +#: ../../code/menudef.cpp:277 msgid "Down" msgstr "" -#: ../../code/menudef.cpp:282 +#: ../../code/menudef.cpp:278 msgid "Push" msgstr "" -#: ../../code/menudef.cpp:283 +#: ../../code/menudef.cpp:279 msgid "Change" msgstr "" -#: ../../code/menudef.cpp:302 -msgid "Configuration" +#: ../../code/menudef.cpp:298 ../../code/menudef.cpp:329 +msgid "Player configuration" msgstr "" -#: ../../code/menudef.cpp:314 +#: ../../code/menudef.cpp:302 msgid "Change player 1's name" msgstr "" -#: ../../code/menudef.cpp:316 +#: ../../code/menudef.cpp:304 msgid "Change player 2's name" msgstr "" -#: ../../code/menudef.cpp:318 +#: ../../code/menudef.cpp:306 msgid "Change player 1's keys" msgstr "" -#: ../../code/menudef.cpp:320 +#: ../../code/menudef.cpp:308 msgid "Change player 2's keys" msgstr "" -#: ../../code/menudef.cpp:333 +#: ../../code/menudef.cpp:322 +msgid "Configuration" +msgstr "" + +#: ../../code/menudef.cpp:331 +msgid "Configure mods" +msgstr "" + +#: ../../code/menudef.cpp:347 msgid "Single player VS" msgstr "" -#: ../../code/menudef.cpp:349 +#: ../../code/menudef.cpp:363 msgid "Very easy" msgstr "" -#: ../../code/menudef.cpp:350 +#: ../../code/menudef.cpp:364 msgid "Easy" msgstr "" -#: ../../code/menudef.cpp:351 +#: ../../code/menudef.cpp:365 msgid "Below normal" msgstr "" -#: ../../code/menudef.cpp:352 +#: ../../code/menudef.cpp:366 msgid "Normal" msgstr "" -#: ../../code/menudef.cpp:353 +#: ../../code/menudef.cpp:367 msgid "Above normal" msgstr "" -#: ../../code/menudef.cpp:354 +#: ../../code/menudef.cpp:368 msgid "Hard" msgstr "" -#: ../../code/menudef.cpp:355 +#: ../../code/menudef.cpp:369 msgid "Hardest" msgstr "" -#: ../../code/menudef.cpp:367 +#: ../../code/menudef.cpp:381 msgid "Multiplayer" msgstr "" -#: ../../code/menudef.cpp:369 +#: ../../code/menudef.cpp:383 msgid "Two player - time trial" msgstr "" -#: ../../code/menudef.cpp:371 +#: ../../code/menudef.cpp:385 msgid "Two player - vs" msgstr "" -#: ../../code/menudef.cpp:395 ../../code/menudef.cpp:410 +#: ../../code/menudef.cpp:409 ../../code/menudef.cpp:424 msgid "Credits" msgstr "" -#: ../../code/menudef.cpp:400 ../../code/menudef.cpp:471 +#: ../../code/menudef.cpp:414 ../../code/menudef.cpp:487 msgid "Help" msgstr "" -#: ../../code/menudef.cpp:402 +#: ../../code/menudef.cpp:416 msgid "How to" msgstr "" -#: ../../code/menudef.cpp:406 +#: ../../code/menudef.cpp:420 msgid "Gamepad" msgstr "" -#: ../../code/menudef.cpp:421 ../../code/menudef.cpp:463 +#: ../../code/menudef.cpp:435 ../../code/menudef.cpp:479 msgid "Single player" msgstr "" -#: ../../code/menudef.cpp:423 +#: ../../code/menudef.cpp:437 msgid "Single player - endless" msgstr "" -#: ../../code/menudef.cpp:425 +#: ../../code/menudef.cpp:439 msgid "Single player - time trial" msgstr "" -#: ../../code/menudef.cpp:427 +#: ../../code/menudef.cpp:441 msgid "Single player - stage clear" msgstr "" -#: ../../code/menudef.cpp:429 +#: ../../code/menudef.cpp:443 msgid "Single player - puzzle mode" msgstr "" -#: ../../code/menudef.cpp:431 +#: ../../code/menudef.cpp:445 msgid "Single player - vs" msgstr "" -#: ../../code/menudef.cpp:446 +#: ../../code/menudef.cpp:460 msgid "Game did not shutdown as it should" msgstr "" -#: ../../code/menudef.cpp:449 +#: ../../code/menudef.cpp:463 msgid "Use software renderer this time" msgstr "" -#: ../../code/menudef.cpp:450 +#: ../../code/menudef.cpp:464 msgid "Always use software renderer" msgstr "" -#: ../../code/menudef.cpp:461 +#: ../../code/menudef.cpp:477 msgid "Block Attack - Rise of the blocks" msgstr "" -#: ../../code/menudef.cpp:465 +#: ../../code/menudef.cpp:481 msgid "Multi player" msgstr "" -#: ../../code/menudef.cpp:467 +#: ../../code/menudef.cpp:483 msgid "Configure" msgstr "" -#: ../../code/menudef.cpp:469 +#: ../../code/menudef.cpp:485 msgid "Highscores" msgstr "" -#: ../../code/MenuSystem.cpp:159 ../../code/MenuSystem.cpp:167 -#: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:220 +#: ../../code/MenuSystem.cpp:146 ../../code/MenuSystem.cpp:151 +#: ../../code/MenuSystem.cpp:160 ../../code/ScoresDisplay.cpp:220 msgid "Back" msgstr "" -#: ../../code/MenuSystem.cpp:170 ../../code/MenuSystem.cpp:182 +#: ../../code/MenuSystem.cpp:154 ../../code/MenuSystem.cpp:163 msgid "Exit" msgstr "" -#: ../../code/os.cpp:101 +#: ../../code/ModConfigMenuState.cpp:84 +msgid "Mod config" +msgstr "" + +#: ../../code/ModConfigMenuState.cpp:87 +msgid "Yes" +msgstr "" + +#: ../../code/ModConfigMenuState.cpp:87 +msgid "No" +msgstr "" + +#: ../../code/os.cpp:103 msgid "Player 1" msgstr "" @@ -621,15 +641,15 @@ msgstr "" msgid "Skip" msgstr "" -#: ../../code/BlockGameSdl.inc:328 +#: ../../code/BlockGameSdl.inc:318 msgid "Moves left: " msgstr "" -#: ../../code/BlockGameSdl.inc:351 +#: ../../code/BlockGameSdl.inc:341 msgid "Last puzzle" msgstr "" -#: ../../code/BlockGameSdl.inc:371 +#: ../../code/BlockGameSdl.inc:361 msgid "Last stage" msgstr ""