Merge pull request #1336 from colobot/dev-mod-manager

Add Mod Manager
pyro-refactor
Emxx52 2020-08-21 18:43:45 +02:00 committed by GitHub
commit b17a4391b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 2163 additions and 102 deletions

View File

@ -189,12 +189,12 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\" /EHsc") # disable some useless warnings set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\" /EHsc") # disable some useless warnings
if(MSVC_STATIC) if(MSVC_STATIC)
set(RELEASE_CXX_FLAGS "/MT /Ox") set(RELEASE_CXX_FLAGS "/MT /Ox")
set(DEBUG_CXX_FLAGS "/MTd /ZI") set(DEBUG_CXX_FLAGS "/MTd /Od /ZI")
else(MSVC_STATIC) else(MSVC_STATIC)
set(RELEASE_CXX_FLAGS "/MD /Ox") set(RELEASE_CXX_FLAGS "/MD /Ox")
set(DEBUG_CXX_FLAGS "/MDd /ZI") set(DEBUG_CXX_FLAGS "/MDd /Od /ZI")
endif() endif()
set(TEST_CXX_FLAGS "") set(TEST_CXX_FLAGS "${DEBUG_CXX_FLAGS}")
add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG) add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG)
# Needed for Debug information (it's set to "No" by default for some reason) # Needed for Debug information (it's set to "No" by default for some reason)

2
data

@ -1 +1 @@
Subproject commit 611cbfdd079e97a71f97810636f2ab2358cb4eeb Subproject commit 069fc5bd15b87aaf5b1b301a787f05a99dfc3856

View File

@ -84,6 +84,9 @@ msgstr ""
msgid "Load a saved mission" msgid "Load a saved mission"
msgstr "" msgstr ""
msgid "Mods"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "" msgstr ""
@ -166,6 +169,23 @@ msgstr ""
msgid "This menu is for userlevels from mods, but you didn't install any" msgid "This menu is for userlevels from mods, but you didn't install any"
msgstr "" msgstr ""
msgid "Could not open the file explorer!"
msgstr ""
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "Keyword help(\\key cbot;)" msgid "Keyword help(\\key cbot;)"
msgstr "" msgstr ""
@ -280,6 +300,42 @@ msgstr ""
msgid "%s: %d pts" msgid "%s: %d pts"
msgstr "" msgstr ""
msgid "Mods:"
msgstr ""
msgid "Information:"
msgstr ""
msgid "Description:"
msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Unknown author"
msgstr ""
msgid "by"
msgstr ""
msgid "Version"
msgstr ""
msgid "Website"
msgstr ""
msgid "Changes"
msgstr ""
msgid "No description."
msgstr ""
msgid "No changes."
msgstr ""
msgid "Code battle" msgid "Code battle"
msgstr "" msgstr ""
@ -316,6 +372,9 @@ msgstr ""
msgid "SatCom" msgid "SatCom"
msgstr "" msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "" msgstr ""
@ -343,6 +402,24 @@ msgstr ""
msgid "Play\\Start mission!" msgid "Play\\Start mission!"
msgstr "" msgstr ""
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "" msgstr ""

View File

@ -125,6 +125,9 @@ msgstr "Vzhled\\Upravte svůj vzhled"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Uložit změny\\Aktivovat změny nastavení" msgstr "Uložit změny\\Aktivovat změny nastavení"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Chybí vhodný konstruktor" msgstr "Chybí vhodný konstruktor"
@ -371,6 +374,9 @@ msgstr "Změnit kameru\\Přepíná mezi kamerou na robotu a za robotem"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Změnit hráče\\Změnit hráče" msgstr "Změnit hráče\\Změnit hráče"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Kapitoly:" msgstr "Kapitoly:"
@ -440,6 +446,12 @@ msgstr "Kopírovat"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Kopírovat (Ctrl+C)" msgstr "Kopírovat (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Současná mise uložena" msgstr "Současná mise uložena"
@ -473,6 +485,9 @@ msgstr "Vrtná věž"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Klesat\\Snížit tah tryskového motoru" msgstr "Klesat\\Snížit tah tryskového motoru"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Zbourat" msgstr "Zbourat"
@ -485,6 +500,9 @@ msgstr "Drtič"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Obrazovka\\Nastavení grafické karty a rozlišení" msgstr "Obrazovka\\Nastavení grafické karty a rozlišení"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Dělení nulou" msgstr "Dělení nulou"
@ -501,6 +519,9 @@ msgstr "Dveře blokuje robot nebo jiný objekt"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Dolů (\\key gdown;)" msgstr "Dolů (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Tužkobot" msgstr "Tužkobot"
@ -528,6 +549,9 @@ msgstr "Vejce"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Chybí konec bloku" msgstr "Chybí konec bloku"
@ -754,6 +778,9 @@ msgstr "Infikováno virem; dočasně mimo provoz"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Komunikační stanice" msgstr "Komunikační stanice"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Příkaz \"break\" mimo cyklus" msgstr "Příkaz \"break\" mimo cyklus"
@ -904,6 +931,15 @@ msgstr "Mise na této planetě:"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Mise\\Vyberte misi" msgstr "Mise\\Vyberte misi"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Vodorovné převrácení posunu\\Při vodorovném posunu kamery myší pousouvat opačným směrem" msgstr "Vodorovné převrácení posunu\\Při vodorovném posunu kamery myší pousouvat opačným směrem"
@ -952,6 +988,12 @@ msgstr "Další objekt\\Vybere následující objekt"
msgid "No" msgid "No"
msgstr "Ne" msgstr "Ne"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Pod povrchem není zdroj energie" msgstr "Pod povrchem není zdroj energie"
@ -1072,6 +1114,9 @@ msgstr "Otevřít"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Otevřít (Ctrl+O)" msgstr "Otevřít (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Chybí levá složená závorka" msgstr "Chybí levá složená závorka"
@ -1282,6 +1327,9 @@ msgstr "Červená vlajka"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Odlesky na tlačítkách\\Blyštivá tlačítka" msgstr "Odlesky na tlačítkách\\Blyštivá tlačítka"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Pozůstatky mise Apollo" msgstr "Pozůstatky mise Apollo"
@ -1543,6 +1591,10 @@ msgstr "Filtrování textur\\Filtrování textur"
msgid "Textures" msgid "Textures"
msgstr "Textury" msgstr "Textury"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "Souboj skončil" msgstr "Souboj skončil"
@ -1555,9 +1607,16 @@ msgstr "Funkce nevrátila žádnou hodnotu"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Mise ještě nebyla splněna (pro podrobnosti stiskněte \\key help;)" msgstr "Mise ještě nebyla splněna (pro podrobnosti stiskněte \\key help;)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Operaci nelze provést s operandy těchto dvou typů" msgstr "Operaci nelze provést s operandy těchto dvou typů"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Tato třída již existuje" msgstr "Tato třída již existuje"
@ -1682,6 +1741,9 @@ msgstr "Jednotka"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Neznámý objekt" msgstr "Neznámý objekt"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Neznámý příkaz" msgstr "Neznámý příkaz"
@ -1694,6 +1756,9 @@ msgstr "Neznámá funkce"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Vzhůru (\\key gup;)" msgstr "Vzhůru (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Uranové ložisko (místo pro vrtnou věž)" msgstr "Uranové ložisko (místo pro vrtnou věž)"
@ -1715,6 +1780,9 @@ msgstr "Proměnná nebyla nastavena"
msgid "Vault" msgid "Vault"
msgstr "Trezor" msgstr "Trezor"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1733,6 +1801,9 @@ msgstr "Vosa byla smrtelně raněna"
msgid "Waste" msgid "Waste"
msgstr "Odpad" msgstr "Odpad"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1766,6 +1837,9 @@ msgstr "Létající detektor"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Vypnout štít (\\key action;)" msgstr "Vypnout štít (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Červ" msgstr "Červ"
@ -1916,6 +1990,9 @@ msgstr "\\Fialové vlajky"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Žluté vlajky" msgstr "\\Žluté vlajky"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"

View File

@ -126,6 +126,9 @@ msgstr "Aussehen\\Erscheinungsbild des Astronauten einstellen"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden" msgstr "Änderungen anwenden\\Getätigte Einstellungen anwenden"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Es gibt keinen geeigneten Konstruktor" msgstr "Es gibt keinen geeigneten Konstruktor"
@ -372,6 +375,9 @@ msgstr "Andere Kamera\\Sichtpunkt einstellen"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Anderer Spieler\\Spielername ändern" msgstr "Anderer Spieler\\Spielername ändern"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Liste der Kapitel:" msgstr "Liste der Kapitel:"
@ -441,6 +447,12 @@ msgstr "Kopieren"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Kopieren (Ctrl+C)" msgstr "Kopieren (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Mission gespeichert" msgstr "Mission gespeichert"
@ -474,6 +486,9 @@ msgstr "Bohrturm"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Sinken\\Leistung des Triebwerks drosseln" msgstr "Sinken\\Leistung des Triebwerks drosseln"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Zerstören" msgstr "Zerstören"
@ -486,6 +501,9 @@ msgstr "Einstampfer"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Bildschirm\\Driver und Bildschirmauflösung" msgstr "Bildschirm\\Driver und Bildschirmauflösung"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Division durch Null" msgstr "Division durch Null"
@ -502,6 +520,9 @@ msgstr "Die Türen werden von einem Gegenstand blockiert"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Sinkt (\\key gdown;)" msgstr "Sinkt (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Zeichner" msgstr "Zeichner"
@ -529,6 +550,9 @@ msgstr "Ei"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)" msgstr "Es fehlt eine geschlossene geschweifte Klammer \"}\" (Ende des Blocks)"
@ -756,6 +780,9 @@ msgstr "Von Virus infiziert, zeitweise außer Betrieb"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Infoserver" msgstr "Infoserver"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Anweisung \"break\" außerhalb einer Schleife" msgstr "Anweisung \"break\" außerhalb einer Schleife"
@ -920,6 +947,15 @@ msgstr "Liste der Missionen des Planeten:"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Missionen\\Aufbruch ins Weltall" msgstr "Missionen\\Aufbruch ins Weltall"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse" msgstr "Umkehr X\\Umkehr der Kameradrehung X-Achse"
@ -968,6 +1004,12 @@ msgstr "Nächstes auswählen\\Nächstes Objekt auswählen"
msgid "No" msgid "No"
msgstr "Nein" msgstr "Nein"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Kein unterirdisches Energievorkommen" msgstr "Kein unterirdisches Energievorkommen"
@ -1088,6 +1130,9 @@ msgstr "Öffnen"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Öffnen (Ctrl+O)" msgstr "Öffnen (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Es fehlt eine offene geschweifte Klammer\"{\"" msgstr "Es fehlt eine offene geschweifte Klammer\"{\""
@ -1299,6 +1344,9 @@ msgstr "Rote Fahne"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Glänzende Tasten\\Glänzende Tasten in den Menüs" msgstr "Glänzende Tasten\\Glänzende Tasten in den Menüs"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Überreste einer Apollo-Mission" msgstr "Überreste einer Apollo-Mission"
@ -1560,6 +1608,10 @@ msgstr "Texturfilterung\\Texturfilterung"
msgid "Textures" msgid "Textures"
msgstr "Texturen" msgstr "Texturen"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "" msgstr ""
@ -1572,9 +1624,16 @@ msgstr "Die Funktion hat kein Ergebnis zurückgegeben"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)" msgstr "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Die zwei Operanden sind nicht kompatibel" msgstr "Die zwei Operanden sind nicht kompatibel"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Diese Klasse gibt es schon" msgstr "Diese Klasse gibt es schon"
@ -1699,6 +1758,9 @@ msgstr "Einheit"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Das Objekt existiert nicht" msgstr "Das Objekt existiert nicht"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Befehl unbekannt" msgstr "Befehl unbekannt"
@ -1711,6 +1773,9 @@ msgstr "Unbekannte Funktion"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Steigt (\\key gup;)" msgstr "Steigt (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Markierung für unterirdisches Platinvorkommen" msgstr "Markierung für unterirdisches Platinvorkommen"
@ -1732,6 +1797,9 @@ msgstr "Der Wert dieser Variable wurde nicht definiert"
msgid "Vault" msgid "Vault"
msgstr "Bunker" msgstr "Bunker"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1750,6 +1818,9 @@ msgstr "Wespe tödlich verwundet"
msgid "Waste" msgid "Waste"
msgstr "Abfall" msgstr "Abfall"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1783,6 +1854,9 @@ msgstr "Schnüffler"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Schutzschild einholen (\\key action;)" msgstr "Schutzschild einholen (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Wurm" msgstr "Wurm"
@ -1931,6 +2005,9 @@ msgstr "\\Violette Fahne"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Gelbe Fahne" msgstr "\\Gelbe Fahne"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"

View File

@ -125,6 +125,9 @@ msgstr "Aspect\\Choisir votre aspect"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Appliquer les changements\\Active les changements effectués" msgstr "Appliquer les changements\\Active les changements effectués"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Constructeur approprié manquant" msgstr "Constructeur approprié manquant"
@ -374,6 +377,9 @@ msgstr "Changement de caméra\\Autre de point de vue"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Autre joueur\\Choix du nom du joueur" msgstr "Autre joueur\\Choix du nom du joueur"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Liste des chapitres :" msgstr "Liste des chapitres :"
@ -443,6 +449,12 @@ msgstr "Copier"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Copier (Ctrl+C)" msgstr "Copier (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Enregistrement effectué" msgstr "Enregistrement effectué"
@ -476,6 +488,9 @@ msgstr "Derrick"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Descendre\\Diminuer la puissance du réacteur" msgstr "Descendre\\Diminuer la puissance du réacteur"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Détruire" msgstr "Détruire"
@ -488,6 +503,9 @@ msgstr "Destructeur"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Affichage\\Pilote et résolution d'affichage" msgstr "Affichage\\Pilote et résolution d'affichage"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Division par zéro" msgstr "Division par zéro"
@ -504,6 +522,9 @@ msgstr "Portes bloquées par un robot ou un objet"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Descend (\\key gdown;)" msgstr "Descend (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Robot dessinateur" msgstr "Robot dessinateur"
@ -531,6 +552,9 @@ msgstr "Oeuf"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Il manque la fin du bloc" msgstr "Il manque la fin du bloc"
@ -758,6 +782,9 @@ msgstr "Infecté par un virus; ne fonctionne plus temporairement"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Station relais" msgstr "Station relais"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Instruction \"break\" en dehors d'une boucle" msgstr "Instruction \"break\" en dehors d'une boucle"
@ -922,6 +949,15 @@ msgstr "Liste des missions du chapitre :"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Missions\\La grande aventure" msgstr "Missions\\La grande aventure"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord" msgstr "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord"
@ -970,6 +1006,12 @@ msgstr "Sélectionner l'objet suivant\\Sélectionner l'objet suivant"
msgid "No" msgid "No"
msgstr "Non" msgstr "Non"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Pas d'énergie en sous-sol" msgstr "Pas d'énergie en sous-sol"
@ -1090,6 +1132,9 @@ msgstr "Ouvrir"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Ouvrir (Ctrl+O)" msgstr "Ouvrir (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Début d'un bloc attendu" msgstr "Début d'un bloc attendu"
@ -1301,6 +1346,9 @@ msgstr "Drapeau rouge"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Reflets sur les boutons\\Boutons brillants" msgstr "Reflets sur les boutons\\Boutons brillants"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Vestige d'une mission Apollo" msgstr "Vestige d'une mission Apollo"
@ -1562,6 +1610,10 @@ msgstr "Filtrage de textures\\Filtrage de textures"
msgid "Textures" msgid "Textures"
msgstr "Textures" msgstr "Textures"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "La bataille est terminée" msgstr "La bataille est terminée"
@ -1574,9 +1626,16 @@ msgstr "La fonction n'a pas retourné de résultat"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "La mission n'est pas terminée (appuyez sur \\key help; pour plus de détails)" msgstr "La mission n'est pas terminée (appuyez sur \\key help; pour plus de détails)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Les deux opérandes ne sont pas de types compatibles" msgstr "Les deux opérandes ne sont pas de types compatibles"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Cette classe existe déjà" msgstr "Cette classe existe déjà"
@ -1701,6 +1760,9 @@ msgstr "Unité"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Objet inconnu" msgstr "Objet inconnu"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Commande inconnue" msgstr "Commande inconnue"
@ -1713,6 +1775,9 @@ msgstr "Routine inconnue"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Monte (\\key gup;)" msgstr "Monte (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Emplacement pour un derrick (minerai d'uranium)" msgstr "Emplacement pour un derrick (minerai d'uranium)"
@ -1734,6 +1799,9 @@ msgstr "Variable non initialisée"
msgid "Vault" msgid "Vault"
msgstr "Coffre-fort" msgstr "Coffre-fort"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher." msgstr "Synchronisation verticale :\\Réduit la fréquence d'images par seconde à afficher."
@ -1752,6 +1820,9 @@ msgstr "Guêpe mortellement touchée"
msgid "Waste" msgid "Waste"
msgstr "Déchet" msgstr "Déchet"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1785,6 +1856,9 @@ msgstr "Robot renifleur volant"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Refermer le bouclier (\\key action;)" msgstr "Refermer le bouclier (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Ver" msgstr "Ver"
@ -1933,6 +2007,9 @@ msgstr "\\Drapeaux violets"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Drapeaux jaunes" msgstr "\\Drapeaux jaunes"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"

View File

@ -124,6 +124,9 @@ msgstr "Wygląd\\Wybierz swoją postać"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia" msgstr "Zastosuj zmiany\\Aktywuje zmienione ustawienia"
msgid "Apply\\Apply the current mod configuration"
msgstr "Zastosuj\\Zastosuj obecną konfigurację modów"
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Brak odpowiedniego konstruktora" msgstr "Brak odpowiedniego konstruktora"
@ -370,6 +373,9 @@ msgstr "Zmień kamerę\\Przełącza pomiędzy kamerą pokładową i śledzącą"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Zmień gracza\\Zmień gracza" msgstr "Zmień gracza\\Zmień gracza"
msgid "Changes"
msgstr "Zmiany"
msgid "Chapters:" msgid "Chapters:"
msgstr "Rozdziały:" msgstr "Rozdziały:"
@ -439,6 +445,12 @@ msgstr "Kopiuj"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Kopiuj (Ctrl+C)" msgstr "Kopiuj (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr "Nie udało się otworzyć przeglądarki plików!"
msgid "Could not open the web browser!"
msgstr "Nie udało się otworzyć przeglądarki internetowej!"
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Bieżąca misja zapisana" msgstr "Bieżąca misja zapisana"
@ -472,6 +484,9 @@ msgstr "Kopalnia"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "W dół\\Zmniejsza moc silnika" msgstr "W dół\\Zmniejsza moc silnika"
msgid "Description:"
msgstr "Opis:"
msgid "Destroy" msgid "Destroy"
msgstr "Zniszcz" msgstr "Zniszcz"
@ -484,6 +499,9 @@ msgstr "Destroyer"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości" msgstr "Urządzenie\\Ustawienia sterownika i rozdzielczości"
msgid "Disable\\Disable the selected mod"
msgstr "Wyłącz\\Wyłącza zaznaczonego moda"
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Dzielenie przez zero" msgstr "Dzielenie przez zero"
@ -500,6 +518,9 @@ msgstr "Drzwi zablokowane przez robota lub inny obiekt"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Dół (\\key gdown;)" msgstr "Dół (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr "W dół\\Przenieś zaznaczonego moda w dół, aby był załadowany później (mody mogą nadpisywać pliki modów wyżej)"
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Robot rysownik" msgstr "Robot rysownik"
@ -527,6 +548,9 @@ msgstr "Jajo"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr "Włącz\\Włącza zaznaczonego moda"
msgid "End of block missing" msgid "End of block missing"
msgstr "Brak końca bloku" msgstr "Brak końca bloku"
@ -753,6 +777,9 @@ msgstr "Zainfekowane wirusem, chwilowo niesprawne"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Stacja przekaźnikowa informacji" msgstr "Stacja przekaźnikowa informacji"
msgid "Information:"
msgstr "Informacje:"
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Polecenie \"break\" na zewnątrz pętli" msgstr "Polecenie \"break\" na zewnątrz pętli"
@ -903,6 +930,15 @@ msgstr "Misje na tej planecie:"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Misje\\Wybierz misję" msgstr "Misje\\Wybierz misję"
msgid "Mods"
msgstr "Mody"
msgid "Mods:"
msgstr "Mody:"
msgid "Mods\\Mod manager"
msgstr "Mody\\Zarządzanie modami"
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie" msgstr "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie"
@ -951,6 +987,12 @@ msgstr "Następny obiekt\\Zaznacza następny obiekt"
msgid "No" msgid "No"
msgstr "Nie" msgstr "Nie"
msgid "No changes."
msgstr "Brak zmian."
msgid "No description."
msgstr "Brak opisu."
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Brak energii w ziemi" msgstr "Brak energii w ziemi"
@ -1071,6 +1113,9 @@ msgstr "Otwórz"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Otwórz (Ctrl+O)" msgstr "Otwórz (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr "Otwórz katalog\\Otwórz katalog z modami"
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Brak klamry otwierającej" msgstr "Brak klamry otwierającej"
@ -1281,6 +1326,9 @@ msgstr "Czerwona flaga"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Odbicia na przyciskach \\Świecące przyciski" msgstr "Odbicia na przyciskach \\Świecące przyciski"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr "Odśwież\\Odśwież listę obecnie zainstalowanych modów"
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Pozostałości z misji Apollo" msgstr "Pozostałości z misji Apollo"
@ -1542,6 +1590,10 @@ msgstr "Filtrowanie tekstur\\Filtrowanie tekstur"
msgid "Textures" msgid "Textures"
msgstr "Tekstury" msgstr "Tekstury"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr "Nie udało się otworzyć adresu %s w przeglądarce internetowej."
msgid "The battle has ended" msgid "The battle has ended"
msgstr "Bitwa zakończyła się" msgstr "Bitwa zakończyła się"
@ -1554,9 +1606,16 @@ msgstr "Funkcja nie zwróciła żadnej wartości"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Misja nie jest wypełniona (naciśnij \\key help; aby uzyskać szczegóły)" msgstr "Misja nie jest wypełniona (naciśnij \\key help; aby uzyskać szczegóły)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr "Nie udało się otworzyć ścieżki %s w przeglądarce plików."
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Niezgodne typy operatorów" msgstr "Niezgodne typy operatorów"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr "Są niezapisane zmiany. Czy chcesz je zapisać przed wyjściem?"
msgid "This class already exists" msgid "This class already exists"
msgstr "Taka klasa już istnieje" msgstr "Taka klasa już istnieje"
@ -1681,6 +1740,9 @@ msgstr "Jednostka"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Obiekt nieznany" msgstr "Obiekt nieznany"
msgid "Unknown author"
msgstr "Nieznany autor"
msgid "Unknown command" msgid "Unknown command"
msgstr "Nieznane polecenie" msgstr "Nieznane polecenie"
@ -1693,6 +1755,9 @@ msgstr "Funkcja nieznana"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Góra (\\key gup;)" msgstr "Góra (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr "W górę\\Przenieś zaznaczonego moda w górę, aby był załadowany wcześniej (mody mogą nadpisywać pliki modów wyżej)"
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Złoże uranu (miejsce na kopalnię)" msgstr "Złoże uranu (miejsce na kopalnię)"
@ -1714,6 +1779,9 @@ msgstr "Zmienna nie została zainicjalizowana"
msgid "Vault" msgid "Vault"
msgstr "Skrytka" msgstr "Skrytka"
msgid "Version"
msgstr "Wersja"
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu" msgstr "Synchronizacja pionowa\\Ogranicza ilość klatek na sekundę do wartości odświeżania ekranu"
@ -1732,6 +1800,9 @@ msgstr "Osa śmiertelnie raniona"
msgid "Waste" msgid "Waste"
msgstr "Odpady" msgstr "Odpady"
msgid "Website"
msgstr "Strona internetowa"
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1765,6 +1836,9 @@ msgstr "Szperacz latający"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Wyłącz osłonę (\\key action;)" msgstr "Wyłącz osłonę (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr "Warsztat\\Otwórz warsztat, aby poszukać modów"
msgid "Worm" msgid "Worm"
msgstr "Robal" msgstr "Robal"
@ -1915,6 +1989,9 @@ msgstr "\\Fioletowe flagi"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Żółte flagi" msgstr "\\Żółte flagi"
msgid "by"
msgstr "autorstwa"
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"

View File

@ -122,6 +122,9 @@ msgstr "Aparência\\Escolha sua aparência"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Aplicar mudanças\\Ativa as configurações alteradas" msgstr "Aplicar mudanças\\Ativa as configurações alteradas"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Construtor apropriado faltando" msgstr "Construtor apropriado faltando"
@ -368,6 +371,9 @@ msgstr "Mudar câmera\\Alterna entre câmera incorporada e câmera seguidora"
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Mudar jogador\\Mudar jogador" msgstr "Mudar jogador\\Mudar jogador"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Capítulos:" msgstr "Capítulos:"
@ -438,6 +444,12 @@ msgstr "Copiar"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Copiar (Ctrl+C)" msgstr "Copiar (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Missão atual salva" msgstr "Missão atual salva"
@ -471,6 +483,9 @@ msgstr "Extrator"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Descer\\Diminui o poder do jato" msgstr "Descer\\Diminui o poder do jato"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Destruir" msgstr "Destruir"
@ -483,6 +498,9 @@ msgstr "Destruidor"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Dispositivo\\Configurações de driver e resolução" msgstr "Dispositivo\\Configurações de driver e resolução"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Dividindo por zero" msgstr "Dividindo por zero"
@ -499,6 +517,9 @@ msgstr "Portas bloqueadas por um robô ou outro objeto"
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Baixo (\\key gdown;)" msgstr "Baixo (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Robô cartoonista" msgstr "Robô cartoonista"
@ -526,6 +547,9 @@ msgstr "Ovo"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Fim do bloco ausente" msgstr "Fim do bloco ausente"
@ -753,6 +777,9 @@ msgstr "Infectado por vírus; temporariamento fora de serviço"
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Posto de troca de informação" msgstr "Posto de troca de informação"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Intrução \"break\" fora de um laço" msgstr "Intrução \"break\" fora de um laço"
@ -917,6 +944,15 @@ msgstr "Lista de missões neste planeta:"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Missões\\Selecione uma missão" msgstr "Missões\\Selecione uma missão"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X" msgstr "Inversão de mouse X\\Inverte a direção da rolagem no eixo X"
@ -965,6 +1001,12 @@ msgstr "Próximo objeto\\Selecionar o próximo objeto"
msgid "No" msgid "No"
msgstr "Não" msgstr "Não"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Nenhuma energia no subsolo" msgstr "Nenhuma energia no subsolo"
@ -1085,6 +1127,9 @@ msgstr "Abrir"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Abrir (Ctrl+O)" msgstr "Abrir (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Chave de abertura ausente" msgstr "Chave de abertura ausente"
@ -1296,6 +1341,9 @@ msgstr "Bandeira vermelha"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Reflexões nos botões\\Botões brilhantes" msgstr "Reflexões nos botões\\Botões brilhantes"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Restos da missão Apollo" msgstr "Restos da missão Apollo"
@ -1557,6 +1605,10 @@ msgstr "Filtragem de textura\\Filtragem de textura"
msgid "Textures" msgid "Textures"
msgstr "Texturas" msgstr "Texturas"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "A batalha acabou" msgstr "A batalha acabou"
@ -1569,9 +1621,16 @@ msgstr "A função não retornou nenhum valor"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "A missão não foi completada ainda (pressione \\key help; para mais detalhes)" msgstr "A missão não foi completada ainda (pressione \\key help; para mais detalhes)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Os tipos dos dois operandos são incompativeis" msgstr "Os tipos dos dois operandos são incompativeis"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Esta classe já existe" msgstr "Esta classe já existe"
@ -1696,6 +1755,9 @@ msgstr "Unidade"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Objeto desconhecido" msgstr "Objeto desconhecido"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Comando desconhecido" msgstr "Comando desconhecido"
@ -1708,6 +1770,9 @@ msgstr "Função desconhecida"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Cima (\\key gup;)" msgstr "Cima (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Depósito de urânio (local para extrator)" msgstr "Depósito de urânio (local para extrator)"
@ -1729,6 +1794,9 @@ msgstr "Variável não inicializada"
msgid "Vault" msgid "Vault"
msgstr "Cofre" msgstr "Cofre"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1747,6 +1815,9 @@ msgstr "Vespa fatalmente ferida"
msgid "Waste" msgid "Waste"
msgstr "Desperdício" msgstr "Desperdício"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1780,6 +1851,9 @@ msgstr "Farejador alado"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Retirar escudo (\\key action;)" msgstr "Retirar escudo (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Verme" msgstr "Verme"
@ -1928,6 +2002,9 @@ msgstr "\\Bandeiras violetas"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Bandeiras amarelas" msgstr "\\Bandeiras amarelas"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"

View File

@ -124,6 +124,9 @@ msgstr "Внешность\\Настройка внешности"
msgid "Apply changes\\Activates the changed settings" msgid "Apply changes\\Activates the changed settings"
msgstr "Принять\\Принять изменения настроек" msgstr "Принять\\Принять изменения настроек"
msgid "Apply\\Apply the current mod configuration"
msgstr ""
msgid "Appropriate constructor missing" msgid "Appropriate constructor missing"
msgstr "Соответствующий конструктор отсутствует" msgstr "Соответствующий конструктор отсутствует"
@ -375,6 +378,9 @@ msgstr "Изменить вид\\Переключение между борто
msgid "Change player\\Change player" msgid "Change player\\Change player"
msgstr "Новый игрок\\Выберите имя для игрока" msgstr "Новый игрок\\Выберите имя для игрока"
msgid "Changes"
msgstr ""
msgid "Chapters:" msgid "Chapters:"
msgstr "Разделы:" msgstr "Разделы:"
@ -446,6 +452,12 @@ msgstr "Копировать"
msgid "Copy (Ctrl+C)" msgid "Copy (Ctrl+C)"
msgstr "Копировать (Ctrl+C)" msgstr "Копировать (Ctrl+C)"
msgid "Could not open the file explorer!"
msgstr ""
msgid "Could not open the web browser!"
msgstr ""
msgid "Current mission saved" msgid "Current mission saved"
msgstr "Текущая миссия сохранена" msgstr "Текущая миссия сохранена"
@ -480,6 +492,9 @@ msgstr "Космический корабль"
msgid "Descend\\Reduces the power of the jet" msgid "Descend\\Reduces the power of the jet"
msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя" msgstr "Снижение и посадка\\Понижение мощности реактивного двигателя"
msgid "Description:"
msgstr ""
msgid "Destroy" msgid "Destroy"
msgstr "Уничтожить" msgstr "Уничтожить"
@ -492,6 +507,9 @@ msgstr "Уничтожитель"
msgid "Device\\Driver and resolution settings" msgid "Device\\Driver and resolution settings"
msgstr "Устройство\\Драйвер и настройки разрешения" msgstr "Устройство\\Драйвер и настройки разрешения"
msgid "Disable\\Disable the selected mod"
msgstr ""
msgid "Dividing by zero" msgid "Dividing by zero"
msgstr "Деление на ноль (запрещено!)" msgstr "Деление на ноль (запрещено!)"
@ -508,6 +526,9 @@ msgstr "Двери заблокированы роботом или другим
msgid "Down (\\key gdown;)" msgid "Down (\\key gdown;)"
msgstr "Вниз (\\key gdown;)" msgstr "Вниз (\\key gdown;)"
msgid "Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Drawer bot" msgid "Drawer bot"
msgstr "Рисовальщик" msgstr "Рисовальщик"
@ -535,6 +556,9 @@ msgstr "Яйцо"
msgid "Empty character constant" msgid "Empty character constant"
msgstr "" msgstr ""
msgid "Enable\\Enable the selected mod"
msgstr ""
msgid "End of block missing" msgid "End of block missing"
msgstr "Отсутствует конец блока" msgstr "Отсутствует конец блока"
@ -762,6 +786,9 @@ msgstr "Заражено вирусом. Временно вышел из стр
msgid "Information exchange post" msgid "Information exchange post"
msgstr "Пост обмена информацией" msgstr "Пост обмена информацией"
msgid "Information:"
msgstr ""
msgid "Instruction \"break\" outside a loop" msgid "Instruction \"break\" outside a loop"
msgstr "Инструкция \"break\" вне цикла" msgstr "Инструкция \"break\" вне цикла"
@ -926,6 +953,15 @@ msgstr "Миссии на этой планете:"
msgid "Missions\\Select mission" msgid "Missions\\Select mission"
msgstr "Миссии\\Выбор миссии" msgstr "Миссии\\Выбор миссии"
msgid "Mods"
msgstr ""
msgid "Mods:"
msgstr ""
msgid "Mods\\Mod manager"
msgstr ""
msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis" msgid "Mouse inversion X\\Inversion of the scrolling direction on the X axis"
msgstr "Инверсия мыши по оси X\\Инверсия прокрутки по оси Х" msgstr "Инверсия мыши по оси X\\Инверсия прокрутки по оси Х"
@ -976,6 +1012,12 @@ msgstr "Следующий объект\\Выбор следующего объ
msgid "No" msgid "No"
msgstr "Нет" msgstr "Нет"
msgid "No changes."
msgstr ""
msgid "No description."
msgstr ""
msgid "No energy in the subsoil" msgid "No energy in the subsoil"
msgstr "Под землей нет запасов энергии" msgstr "Под землей нет запасов энергии"
@ -1096,6 +1138,9 @@ msgstr "Открыть"
msgid "Open (Ctrl+O)" msgid "Open (Ctrl+O)"
msgstr "Открыть (Ctrl+O)" msgstr "Открыть (Ctrl+O)"
msgid "Open Directory\\Open the mods directory"
msgstr ""
msgid "Opening brace missing" msgid "Opening brace missing"
msgstr "Открывающая скобка отсутствует" msgstr "Открывающая скобка отсутствует"
@ -1308,6 +1353,9 @@ msgstr "Красный флаг"
msgid "Reflections on the buttons \\Shiny buttons" msgid "Reflections on the buttons \\Shiny buttons"
msgstr "Отражения на кнопках \\Блестящие кнопки" msgstr "Отражения на кнопках \\Блестящие кнопки"
msgid "Refresh\\Refresh the list of currently installed mods"
msgstr ""
msgid "Remains of Apollo mission" msgid "Remains of Apollo mission"
msgstr "Остатки миссии Аполлон" msgstr "Остатки миссии Аполлон"
@ -1573,6 +1621,10 @@ msgstr "Фильтрация текстур\\Фильтрация текстур
msgid "Textures" msgid "Textures"
msgstr "Текстуры" msgstr "Текстуры"
#, c-format
msgid "The address %s could not be opened in a web browser."
msgstr ""
msgid "The battle has ended" msgid "The battle has ended"
msgstr "" msgstr ""
@ -1585,9 +1637,16 @@ msgstr "Функция не возвратила значения"
msgid "The mission is not accomplished yet (press \\key help; for more details)" msgid "The mission is not accomplished yet (press \\key help; for more details)"
msgstr "Миссия еще не выполнена (нажмите \\key help; для более подробной информации)" msgstr "Миссия еще не выполнена (нажмите \\key help; для более подробной информации)"
#, c-format
msgid "The path %s could not be opened in a file explorer."
msgstr ""
msgid "The types of the two operands are incompatible" msgid "The types of the two operands are incompatible"
msgstr "Типы операндов несовместимы" msgstr "Типы операндов несовместимы"
msgid "There are unsaved changes. Do you want to save them before leaving?"
msgstr ""
msgid "This class already exists" msgid "This class already exists"
msgstr "Этот класс уже существует" msgstr "Этот класс уже существует"
@ -1712,6 +1771,9 @@ msgstr "Юнит"
msgid "Unknown Object" msgid "Unknown Object"
msgstr "Неизвестный объект" msgstr "Неизвестный объект"
msgid "Unknown author"
msgstr ""
msgid "Unknown command" msgid "Unknown command"
msgstr "Неизвестная команда" msgstr "Неизвестная команда"
@ -1724,6 +1786,9 @@ msgstr "Неизвестная функция"
msgid "Up (\\key gup;)" msgid "Up (\\key gup;)"
msgstr "Вверх (\\key gup;)" msgstr "Вверх (\\key gup;)"
msgid "Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)"
msgstr ""
msgid "Uranium deposit (site for derrick)" msgid "Uranium deposit (site for derrick)"
msgstr "Запасы урана (место для буровой вышки)" msgstr "Запасы урана (место для буровой вышки)"
@ -1745,6 +1810,9 @@ msgstr "Переменная не инициализирована"
msgid "Vault" msgid "Vault"
msgstr "Хранилище" msgstr "Хранилище"
msgid "Version"
msgstr ""
msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency" msgid "Vertical Synchronization\\Limits the number of frames per second to display frequency"
msgstr "" msgstr ""
@ -1763,6 +1831,9 @@ msgstr "Оса смертельно ранена"
msgid "Waste" msgid "Waste"
msgstr "Мусор" msgstr "Мусор"
msgid "Website"
msgstr ""
msgid "Wheeled builder" msgid "Wheeled builder"
msgstr "" msgstr ""
@ -1796,6 +1867,9 @@ msgstr "Летающий искатель"
msgid "Withdraw shield (\\key action;)" msgid "Withdraw shield (\\key action;)"
msgstr "Снять щит (\\key action;)" msgstr "Снять щит (\\key action;)"
msgid "Workshop\\Open the workshop to search for mods"
msgstr ""
msgid "Worm" msgid "Worm"
msgstr "Червь" msgstr "Червь"
@ -1944,6 +2018,9 @@ msgstr "\\Фиолетовый флаг"
msgid "\\Yellow flags" msgid "\\Yellow flags"
msgstr "\\Желтый флаг" msgstr "\\Желтый флаг"
msgid "by"
msgstr ""
msgid "colobot.info" msgid "colobot.info"
msgstr "colobot.info" msgstr "colobot.info"

View File

@ -145,6 +145,8 @@ set(BASE_SOURCES
app/controller.h app/controller.h
app/input.cpp app/input.cpp
app/input.h app/input.h
app/modman.cpp
app/modman.h
app/pathman.cpp app/pathman.cpp
app/pathman.h app/pathman.h
app/pausemanager.cpp app/pausemanager.cpp
@ -568,6 +570,8 @@ set(BASE_SOURCES
ui/screen/screen_loading.h ui/screen/screen_loading.h
ui/screen/screen_main_menu.cpp ui/screen/screen_main_menu.cpp
ui/screen/screen_main_menu.h ui/screen/screen_main_menu.h
ui/screen/screen_mod_list.cpp
ui/screen/screen_mod_list.h
ui/screen/screen_player_select.cpp ui/screen/screen_player_select.cpp
ui/screen/screen_player_select.h ui/screen/screen_player_select.h
ui/screen/screen_quit.cpp ui/screen/screen_quit.cpp

View File

@ -21,6 +21,7 @@
#include "app/controller.h" #include "app/controller.h"
#include "app/input.h" #include "app/input.h"
#include "app/modman.h"
#include "app/pathman.h" #include "app/pathman.h"
#include "common/config_file.h" #include "common/config_file.h"
@ -113,7 +114,8 @@ CApplication::CApplication(CSystemUtils* systemUtils)
m_private(MakeUnique<ApplicationPrivate>()), m_private(MakeUnique<ApplicationPrivate>()),
m_configFile(MakeUnique<CConfigFile>()), m_configFile(MakeUnique<CConfigFile>()),
m_input(MakeUnique<CInput>()), m_input(MakeUnique<CInput>()),
m_pathManager(MakeUnique<CPathManager>(systemUtils)) m_pathManager(MakeUnique<CPathManager>(systemUtils)),
m_modManager(MakeUnique<CModManager>(this, m_pathManager.get()))
{ {
m_exitCode = 0; m_exitCode = 0;
m_active = false; m_active = false;
@ -220,6 +222,11 @@ CSoundInterface* CApplication::GetSound()
return m_sound.get(); return m_sound.get();
} }
CModManager* CApplication::GetModManager()
{
return m_modManager.get();
}
void CApplication::LoadEnvironmentVariables() void CApplication::LoadEnvironmentVariables()
{ {
auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR"); auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR");
@ -513,6 +520,10 @@ bool CApplication::Create()
GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); GetLogger()->Warn("Config could not be loaded. Default values will be used!\n");
} }
m_modManager->FindMods();
m_modManager->SaveMods();
m_modManager->MountAllMods();
// Create the sound instance. // Create the sound instance.
#ifdef OPENAL_SOUND #ifdef OPENAL_SOUND
if (!m_headless) if (!m_headless)
@ -698,21 +709,7 @@ bool CApplication::Create()
// Create the robot application. // Create the robot application.
m_controller = MakeUnique<CController>(); m_controller = MakeUnique<CController>();
CThread musicLoadThread([this]() StartLoadingMusic();
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
if (m_runSceneCategory == LevelCategory::Max) if (m_runSceneCategory == LevelCategory::Max)
m_controller->StartApp(); m_controller->StartApp();
@ -726,6 +723,15 @@ bool CApplication::Create()
return true; return true;
} }
void CApplication::ReloadResources()
{
GetLogger()->Info("Reloading resources\n");
m_engine->ReloadAllTextures();
StartLoadingMusic();
m_controller->GetRobotMain()->UpdateCustomLevelList();
}
bool CApplication::CreateVideoSurface() bool CApplication::CreateVideoSurface()
{ {
Uint32 videoFlags = SDL_WINDOW_OPENGL; Uint32 videoFlags = SDL_WINDOW_OPENGL;
@ -1537,6 +1543,26 @@ void CApplication::InternalResumeSimulation()
m_absTimeBase = m_exactAbsTime; m_absTimeBase = m_exactAbsTime;
} }
void CApplication::StartLoadingMusic()
{
CThread musicLoadThread([this]()
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->Reset();
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
}
bool CApplication::GetSimulationSuspended() const bool CApplication::GetSimulationSuspended() const
{ {
return m_simulationSuspended; return m_simulationSuspended;

View File

@ -42,6 +42,7 @@ class CEventQueue;
class CController; class CController;
class CSoundInterface; class CSoundInterface;
class CInput; class CInput;
class CModManager;
class CPathManager; class CPathManager;
class CConfigFile; class CConfigFile;
class CSystemUtils; class CSystemUtils;
@ -162,6 +163,8 @@ public:
CEventQueue* GetEventQueue(); CEventQueue* GetEventQueue();
//! Returns the sound subsystem //! Returns the sound subsystem
CSoundInterface* GetSound(); CSoundInterface* GetSound();
//! Returns the mod manager
CModManager* GetModManager();
public: public:
//! Loads some data from environment variables //! Loads some data from environment variables
@ -170,6 +173,8 @@ public:
ParseArgsStatus ParseArguments(int argc, char *argv[]); ParseArgsStatus ParseArguments(int argc, char *argv[]);
//! Initializes the application //! Initializes the application
bool Create(); bool Create();
//! Reloads the application resources, e.g. mods
void ReloadResources();
//! Main event loop //! Main event loop
int Run(); int Run();
//! Returns the code to be returned at main() exit //! Returns the code to be returned at main() exit
@ -301,6 +306,9 @@ protected:
//! Internal procedure to reset time counters //! Internal procedure to reset time counters
void InternalResumeSimulation(); void InternalResumeSimulation();
//! Loads music in a new thread
void StartLoadingMusic();
protected: protected:
//! System utils instance //! System utils instance
CSystemUtils* m_systemUtils; CSystemUtils* m_systemUtils;
@ -322,6 +330,8 @@ protected:
std::unique_ptr<CInput> m_input; std::unique_ptr<CInput> m_input;
//! Path manager //! Path manager
std::unique_ptr<CPathManager> m_pathManager; std::unique_ptr<CPathManager> m_pathManager;
//! Mod manager
std::unique_ptr<CModManager> m_modManager;
//! Code to return at exit //! Code to return at exit
int m_exitCode; int m_exitCode;

358
src/app/modman.cpp Normal file
View File

@ -0,0 +1,358 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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://gnu.org/licenses
*/
#include "app/modman.h"
#include "common/config.h"
#include "app/app.h"
#include "app/pathman.h"
#include "common/config_file.h"
#include "common/logger.h"
#include "common/resources/resourcemanager.h"
#include "level/parser/parser.h"
#include <algorithm>
#include <map>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost::filesystem;
CModManager::CModManager(CApplication* app, CPathManager* pathManager)
: m_app{app},
m_pathManager{pathManager}
{
}
void CModManager::FindMods()
{
m_mods.clear();
m_userChanges = false;
// Load names from the config file
std::vector<std::string> savedModNames;
GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames);
std::vector<bool> savedEnabled;
GetConfigFile().GetArrayProperty("Mods", "Enabled", savedEnabled);
// Transform the data into Mod structures
m_mods.reserve(savedModNames.size());
for (size_t i = 0; i < savedModNames.size(); ++i)
{
Mod mod{};
mod.name = savedModNames[i];
if (i < savedEnabled.size())
{
mod.enabled = savedEnabled[i];
}
mod.path = ""; // Find the path later
m_mods.push_back(mod);
}
// Search the folders for mods
auto rawPaths = m_pathManager->FindMods();
std::map<std::string, std::string> modPaths;
for (const auto& path : rawPaths)
{
auto modName = boost::filesystem::path(path).stem().string();
modPaths.insert(std::make_pair(modName, path));
}
// Find paths for already saved mods
auto it = m_mods.begin();
while (it != m_mods.end())
{
auto& mod = *it;
const auto pathsIt = modPaths.find(mod.name);
if (pathsIt != modPaths.end())
{
mod.path = (*pathsIt).second;
modPaths.erase(pathsIt);
++it;
}
else
{
GetLogger()->Warn("Could not find mod %s, removing it from the list\n", mod.name.c_str());
it = m_mods.erase(it);
}
}
// Add the remaining found mods to the end of the list
for (const auto& newMod : modPaths)
{
Mod mod{};
mod.name = newMod.first;
mod.path = newMod.second;
m_mods.push_back(mod);
}
// Load the metadata for each mod
// Unfortunately, the paths are distinguished by their real paths, not mount points
// So we must unmount mods temporarily
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
for (auto& mod : m_mods)
{
MountMod(mod, "/temp/mod");
LoadModData(mod);
UnmountMod(mod);
}
// Mount back
for (const auto& path : m_mountedModPaths)
{
MountMod(path);
}
}
void CModManager::ReloadMods()
{
UnmountAllMountedMods();
MountAllMods();
ReloadResources();
}
void CModManager::EnableMod(size_t i)
{
m_mods[i].enabled = true;
m_userChanges = true;
}
void CModManager::DisableMod(size_t i)
{
m_mods[i].enabled = false;
m_userChanges = true;
}
size_t CModManager::MoveUp(size_t i)
{
if (i != 0)
{
std::swap(m_mods[i - 1], m_mods[i]);
m_userChanges = true;
return i - 1;
}
else
{
return i;
}
}
size_t CModManager::MoveDown(size_t i)
{
if (i != m_mods.size() - 1)
{
std::swap(m_mods[i], m_mods[i + 1]);
m_userChanges = true;
return i + 1;
}
else
{
return i;
}
}
bool CModManager::Changes()
{
std::vector<std::string> paths;
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
paths.push_back(mod.path);
}
}
return paths != m_mountedModPaths || m_userChanges;
}
void CModManager::MountAllMods()
{
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
MountMod(mod);
m_mountedModPaths.push_back(mod.path);
}
}
}
void CModManager::ReloadResources()
{
m_app->ReloadResources();
}
void CModManager::SaveMods()
{
std::vector<std::string> savedNames;
savedNames.reserve(m_mods.size());
std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedNames), [](const Mod& mod) { return mod.name; });
GetConfigFile().SetArrayProperty("Mods", "Names", savedNames);
std::vector<bool> savedEnabled;
savedEnabled.reserve(m_mods.size());
std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedEnabled), [](const Mod& mod) { return mod.enabled; });
GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled);
GetConfigFile().Save();
m_userChanges = false;
}
size_t CModManager::CountMods() const
{
return m_mods.size();
}
const Mod& CModManager::GetMod(size_t i) const
{
return m_mods[i];
}
const std::vector<Mod>& CModManager::GetMods() const
{
return m_mods;
}
void CModManager::LoadModData(Mod& mod)
{
auto& data = mod.data;
data.displayName = mod.name;
try
{
CLevelParser levelParser("temp/mod/manifest.txt");
if (levelParser.Exists())
{
levelParser.Load();
CLevelParserLine* line = nullptr;
// DisplayName
line = levelParser.GetIfDefined("DisplayName");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.displayName = line->GetParam("text")->AsString();
}
// Author
line = levelParser.GetIfDefined("Author");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.author = line->GetParam("text")->AsString();
}
// Version
line = levelParser.GetIfDefined("Version");
if (line != nullptr)
{
if (line->GetParam("text")->IsDefined())
{
data.version = line->GetParam("text")->AsString();
}
else if (line->GetParam("major")->IsDefined() && line->GetParam("minor")->IsDefined() && line->GetParam("patch")->IsDefined())
{
auto major = boost::lexical_cast<std::string>(line->GetParam("major")->AsInt());
auto minor = boost::lexical_cast<std::string>(line->GetParam("minor")->AsInt());
auto patch = boost::lexical_cast<std::string>(line->GetParam("patch")->AsInt());
data.version = boost::algorithm::join(std::vector<std::string>{ major, minor, patch }, ".");
}
}
// Website
line = levelParser.GetIfDefined("Website");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.website = line->GetParam("text")->AsString();
}
// Summary
line = levelParser.GetIfDefined("Summary");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.summary = line->GetParam("text")->AsString();
}
}
else
{
GetLogger()->Warn("No manifest file for mod %s\n", mod.name.c_str());
}
}
catch (CLevelParserException& e)
{
GetLogger()->Warn("Failed parsing manifest for mod %s: %s\n", mod.name.c_str(), e.what());
}
// Changes
data.changes = CResourceManager::ListDirectories("temp/mod");
auto levelsIt = std::find(data.changes.begin(), data.changes.end(), "levels");
if (levelsIt != data.changes.end())
{
auto levelsDirs = CResourceManager::ListDirectories("temp/mod/levels");
if (!levelsDirs.empty())
{
std::transform(levelsDirs.begin(), levelsDirs.end(), levelsDirs.begin(), [](const std::string& dir) { return "levels/" + dir; });
levelsIt = data.changes.erase(levelsIt);
data.changes.insert(levelsIt, levelsDirs.begin(), levelsDirs.end());
}
}
}
void CModManager::MountMod(const Mod& mod, const std::string& mountPoint)
{
MountMod(mod.path, mountPoint);
}
void CModManager::MountMod(const std::string& path, const std::string& mountPoint)
{
GetLogger()->Debug("Mounting mod: '%s' at path %s\n", path.c_str(), mountPoint.c_str());
CResourceManager::AddLocation(path, true, mountPoint);
}
void CModManager::UnmountMod(const Mod& mod)
{
UnmountMod(mod.path);
}
void CModManager::UnmountMod(const std::string& path)
{
if (CResourceManager::LocationExists(path))
{
GetLogger()->Debug("Unmounting mod: '%s'\n", path.c_str());
CResourceManager::RemoveLocation(path);
}
}
void CModManager::UnmountAllMountedMods()
{
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
m_mountedModPaths.clear();
}

124
src/app/modman.h Normal file
View File

@ -0,0 +1,124 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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://gnu.org/licenses
*/
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
class CApplication;
class CPathManager;
struct ModData
{
std::string displayName{};
std::string author{};
std::string version{};
std::string website{};
std::string summary{};
std::vector<std::string> changes{};
};
struct Mod
{
std::string name{};
std::string path{};
bool enabled = false;
ModData data{};
};
/**
* \class CModManager
* \brief This class handles the list of mods.
*
* The order matters since the order in which files are loaded matters,
* because some files can be overwritten.
*
* The changes in the list do not immediately apply.
*/
class CModManager
{
public:
CModManager(CApplication* app, CPathManager* pathManager);
//! Finds all the mods along with their metadata
void FindMods();
//! Applies the current configuration and reloads the application
void ReloadMods();
//! Removes a mod from the list of loaded mods
void EnableMod(size_t i);
//! Adds a mod to the list of loaded mods
void DisableMod(size_t i);
//! Moves the selected mod up in the list so that it's loaded sooner than others, returns the new index
size_t MoveUp(size_t i);
//! Moves the selected mod down in the list so that it's loaded later than others, returns the new index
size_t MoveDown(size_t i);
//! Checks if the list of currently used mods differs from the current configuration or there were changes made by the user
bool Changes();
//! Saves the current configuration of mods to the config file
void SaveMods();
//! Number of mods loaded
size_t CountMods() const;
//! Returns the reference to the mod in given position
const Mod& GetMod(size_t i) const;
//! Returns the list of mods
const std::vector<Mod>& GetMods() const;
private:
// Allow access to MountAllMods() as CApplication doesn't want to reload itself during initialization
friend CApplication;
//! Reloads application resources so the enabled mods are applied
void ReloadResources();
//! Load mod data into mod
void LoadModData(Mod& mod);
//! Updates the paths in Path Manager according to the current mod configuration
void MountAllMods();
void MountMod(const Mod& mod, const std::string& mountPoint = "");
void MountMod(const std::string& path, const std::string& mountPoint = "");
void UnmountMod(const Mod& mod);
void UnmountMod(const std::string& path);
void UnmountAllMountedMods();
private:
CApplication* m_app;
CPathManager* m_pathManager;
//! Paths to mods already in the virtual filesystem
std::vector<std::string> m_mountedModPaths;
//! List of mods
std::vector<Mod> m_mods;
bool m_userChanges = false;
};

View File

@ -41,8 +41,7 @@ CPathManager::CPathManager(CSystemUtils* systemUtils)
: m_dataPath(systemUtils->GetDataPath()) : m_dataPath(systemUtils->GetDataPath())
, m_langPath(systemUtils->GetLangPath()) , m_langPath(systemUtils->GetLangPath())
, m_savePath(systemUtils->GetSaveDir()) , m_savePath(systemUtils->GetSaveDir())
, m_modAutoloadDir{} , m_modSearchDirs{}
, m_mods{}
{ {
} }
@ -65,16 +64,6 @@ void CPathManager::SetSavePath(const std::string &savePath)
m_savePath = savePath; m_savePath = savePath;
} }
void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath)
{
m_modAutoloadDir.push_back(modAutoloadDirPath);
}
void CPathManager::AddMod(const std::string &modPath)
{
m_mods.push_back(modPath);
}
const std::string& CPathManager::GetDataPath() const std::string& CPathManager::GetDataPath()
{ {
return m_dataPath; return m_dataPath;
@ -131,40 +120,18 @@ void CPathManager::InitPaths()
GetLogger()->Info("Data path: %s\n", m_dataPath.c_str()); GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
GetLogger()->Info("Save path: %s\n", m_savePath.c_str()); GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
m_modAutoloadDir.push_back(m_dataPath + "/mods"); m_modSearchDirs.push_back(m_dataPath + "/mods");
m_modAutoloadDir.push_back(m_savePath + "/mods"); m_modSearchDirs.push_back(m_savePath + "/mods");
if (!m_modAutoloadDir.empty()) if (!m_modSearchDirs.empty())
{ {
GetLogger()->Info("Mod autoload dirs:\n"); GetLogger()->Info("Mod search dirs:\n");
for(const std::string& modAutoloadDir : m_modAutoloadDir) for(const std::string& modSearchDir : m_modSearchDirs)
GetLogger()->Info(" * %s\n", modAutoloadDir.c_str()); GetLogger()->Info(" * %s\n", modSearchDir.c_str());
}
if (!m_mods.empty())
{
GetLogger()->Info("Mods:\n");
for(const std::string& modPath : m_mods)
GetLogger()->Info(" * %s\n", modPath.c_str());
} }
CResourceManager::AddLocation(m_dataPath); CResourceManager::AddLocation(m_dataPath);
for (const std::string& modAutoloadDir : m_modAutoloadDir)
{
GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str());
for (const std::string& modPath : FindModsInDir(modAutoloadDir))
{
GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath);
}
}
for (const std::string& modPath : m_mods)
{
GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath);
}
CResourceManager::SetSaveLocation(m_savePath); CResourceManager::SetSaveLocation(m_savePath);
CResourceManager::AddLocation(m_savePath); CResourceManager::AddLocation(m_savePath);
@ -174,7 +141,45 @@ void CPathManager::InitPaths()
GetLogger()->Debug(" * %s\n", path.c_str()); GetLogger()->Debug(" * %s\n", path.c_str());
} }
std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) void CPathManager::AddMod(const std::string &path)
{
m_mods.push_back(path);
}
std::vector<std::string> CPathManager::FindMods() const
{
std::vector<std::string> mods;
GetLogger()->Info("Found mods:\n");
for (const auto &searchPath : m_modSearchDirs)
{
for (const auto &modPath : FindModsInDir(searchPath))
{
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
}
GetLogger()->Info("Additional mod paths:\n");
for (const auto& modPath : m_mods)
{
if (boost::filesystem::exists(modPath))
{
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
else
{
GetLogger()->Warn("Mod does not exist: %s\n", modPath.c_str());
}
}
return mods;
}
void CPathManager::AddModSearchDir(const std::string &modSearchDirPath)
{
m_modSearchDirs.push_back(modSearchDirPath);
}
std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) const
{ {
std::vector<std::string> ret; std::vector<std::string> ret;
try try

View File

@ -37,8 +37,6 @@ public:
void SetDataPath(const std::string &dataPath); void SetDataPath(const std::string &dataPath);
void SetLangPath(const std::string &langPath); void SetLangPath(const std::string &langPath);
void SetSavePath(const std::string &savePath); void SetSavePath(const std::string &savePath);
void AddModAutoloadDir(const std::string &modAutoloadDirPath);
void AddMod(const std::string &modPath);
const std::string& GetDataPath(); const std::string& GetDataPath();
const std::string& GetLangPath(); const std::string& GetLangPath();
@ -49,9 +47,15 @@ public:
//! Loads configured paths //! Loads configured paths
void InitPaths(); void InitPaths();
//! Adds a path to a mod
void AddMod(const std::string& path);
//! Find paths to mods in mod search directories
std::vector<std::string> FindMods() const;
//! Adds a mod search directory
void AddModSearchDir(const std::string &modSearchDirPath);
private: private:
//! Loads all mods from given directory std::vector<std::string> FindModsInDir(const std::string &dir) const;
std::vector<std::string> FindModsInDir(const std::string &dir);
private: private:
//! Data path //! Data path
@ -60,8 +64,8 @@ private:
std::string m_langPath; std::string m_langPath;
//! Save path //! Save path
std::string m_savePath; std::string m_savePath;
//! Mod autoload paths //! Mod search paths
std::vector<std::string> m_modAutoloadDir; std::vector<std::string> m_modSearchDirs;
//! Mod paths //! Additional mod paths
std::vector<std::string> m_mods; std::vector<std::string> m_mods;
}; };

View File

@ -26,9 +26,15 @@
#include "common/singleton.h" #include "common/singleton.h"
#include "common/logger.h"
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/lexical_cast.hpp>
#include <string> #include <string>
#include <sstream>
#include <vector>
#include <stdexcept>
/** /**
@ -100,6 +106,76 @@ public:
*/ */
bool GetBoolProperty(std::string section, std::string key, bool &value); bool GetBoolProperty(std::string section, std::string key, bool &value);
/** Gets an array of values of type T in section under specified key
* The value separator is ','.
* \a array will only be changed if key exists
* \return return true on success
*/
template<typename T>
bool SetArrayProperty(std::string section, std::string key, const std::vector<T>& array)
{
try
{
std::string convertedValue = ArrayToString(array);
m_propertyTree.put(section + "." + key, convertedValue);
m_needsSave = true;
}
catch (std::exception & e)
{
GetLogger()->Error("Error on editing config file: %s\n", e.what());
return false;
}
return true;
}
/** Sets an array of values of type T in section under specified key.
* The value separator is ','.
* \a array will only be changed if key exists
* \return return true on success
*/
template<typename T>
bool GetArrayProperty(std::string section, std::string key, std::vector<T>& array)
{
try
{
std::string readValue = m_propertyTree.get<std::string>(section + "." + key);
std::vector<T> convertedValue = StringToArray<T>(readValue);
array = std::move(convertedValue);
}
catch (std::exception & e)
{
GetLogger()->Log(m_loaded ? LOG_INFO : LOG_TRACE, "Error on parsing config file: %s\n", e.what());
return false;
}
return true;
}
private:
template<typename T>
std::vector<T> StringToArray(const std::string& s)
{
std::vector<T> result;
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, ','))
{
result.push_back(boost::lexical_cast<T>(item));
}
return result;
}
template<typename T>
std::string ArrayToString(const std::vector<T> &array)
{
std::ostringstream oss;
if (!array.empty())
{
std::copy(array.begin(), array.end() - 1, std::ostream_iterator<T>(oss, ","));
oss << array.back();
}
return oss.str();
}
private: private:
boost::property_tree::ptree m_propertyTree; boost::property_tree::ptree m_propertyTree;
bool m_needsSave; bool m_needsSave;

View File

@ -190,6 +190,7 @@ void InitializeEventTypeTexts()
EVENT_TYPE_TEXT[EVENT_INTERFACE_ABORT] = "EVENT_INTERFACE_ABORT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_ABORT] = "EVENT_INTERFACE_ABORT";
EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER"; EVENT_TYPE_TEXT[EVENT_INTERFACE_USER] = "EVENT_INTERFACE_USER";
EVENT_TYPE_TEXT[EVENT_INTERFACE_SATCOM] = "EVENT_INTERFACE_SATCOM"; EVENT_TYPE_TEXT[EVENT_INTERFACE_SATCOM] = "EVENT_INTERFACE_SATCOM";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS] = "EVENT_INTERFACE_MODS";
EVENT_TYPE_TEXT[EVENT_INTERFACE_CHAP] = "EVENT_INTERFACE_CHAP"; EVENT_TYPE_TEXT[EVENT_INTERFACE_CHAP] = "EVENT_INTERFACE_CHAP";
EVENT_TYPE_TEXT[EVENT_INTERFACE_LIST] = "EVENT_INTERFACE_LIST"; EVENT_TYPE_TEXT[EVENT_INTERFACE_LIST] = "EVENT_INTERFACE_LIST";
@ -272,6 +273,16 @@ void InitializeEventTypeTexts()
EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT";
EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT"; EVENT_TYPE_TEXT[EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT]= "EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_LIST] = "EVENT_INTERFACE_MOD_LIST";
EVENT_TYPE_TEXT[EVENT_INTERFACE_WORKSHOP] = "EVENT_INTERFACE_WORKSHOP";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_DIR] = "EVENT_INTERFACE_MODS_DIR";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE] = "EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_APPLY] = "EVENT_INTERFACE_MODS_APPLY";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_DETAILS] = "EVENT_INTERFACE_MOD_DETAILS";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_MOVE_UP] = "EVENT_INTERFACE_MOD_MOVE_UP";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MOD_MOVE_DOWN] = "EVENT_INTERFACE_MOD_MOVE_DOWN";
EVENT_TYPE_TEXT[EVENT_INTERFACE_MODS_REFRESH] = "EVENT_INTERFACE_MODS_REFRESH";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTl] = "EVENT_INTERFACE_GLINTl";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTr] = "EVENT_INTERFACE_GLINTr";
EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu"; EVENT_TYPE_TEXT[EVENT_INTERFACE_GLINTu] = "EVENT_INTERFACE_GLINTu";

View File

@ -225,6 +225,7 @@ enum EventType
EVENT_INTERFACE_ABORT = 412, EVENT_INTERFACE_ABORT = 412,
EVENT_INTERFACE_USER = 413, EVENT_INTERFACE_USER = 413,
EVENT_INTERFACE_SATCOM = 414, EVENT_INTERFACE_SATCOM = 414,
EVENT_INTERFACE_MODS = 416,
EVENT_INTERFACE_CHAP = 420, EVENT_INTERFACE_CHAP = 420,
EVENT_INTERFACE_LIST = 421, EVENT_INTERFACE_LIST = 421,
@ -311,6 +312,17 @@ enum EventType
EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT = 573,
EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT = 574,
EVENT_INTERFACE_MOD_LIST = 580,
EVENT_INTERFACE_WORKSHOP = 581,
EVENT_INTERFACE_MODS_DIR = 582,
EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE = 583,
EVENT_INTERFACE_MODS_APPLY = 584,
EVENT_INTERFACE_MOD_SUMMARY = 585,
EVENT_INTERFACE_MOD_DETAILS = 586,
EVENT_INTERFACE_MOD_MOVE_UP = 587,
EVENT_INTERFACE_MOD_MOVE_DOWN = 888,
EVENT_INTERFACE_MODS_REFRESH = 589,
EVENT_INTERFACE_GLINTl = 590, EVENT_INTERFACE_GLINTl = 590,
EVENT_INTERFACE_GLINTr = 591, EVENT_INTERFACE_GLINTr = 591,
EVENT_INTERFACE_GLINTu = 592, EVENT_INTERFACE_GLINTu = 592,

View File

@ -62,9 +62,9 @@ std::string CResourceManager::CleanPath(const std::string& path)
} }
bool CResourceManager::AddLocation(const std::string &location, bool prepend) bool CResourceManager::AddLocation(const std::string &location, bool prepend, const std::string &mountPoint)
{ {
if (!PHYSFS_mount(location.c_str(), nullptr, prepend ? 0 : 1)) if (!PHYSFS_mount(location.c_str(), mountPoint.c_str(), prepend ? 0 : 1))
{ {
GetLogger()->Error("Error while mounting \"%s\": %s\n", location.c_str(), PHYSFS_getLastError()); GetLogger()->Error("Error while mounting \"%s\": %s\n", location.c_str(), PHYSFS_getLastError());
return false; return false;
@ -95,6 +95,12 @@ std::vector<std::string> CResourceManager::GetLocations()
return ret; return ret;
} }
bool CResourceManager::LocationExists(const std::string& location)
{
auto locations = GetLocations();
auto it = std::find(locations.cbegin(), locations.cend(), location);
return it != locations.cend();
}
bool CResourceManager::SetSaveLocation(const std::string &location) bool CResourceManager::SetSaveLocation(const std::string &location)
{ {

View File

@ -36,11 +36,13 @@ public:
static std::string CleanPath(const std::string &path); static std::string CleanPath(const std::string &path);
//! Add a location to the search path //! Add a location to the search path
static bool AddLocation(const std::string &location, bool prepend = true); static bool AddLocation(const std::string &location, bool prepend = true, const std::string &mountPoint = "");
//! Remove a location from the search path //! Remove a location from the search path
static bool RemoveLocation(const std::string &location); static bool RemoveLocation(const std::string &location);
//! List all locations in the search path //! List all locations in the search path
static std::vector<std::string> GetLocations(); static std::vector<std::string> GetLocations();
//! Check if given location is in the search path
static bool LocationExists(const std::string &location);
static bool SetSaveLocation(const std::string &location); static bool SetSaveLocation(const std::string &location);
static std::string GetSaveLocation(); static std::string GetSaveLocation();

View File

@ -71,12 +71,13 @@ void InitializeRestext()
stringsText[RT_TITLE_MISSION] = TR("Missions"); stringsText[RT_TITLE_MISSION] = TR("Missions");
stringsText[RT_TITLE_FREE] = TR("Free game"); stringsText[RT_TITLE_FREE] = TR("Free game");
stringsText[RT_TITLE_USER] = TR("User levels"); stringsText[RT_TITLE_USER] = TR("User levels");
stringsText[RT_TITLE_CODE_BATTLES]=TR("Code battles"); stringsText[RT_TITLE_CODE_BATTLES] = TR("Code battles");
stringsText[RT_TITLE_SETUP] = TR("Options"); stringsText[RT_TITLE_SETUP] = TR("Options");
stringsText[RT_TITLE_NAME] = TR("Player's name"); stringsText[RT_TITLE_NAME] = TR("Player's name");
stringsText[RT_TITLE_PERSO] = TR("Customize your appearance"); stringsText[RT_TITLE_PERSO] = TR("Customize your appearance");
stringsText[RT_TITLE_WRITE] = TR("Save the current mission"); stringsText[RT_TITLE_WRITE] = TR("Save the current mission");
stringsText[RT_TITLE_READ] = TR("Load a saved mission"); stringsText[RT_TITLE_READ] = TR("Load a saved mission");
stringsText[RT_TITLE_MODS] = TR("Mods");
stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:"); stringsText[RT_PLAY_CHAP_CHAPTERS] = TR("Chapters:");
stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:"); stringsText[RT_PLAY_CHAP_PLANETS] = TR("Planets:");
@ -108,6 +109,11 @@ void InitializeRestext()
stringsText[RT_DIALOG_OK] = TR("OK"); stringsText[RT_DIALOG_OK] = TR("OK");
stringsText[RT_DIALOG_NOUSRLVL_TITLE] = TR("No userlevels installed!"); stringsText[RT_DIALOG_NOUSRLVL_TITLE] = TR("No userlevels installed!");
stringsText[RT_DIALOG_NOUSRLVL_TEXT] = TR("This menu is for userlevels from mods, but you didn't install any"); stringsText[RT_DIALOG_NOUSRLVL_TEXT] = TR("This menu is for userlevels from mods, but you didn't install any");
stringsText[RT_DIALOG_OPEN_PATH_FAILED_TITLE] = TR("Could not open the file explorer!");
stringsText[RT_DIALOG_OPEN_PATH_FAILED_TEXT] = TR("The path %s could not be opened in a file explorer.");
stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE] = TR("Could not open the web browser!");
stringsText[RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT] = TR("The address %s could not be opened in a web browser.");
stringsText[RT_DIALOG_CHANGES_QUESTION] = TR("There are unsaved changes. Do you want to save them before leaving?");
stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)"); stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)");
stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)"); stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)");
@ -153,7 +159,18 @@ void InitializeRestext()
stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s"); stringsText[RT_SCOREBOARD_RESULTS_TIME]= TR("Time: %s");
stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts"); stringsText[RT_SCOREBOARD_RESULTS_LINE]= TR("%s: %d pts");
stringsText[RT_MOD_LIST] = TR("Mods:");
stringsText[RT_MOD_DETAILS] = TR("Information:");
stringsText[RT_MOD_SUMMARY] = TR("Description:");
stringsText[RT_MOD_ENABLE] = TR("Enable\\Enable the selected mod");
stringsText[RT_MOD_DISABLE] = TR("Disable\\Disable the selected mod");
stringsText[RT_MOD_UNKNOWN_AUTHOR] = TR("Unknown author");
stringsText[RT_MOD_AUTHOR_FIELD_NAME] = TR("by");
stringsText[RT_MOD_VERSION_FIELD_NAME] = TR("Version");
stringsText[RT_MOD_WEBSITE_FIELD_NAME] = TR("Website");
stringsText[RT_MOD_CHANGES_FIELD_NAME] = TR("Changes");
stringsText[RT_MOD_NO_SUMMARY] = TR("No description.");
stringsText[RT_MOD_NO_CHANGES] = TR("No changes.");
stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle"); stringsEvent[EVENT_LABEL_CODE_BATTLE] = TR("Code battle");
@ -173,6 +190,7 @@ void InitializeRestext()
stringsEvent[EVENT_INTERFACE_CODE_BATTLES] = TR("Code battles\\Program your robot to be the best of them all!"); stringsEvent[EVENT_INTERFACE_CODE_BATTLES] = TR("Code battles\\Program your robot to be the best of them all!");
stringsEvent[EVENT_INTERFACE_USER] = TR("Custom levels\\Levels from mods created by the users"); stringsEvent[EVENT_INTERFACE_USER] = TR("Custom levels\\Levels from mods created by the users");
stringsEvent[EVENT_INTERFACE_SATCOM] = TR("SatCom"); stringsEvent[EVENT_INTERFACE_SATCOM] = TR("SatCom");
stringsEvent[EVENT_INTERFACE_MODS] = TR("Mods\\Mod manager");
stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player"); stringsEvent[EVENT_INTERFACE_NAME] = TR("Change player\\Change player");
stringsEvent[EVENT_INTERFACE_SETUP] = TR("Options\\Preferences"); stringsEvent[EVENT_INTERFACE_SETUP] = TR("Options\\Preferences");
stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning"); stringsEvent[EVENT_INTERFACE_AGAIN] = TR("Restart\\Restart the mission from the beginning");
@ -182,6 +200,12 @@ void InitializeRestext()
stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition"); stringsEvent[EVENT_INTERFACE_QUIT] = TR("Quit\\Quit Colobot: Gold Edition");
stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen"); stringsEvent[EVENT_INTERFACE_BACK] = TR("<< Back \\Back to the previous screen");
stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!"); stringsEvent[EVENT_INTERFACE_PLAY] = TR("Play\\Start mission!");
stringsEvent[EVENT_INTERFACE_WORKSHOP] = TR("Workshop\\Open the workshop to search for mods");
stringsEvent[EVENT_INTERFACE_MODS_DIR] = TR("Open Directory\\Open the mods directory");
stringsEvent[EVENT_INTERFACE_MODS_APPLY] = TR("Apply\\Apply the current mod configuration");
stringsEvent[EVENT_INTERFACE_MOD_MOVE_UP] = TR("Up\\Move the selected mod up so it's loaded sooner (mods may overwrite files from the mods above them)");
stringsEvent[EVENT_INTERFACE_MOD_MOVE_DOWN] = TR("Down\\Move the selected mod down so it's loaded later (mods may overwrite files from the mods above them)");
stringsEvent[EVENT_INTERFACE_MODS_REFRESH] = TR("Refresh\\Refresh the list of currently installed mods");
stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings"); stringsEvent[EVENT_INTERFACE_SETUPd] = TR("Device\\Driver and resolution settings");
stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings"); stringsEvent[EVENT_INTERFACE_SETUPg] = TR("Graphics\\Graphics settings");
stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings"); stringsEvent[EVENT_INTERFACE_SETUPp] = TR("Game\\Game settings");

View File

@ -71,6 +71,7 @@ enum ResTextType
RT_TITLE_WRITE = 50, RT_TITLE_WRITE = 50,
RT_TITLE_READ = 51, RT_TITLE_READ = 51,
RT_TITLE_USER = 52, RT_TITLE_USER = 52,
RT_TITLE_MODS = 54,
RT_PLAY_CHAP_CHAPTERS = 60, RT_PLAY_CHAP_CHAPTERS = 60,
RT_PLAY_CHAP_PLANETS = 61, RT_PLAY_CHAP_PLANETS = 61,
@ -102,6 +103,11 @@ enum ResTextType
RT_DIALOG_OK = 110, RT_DIALOG_OK = 110,
RT_DIALOG_NOUSRLVL_TITLE = 111, RT_DIALOG_NOUSRLVL_TITLE = 111,
RT_DIALOG_NOUSRLVL_TEXT = 112, RT_DIALOG_NOUSRLVL_TEXT = 112,
RT_DIALOG_OPEN_PATH_FAILED_TITLE = 113,
RT_DIALOG_OPEN_PATH_FAILED_TEXT = 114,
RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE = 115,
RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT = 116,
RT_DIALOG_CHANGES_QUESTION = 117,
RT_STUDIO_LISTTT = 120, RT_STUDIO_LISTTT = 120,
RT_STUDIO_COMPOK = 121, RT_STUDIO_COMPOK = 121,
@ -147,6 +153,18 @@ enum ResTextType
RT_SCOREBOARD_RESULTS_TIME= 232, RT_SCOREBOARD_RESULTS_TIME= 232,
RT_SCOREBOARD_RESULTS_LINE= 233, RT_SCOREBOARD_RESULTS_LINE= 233,
RT_MOD_LIST = 234,
RT_MOD_DETAILS = 235,
RT_MOD_SUMMARY = 236,
RT_MOD_ENABLE = 237,
RT_MOD_DISABLE = 238,
RT_MOD_UNKNOWN_AUTHOR = 239,
RT_MOD_AUTHOR_FIELD_NAME = 240,
RT_MOD_VERSION_FIELD_NAME = 241,
RT_MOD_WEBSITE_FIELD_NAME = 242,
RT_MOD_CHANGES_FIELD_NAME = 243,
RT_MOD_NO_SUMMARY = 244,
RT_MOD_NO_CHANGES = 245,
RT_MAX //! < number of values RT_MAX //! < number of values
}; };

View File

@ -215,3 +215,13 @@ std::string CSystemUtils::GetEnvVar(const std::string& name)
{ {
return ""; return "";
} }
bool CSystemUtils::OpenPath(const std::string& path)
{
return false;
}
bool CSystemUtils::OpenWebsite(const std::string& url)
{
return false;
}

View File

@ -145,6 +145,14 @@ public:
//! Returns the environment variable with the given name or an empty string if it does not exist //! Returns the environment variable with the given name or an empty string if it does not exist
virtual std::string GetEnvVar(const std::string &name); virtual std::string GetEnvVar(const std::string &name);
//! Opens a path with default file browser
/** \returns true if successful */
virtual bool OpenPath(const std::string& path);
//! Opens a website with default web browser
/** \returns true if successful */
virtual bool OpenWebsite(const std::string& url);
//! Sleep for given amount of microseconds //! Sleep for given amount of microseconds
virtual void Usleep(int usecs) = 0; virtual void Usleep(int usecs) = 0;

View File

@ -150,6 +150,28 @@ std::string CSystemUtilsLinux::GetEnvVar(const std::string& name)
return ""; return "";
} }
bool CSystemUtilsLinux::OpenPath(const std::string& path)
{
int result = system(("xdg-open \"" + path + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result);
return false;
}
return true;
}
bool CSystemUtilsLinux::OpenWebsite(const std::string& url)
{
int result = system(("xdg-open \"" + url + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open website: %s, error code: %i\n", url.c_str(), result);
return false;
}
return true;
}
void CSystemUtilsLinux::Usleep(int usec) void CSystemUtilsLinux::Usleep(int usec)
{ {
usleep(usec); usleep(usec);

View File

@ -48,6 +48,9 @@ public:
std::string GetEnvVar(const std::string& name) override; std::string GetEnvVar(const std::string& name) override;
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override; void Usleep(int usec) override;
private: private:

View File

@ -119,6 +119,28 @@ std::string CSystemUtilsMacOSX::GetEnvVar(const std::string& str)
return std::string(); return std::string();
} }
bool CSystemUtilsMacOSX::OpenPath(const std::string& path)
{
int result = system(("open \"" + path + "\"").c_str()); // TODO: Test on macOS
if (result != 0)
{
GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result);
return false;
}
return true;
}
bool CSystemUtilsMacOSX::OpenWebsite(const std::string& url)
{
int result = system(("open \"" + url + "\"").c_str()); // TODO: Test on macOS
if (result != 0)
{
GetLogger()->Error("Failed to open website: %s, error code: %i\n", website.c_str(), result);
return false;
}
return true;
}
void CSystemUtilsMacOSX::Usleep(int usec) void CSystemUtilsMacOSX::Usleep(int usec)
{ {
usleep(usec); usleep(usec);

View File

@ -38,6 +38,9 @@ public:
std::string GetEnvVar(const std::string& name) override; std::string GetEnvVar(const std::string& name) override;
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override; void Usleep(int usec) override;
private: private:

View File

@ -21,6 +21,7 @@
#include "common/logger.h" #include "common/logger.h"
#include <boost/filesystem.hpp>
#include <windows.h> #include <windows.h>
@ -152,6 +153,28 @@ std::string CSystemUtilsWindows::GetEnvVar(const std::string& name)
} }
} }
bool CSystemUtilsWindows::OpenPath(const std::string& path)
{
int result = system(("start explorer \"" + boost::filesystem::path(path).make_preferred().string() + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open path: %s, error code: %i\n", path.c_str(), result);
return false;
}
return true;
}
bool CSystemUtilsWindows::OpenWebsite(const std::string& url)
{
int result = system(("rundll32 url.dll,FileProtocolHandler \"" + url + "\"").c_str());
if (result != 0)
{
GetLogger()->Error("Failed to open website: %s, error code: %i\n", url.c_str(), result);
return false;
}
return true;
}
void CSystemUtilsWindows::Usleep(int usec) void CSystemUtilsWindows::Usleep(int usec)
{ {
LARGE_INTEGER ft; LARGE_INTEGER ft;

View File

@ -46,6 +46,9 @@ public:
std::string GetEnvVar(const std::string& name) override; std::string GetEnvVar(const std::string& name) override;
bool OpenPath(const std::string& path) override;
bool OpenWebsite(const std::string& url) override;
void Usleep(int usec) override; void Usleep(int usec) override;
public: public:

View File

@ -408,6 +408,7 @@ void CEngine::ReloadAllTextures()
{ {
FlushTextureCache(); FlushTextureCache();
m_text->FlushCache(); m_text->FlushCache();
m_text->ReloadFonts();
m_app->GetEventQueue()->AddEvent(Event(EVENT_RELOAD_TEXTURES)); m_app->GetEventQueue()->AddEvent(Event(EVENT_RELOAD_TEXTURES));
UpdateGroundSpotTextures(); UpdateGroundSpotTextures();

View File

@ -1189,6 +1189,10 @@ public:
void EnablePauseBlur(); void EnablePauseBlur();
void DisablePauseBlur(); void DisablePauseBlur();
//! Reloads all textures
/** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/
void ReloadAllTextures();
protected: protected:
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed) //! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
/** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/ /** Instead of calling this directly, send EVENT_RESOLUTION_CHANGED event **/
@ -1287,10 +1291,6 @@ protected:
}; };
static void WriteScreenShotThread(std::unique_ptr<WriteScreenShotData> data); static void WriteScreenShotThread(std::unique_ptr<WriteScreenShotData> data);
//! Reloads all textures
/** This additionally sends EVENT_RELOAD_TEXTURES to reload all textures not maintained by CEngine **/
void ReloadAllTextures();
protected: protected:
CApplication* m_app; CApplication* m_app;
CSystemUtils* m_systemUtils; CSystemUtils* m_systemUtils;

View File

@ -191,17 +191,32 @@ CText::~CText()
bool CText::Create() bool CText::Create()
{ {
CFontLoader fontLoader;
if (!fontLoader.Init())
{
GetLogger()->Debug("Error on parsing fonts config file: failed to open file\n");
}
if (TTF_Init() != 0) if (TTF_Init() != 0)
{ {
m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError()); m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError());
return false; return false;
} }
if (!ReloadFonts())
{
return false;
}
return true;
}
bool CText::ReloadFonts()
{
CFontLoader fontLoader;
if (!fontLoader.Init())
{
GetLogger()->Debug("Error on parsing fonts config file: failed to open file\n");
}
// Backup previous fonts
auto fonts = std::move(m_fonts);
m_fonts.clear();
for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM}) for (auto type : {FONT_COMMON, FONT_STUDIO, FONT_SATCOM})
{ {
m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type)); m_fonts[static_cast<Gfx::FontType>(type)] = MakeUnique<MultisizeFont>(fontLoader.GetFont(type));
@ -214,7 +229,10 @@ bool CText::Create()
FontType type = (*it).first; FontType type = (*it).first;
CachedFont* cf = GetOrOpenFont(type, m_defaultSize); CachedFont* cf = GetOrOpenFont(type, m_defaultSize);
if (cf == nullptr || cf->font == nullptr) if (cf == nullptr || cf->font == nullptr)
{
m_fonts = std::move(fonts);
return false; return false;
}
} }
return true; return true;

View File

@ -256,6 +256,8 @@ public:
//! Flushes cached textures //! Flushes cached textures
void FlushCache(); void FlushCache();
//! Try to load new font files
bool ReloadFonts();
//@{ //@{
//! Tab size management //! Tab size management

View File

@ -41,6 +41,7 @@
#include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
CLevelParser::CLevelParser() CLevelParser::CLevelParser()
{ {
@ -172,13 +173,28 @@ void CLevelParser::Load()
boost::replace_all(line, "\t", " "); // replace tab by space boost::replace_all(line, "\t", " "); // replace tab by space
// ignore comments // ignore comments
std::size_t comment = line.find("//"); size_t pos = 0;
if (comment != std::string::npos) std::string linesuffix = line;
line = line.substr(0, comment); boost::regex commentRegex{ R"(("[^"]*")|('[^']*')|(//.*$))" };
boost::smatch matches;
while (boost::regex_search(linesuffix, matches, commentRegex))
{
if (matches[3].matched)
{
pos += std::distance(linesuffix.cbegin(), matches.prefix().second);
line = line.substr(0, pos);
linesuffix = "";
}
else
{
pos += std::distance(linesuffix.cbegin(), matches.suffix().first);
linesuffix = matches.suffix().str();
}
}
boost::algorithm::trim(line); boost::algorithm::trim(line);
std::size_t pos = line.find_first_of(" \t\n"); pos = line.find_first_of(" \t\n");
std::string command = line.substr(0, pos); std::string command = line.substr(0, pos);
if (pos != std::string::npos) if (pos != std::string::npos)
{ {

View File

@ -320,6 +320,7 @@ std::string PhaseToString(Phase phase)
if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE"; if (phase == PHASE_APPERANCE) return "PHASE_APPERANCE";
if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU"; if (phase == PHASE_MAIN_MENU) return "PHASE_MAIN_MENU";
if (phase == PHASE_LEVEL_LIST) return "PHASE_LEVEL_LIST"; if (phase == PHASE_LEVEL_LIST) return "PHASE_LEVEL_LIST";
if (phase == PHASE_MOD_LIST) return "PHASE_MOD_LIST";
if (phase == PHASE_SIMUL) return "PHASE_SIMUL"; if (phase == PHASE_SIMUL) return "PHASE_SIMUL";
if (phase == PHASE_SETUPd) return "PHASE_SETUPd"; if (phase == PHASE_SETUPd) return "PHASE_SETUPd";
if (phase == PHASE_SETUPg) return "PHASE_SETUPg"; if (phase == PHASE_SETUPg) return "PHASE_SETUPg";
@ -3911,6 +3912,7 @@ void CRobotMain::ChangeColor()
m_phase != PHASE_SETUPps && m_phase != PHASE_SETUPps &&
m_phase != PHASE_SETUPcs && m_phase != PHASE_SETUPcs &&
m_phase != PHASE_SETUPss && m_phase != PHASE_SETUPss &&
m_phase != PHASE_MOD_LIST &&
m_phase != PHASE_WIN && m_phase != PHASE_WIN &&
m_phase != PHASE_LOST && m_phase != PHASE_LOST &&
m_phase != PHASE_APPERANCE ) return; m_phase != PHASE_APPERANCE ) return;

View File

@ -55,6 +55,7 @@ enum Phase
PHASE_APPERANCE, PHASE_APPERANCE,
PHASE_MAIN_MENU, PHASE_MAIN_MENU,
PHASE_LEVEL_LIST, PHASE_LEVEL_LIST,
PHASE_MOD_LIST,
PHASE_SIMUL, PHASE_SIMUL,
PHASE_SETUPd, PHASE_SETUPd,
PHASE_SETUPg, PHASE_SETUPg,

View File

@ -47,22 +47,7 @@ void CALSound::CleanUp()
if (m_enabled) if (m_enabled)
{ {
GetLogger()->Info("Unloading files and closing device...\n"); GetLogger()->Info("Unloading files and closing device...\n");
StopAll(); Reset();
StopMusic();
m_channels.clear();
m_currentMusic.reset();
m_oldMusic.clear();
m_previousMusic.music.reset();
m_sounds.clear();
m_music.clear();
m_enabled = false;
alcDestroyContext(m_context); alcDestroyContext(m_context);
alcCloseDevice(m_device); alcCloseDevice(m_device);
@ -99,6 +84,24 @@ bool CALSound::Create()
return true; return true;
} }
void CALSound::Reset()
{
StopAll();
StopMusic();
m_channels.clear();
m_currentMusic.reset();
m_oldMusic.clear();
m_previousMusic.music.reset();
m_sounds.clear();
m_music.clear();
}
bool CALSound::GetEnable() bool CALSound::GetEnable()
{ {
return m_enabled; return m_enabled;

View File

@ -84,6 +84,7 @@ public:
~CALSound(); ~CALSound();
bool Create() override; bool Create() override;
void Reset() override;
bool Cache(SoundType, const std::string &) override; bool Cache(SoundType, const std::string &) override;
void CacheMusic(const std::string &) override; void CacheMusic(const std::string &) override;
bool IsCached(SoundType) override; bool IsCached(SoundType) override;

View File

@ -52,6 +52,10 @@ void CSoundInterface::CacheAll()
} }
} }
void CSoundInterface::Reset()
{
}
bool CSoundInterface::Cache(SoundType sound, const std::string &file) bool CSoundInterface::Cache(SoundType sound, const std::string &file)
{ {
return true; return true;

View File

@ -72,6 +72,10 @@ public:
*/ */
void CacheAll(); void CacheAll();
/** Stop all sounds and music and clean cache.
*/
virtual void Reset();
/** Function called to cache sound effect file. /** Function called to cache sound effect file.
* This function is called by plugin interface for each file. * This function is called by plugin interface for each file.
* \param sound - id of a file, will be used to identify sound files * \param sound - id of a file, will be used to identify sound files

View File

@ -1299,7 +1299,9 @@ void CEdit::SetText(const std::string& text, bool bNew)
if( m_len >= GetMaxChar() ) m_len = GetMaxChar(); if( m_len >= GetMaxChar() ) m_len = GetMaxChar();
m_text.resize( m_len + 1, '\0' ); m_text.resize( m_len + 1, '\0' );
m_text[m_len] = '\0';
m_format.resize( m_len + 1, m_fontType ); m_format.resize( m_len + 1, m_fontType );
m_format[m_len] = m_fontType;
font = m_fontType; font = m_fontType;
j = 0; j = 0;

View File

@ -49,6 +49,7 @@
#include "ui/screen/screen_level_list.h" #include "ui/screen/screen_level_list.h"
#include "ui/screen/screen_loading.h" #include "ui/screen/screen_loading.h"
#include "ui/screen/screen_main_menu.h" #include "ui/screen/screen_main_menu.h"
#include "ui/screen/screen_mod_list.h"
#include "ui/screen/screen_player_select.h" #include "ui/screen/screen_player_select.h"
#include "ui/screen/screen_quit.h" #include "ui/screen/screen_quit.h"
#include "ui/screen/screen_setup_controls.h" #include "ui/screen/screen_setup_controls.h"
@ -80,6 +81,7 @@ CMainUserInterface::CMainUserInterface()
m_screenIORead = MakeUnique<CScreenIORead>(m_screenLevelList.get()); m_screenIORead = MakeUnique<CScreenIORead>(m_screenLevelList.get());
m_screenIOWrite = MakeUnique<CScreenIOWrite>(m_screenLevelList.get()); m_screenIOWrite = MakeUnique<CScreenIOWrite>(m_screenLevelList.get());
m_screenLoading = MakeUnique<CScreenLoading>(); m_screenLoading = MakeUnique<CScreenLoading>();
m_screenModList = MakeUnique<CScreenModList>(m_dialog.get(), m_app->GetModManager());
m_screenSetupControls = MakeUnique<CScreenSetupControls>(); m_screenSetupControls = MakeUnique<CScreenSetupControls>();
m_screenSetupDisplay = MakeUnique<CScreenSetupDisplay>(); m_screenSetupDisplay = MakeUnique<CScreenSetupDisplay>();
m_screenSetupGame = MakeUnique<CScreenSetupGame>(); m_screenSetupGame = MakeUnique<CScreenSetupGame>();
@ -184,6 +186,10 @@ void CMainUserInterface::ChangePhase(Phase phase)
m_screenLevelList->SetLevelCategory(m_main->GetLevelCategory()); m_screenLevelList->SetLevelCategory(m_main->GetLevelCategory());
m_currentScreen = m_screenLevelList.get(); m_currentScreen = m_screenLevelList.get();
} }
if (m_phase == PHASE_MOD_LIST)
{
m_currentScreen = m_screenModList.get();
}
if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPs) if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPs)
{ {
CScreenSetup* screenSetup = GetSetupScreen(m_phase); CScreenSetup* screenSetup = GetSetupScreen(m_phase);
@ -531,6 +537,7 @@ void CMainUserInterface::FrameParticle(float rTime)
} }
else if ( m_phase == PHASE_PLAYER_SELECT || else if ( m_phase == PHASE_PLAYER_SELECT ||
m_phase == PHASE_LEVEL_LIST || m_phase == PHASE_LEVEL_LIST ||
m_phase == PHASE_MOD_LIST ||
m_phase == PHASE_SETUPd || m_phase == PHASE_SETUPd ||
m_phase == PHASE_SETUPg || m_phase == PHASE_SETUPg ||
m_phase == PHASE_SETUPp || m_phase == PHASE_SETUPp ||

View File

@ -50,6 +50,7 @@ class CScreenIOWrite;
class CScreenLevelList; class CScreenLevelList;
class CScreenLoading; class CScreenLoading;
class CScreenMainMenu; class CScreenMainMenu;
class CScreenModList;
class CScreenPlayerSelect; class CScreenPlayerSelect;
class CScreenQuit; class CScreenQuit;
class CScreenSetup; class CScreenSetup;
@ -114,6 +115,7 @@ protected:
std::unique_ptr<CScreenLevelList> m_screenLevelList; std::unique_ptr<CScreenLevelList> m_screenLevelList;
std::unique_ptr<CScreenLoading> m_screenLoading; std::unique_ptr<CScreenLoading> m_screenLoading;
std::unique_ptr<CScreenMainMenu> m_screenMainMenu; std::unique_ptr<CScreenMainMenu> m_screenMainMenu;
std::unique_ptr<CScreenModList> m_screenModList;
std::unique_ptr<CScreenPlayerSelect> m_screenPlayerSelect; std::unique_ptr<CScreenPlayerSelect> m_screenPlayerSelect;
std::unique_ptr<CScreenQuit> m_screenQuit; std::unique_ptr<CScreenQuit> m_screenQuit;
std::unique_ptr<CScreenSetupControls> m_screenSetupControls; std::unique_ptr<CScreenSetupControls> m_screenSetupControls;

View File

@ -170,6 +170,13 @@ void CScreenMainMenu::CreateInterface()
pb = pw->CreateButton(pos, ddim, 128+60, EVENT_INTERFACE_SATCOM); pb = pw->CreateButton(pos, ddim, 128+60, EVENT_INTERFACE_SATCOM);
pb->SetState(STATE_SHADOW); pb->SetState(STATE_SHADOW);
// Mods button
pos.x = 447.0f/640.0f;
pos.y = 313.0f/480.0f;
ddim.x = 0.09f;
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS);
pb->SetState(STATE_SHADOW);
SetBackground("textures/interface/interface.png"); SetBackground("textures/interface/interface.png");
CreateVersionDisplay(); CreateVersionDisplay();
} }
@ -235,6 +242,9 @@ bool CScreenMainMenu::EventProcess(const Event &event)
m_main->ChangePhase(PHASE_SATCOM); m_main->ChangePhase(PHASE_SATCOM);
break; break;
case EVENT_INTERFACE_MODS:
m_main->ChangePhase(PHASE_MOD_LIST);
default: default:
return true; return true;
} }

View File

@ -0,0 +1,582 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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://gnu.org/licenses
*/
#include "ui/screen/screen_mod_list.h"
#include "common/config.h"
#include "app/app.h"
#include "app/modman.h"
#include "common/logger.h"
#include "common/restext.h"
#include "common/stringutils.h"
#include "common/resources/resourcemanager.h"
#include "common/system/system.h"
#include "level/robotmain.h"
#include "math/func.h"
#include "sound/sound.h"
#include "ui/controls/button.h"
#include "ui/controls/edit.h"
#include "ui/controls/interface.h"
#include "ui/controls/label.h"
#include "ui/controls/list.h"
#include "ui/controls/window.h"
#include <algorithm>
namespace Ui
{
CScreenModList::CScreenModList(CMainDialog* dialog, CModManager* modManager)
: m_dialog(dialog),
m_modManager(modManager)
{
}
void CScreenModList::CreateInterface()
{
CWindow* pw;
CEdit* pe;
CLabel* pl;
CButton* pb;
CList* pli;
Math::Point pos, ddim;
std::string name;
// Display the window
pos.x = 0.10f;
pos.y = 0.10f;
ddim.x = 0.80f;
ddim.y = 0.80f;
pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
pw->SetClosable(true);
GetResource(RES_TEXT, RT_TITLE_MODS, name);
pw->SetName(name);
pos.x = 0.10f;
pos.y = 0.40f;
ddim.x = 0.50f;
ddim.y = 0.50f;
pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // orange corner
pos.x = 0.40f;
pos.y = 0.10f;
ddim.x = 0.50f;
ddim.y = 0.50f;
pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // blue corner
// Display the list of mods
pos.x = ox+sx*3;
pos.y = oy+sy*10.5f;
ddim.x = dim.x*7.5f;
ddim.y = dim.y*0.6f;
GetResource(RES_TEXT, RT_MOD_LIST, name);
pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name);
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
pos.y = oy+sy*6.7f;
ddim.y = dim.y*4.6f;
ddim.x = dim.x*6.5f;
pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_MOD_LIST);
pli->SetState(STATE_SHADOW);
pli->SetState(STATE_EXTEND);
// Displays the mod details
pos.x = ox+sx*9.5f;
pos.y = oy+sy*10.5f;
ddim.x = dim.x*7.5f;
ddim.y = dim.y*0.6f;
GetResource(RES_TEXT, RT_MOD_DETAILS, name);
pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name);
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
pos.y = oy+sy*6.7f;
ddim.y = dim.y*4.3f;
ddim.x = dim.x*6.5f;
pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_MOD_DETAILS);
pe->SetState(STATE_SHADOW);
pe->SetMaxChar(500);
pe->SetEditCap(false); // just to see
pe->SetHighlightCap(true);
pos = pli->GetPos();
ddim = pli->GetDim();
// Displays the mod summary
pos.x = ox+sx*3;
pos.y = oy+sy*5.4f;
ddim.x = dim.x*6.5f;
ddim.y = dim.y*0.6f;
GetResource(RES_TEXT, RT_MOD_SUMMARY, name);
pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL13, name);
pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
pos.x = ox+sx*3;
pos.y = oy+sy*3.6f;
ddim.x = dim.x*13.4f;
ddim.y = dim.y*1.9f;
pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_MOD_SUMMARY);
pe->SetState(STATE_SHADOW);
pe->SetMaxChar(500);
pe->SetEditCap(false); // just to see
pe->SetHighlightCap(true);
// Apply button
pos.x = ox+sx*13.75f;
pos.y = oy+sy*2;
ddim.x = dim.x*2.0f;
ddim.y = dim.y*1;
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS_APPLY);
pb->SetState(STATE_SHADOW);
// Display the enable/disable button
pos.x -= dim.x*2.3f;
ddim.x = dim.x*2.0f;
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE);
pb->SetState(STATE_SHADOW);
// Display the move up button
pos.x -= dim.x*0.8f;
pos.y = oy+sy*2.48;
ddim.x = dim.x*0.5;
ddim.y = dim.y*0.5;
pb = pw->CreateButton(pos, ddim, 49, EVENT_INTERFACE_MOD_MOVE_UP);
pb->SetState(STATE_SHADOW);
// Display the move down button
pos.y = oy+sy*2;
pb = pw->CreateButton(pos, ddim, 50, EVENT_INTERFACE_MOD_MOVE_DOWN);
pb->SetState(STATE_SHADOW);
// Display the refresh button
pos.x -= dim.x*1.3f;
pos.y = oy+sy*2;
ddim.x = dim.x*1;
ddim.y = dim.y*1;
pb = pw->CreateButton(pos, ddim, 87, EVENT_INTERFACE_MODS_REFRESH);
pb->SetState(STATE_SHADOW);
// Display the open website button
pos.x -= dim.x*1.3f;
pb = pw->CreateButton(pos, ddim, 40, EVENT_INTERFACE_WORKSHOP);
pb->SetState(STATE_SHADOW);
// Display the open directory button
pos.x -= dim.x*1.3f;
pb = pw->CreateButton(pos, ddim, 57, EVENT_INTERFACE_MODS_DIR);
pb->SetState(STATE_SHADOW);
// Back button
pos.x = ox+sx*3;
ddim.x = dim.x*4;
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK);
pb->SetState(STATE_SHADOW);
FindMods();
UpdateAll();
// Background
SetBackground("textures/interface/interface.png");
CreateVersionDisplay();
}
bool CScreenModList::EventProcess(const Event &event)
{
CWindow* pw;
CList* pl;
const std::string workshopUrl = "https://www.moddb.com/games/colobot-gold-edition";
const std::string modDir = CResourceManager::GetSaveLocation() + "/mods";
auto systemUtils = CSystemUtils::Create(); // platform-specific utils
Mod const * mod;
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return false;
if (event.type == pw->GetEventTypeClose() ||
event.type == EVENT_INTERFACE_BACK ||
(event.type == EVENT_KEY_DOWN && event.GetData<KeyEventData>()->key == KEY(ESCAPE)))
{
if (m_modManager->Changes())
{
m_dialog->StartQuestion(RT_DIALOG_CHANGES_QUESTION, true, true, false,
[this]()
{
ApplyChanges();
CloseWindow();
},
[this]()
{
CloseWindow();
});
}
else
{
CloseWindow();
}
return false;
}
switch( event.type )
{
case EVENT_INTERFACE_MOD_LIST:
pl = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_MOD_LIST));
if (pl == nullptr) break;
m_modSelectedIndex = pl->GetSelect();
UpdateModSummary();
UpdateModDetails();
UpdateEnableDisableButton();
UpdateUpDownButtons();
break;
case EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE:
mod = &m_modManager->GetMod(m_modSelectedIndex);
if (mod->enabled)
{
m_modManager->DisableMod(m_modSelectedIndex);
}
else
{
m_modManager->EnableMod(m_modSelectedIndex);
}
UpdateModList();
UpdateEnableDisableButton();
UpdateApplyButton();
break;
case EVENT_INTERFACE_MOD_MOVE_UP:
m_modSelectedIndex = m_modManager->MoveUp(m_modSelectedIndex);
UpdateModList();
UpdateUpDownButtons();
UpdateApplyButton();
break;
case EVENT_INTERFACE_MOD_MOVE_DOWN:
m_modSelectedIndex = m_modManager->MoveDown(m_modSelectedIndex);
UpdateModList();
UpdateUpDownButtons();
UpdateApplyButton();
break;
case EVENT_INTERFACE_MODS_REFRESH:
// Apply any changes before refresh so that the config file
// is better synchronized with the state of the game
case EVENT_INTERFACE_MODS_APPLY:
ApplyChanges();
UpdateAll();
// Start playing the main menu music again
if (!m_app->GetSound()->IsPlayingMusic())
{
m_app->GetSound()->PlayMusic("music/Intro1.ogg", false);
m_app->GetSound()->CacheMusic("music/Intro2.ogg");
}
break;
case EVENT_INTERFACE_MODS_DIR:
if (!systemUtils->OpenPath(modDir))
{
std::string title, text;
GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title);
GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text);
// Workaround for Windows: the label skips everything after the first \\ character
std::string modDirWithoutBackSlashes = modDir;
std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/');
m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), modDirWithoutBackSlashes.c_str()));
}
break;
case EVENT_INTERFACE_WORKSHOP:
if (!systemUtils->OpenWebsite(workshopUrl))
{
std::string title, text;
GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TITLE, title);
GetResource(RES_TEXT, RT_DIALOG_OPEN_WEBSITE_FAILED_TEXT, text);
m_dialog->StartInformation(title, title, StrUtils::Format(text.c_str(), workshopUrl.c_str()));
}
break;
default:
return true;
}
return false;
}
void CScreenModList::FindMods()
{
m_modManager->FindMods();
if (m_modManager->CountMods() != 0)
{
m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast<size_t>(0), m_modManager->CountMods() - 1);
}
}
void CScreenModList::ApplyChanges()
{
m_modManager->SaveMods();
m_modManager->ReloadMods();
}
void CScreenModList::CloseWindow()
{
m_main->ChangePhase(PHASE_MAIN_MENU);
}
void CScreenModList::UpdateAll()
{
UpdateModList();
UpdateModDetails();
UpdateModSummary();
UpdateEnableDisableButton();
UpdateApplyButton();
UpdateUpDownButtons();
}
void CScreenModList::UpdateModList()
{
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return;
CList* pl = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_MOD_LIST));
if (pl == nullptr) return;
pl->Flush();
if (m_modManager->CountMods() == 0)
{
return;
}
const auto& mods = m_modManager->GetMods();
for (size_t i = 0; i < mods.size(); ++i)
{
const auto& mod = mods[i];
const auto& name = mod.data.displayName;
pl->SetItemName(i, name);
pl->SetCheck(i, mod.enabled);
pl->SetEnable(i, true);
}
pl->SetSelect(m_modSelectedIndex);
pl->ShowSelect(false);
}
void CScreenModList::UpdateModDetails()
{
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return;
CEdit* pe = static_cast<CEdit*>(pw->SearchControl(EVENT_INTERFACE_MOD_DETAILS));
if (pe == nullptr) return;
if (m_modManager->CountMods() == 0)
{
pe->SetText("No information");
return;
}
std::string details{};
const auto& mod = m_modManager->GetMod(m_modSelectedIndex);
const auto data = mod.data;
details += "\\b;" + data.displayName + '\n';
std::string authorFieldName;
GetResource(RES_TEXT, RT_MOD_AUTHOR_FIELD_NAME, authorFieldName);
details += "\\s;" + authorFieldName + " ";
if (!data.author.empty())
{
details += data.author;
}
else
{
std::string unknownAuthor;
GetResource(RES_TEXT, RT_MOD_UNKNOWN_AUTHOR, unknownAuthor);
details += unknownAuthor;
}
details += '\n';
details += '\n';
if (!data.version.empty())
{
std::string versionFieldName;
GetResource(RES_TEXT, RT_MOD_VERSION_FIELD_NAME, versionFieldName);
details += "\\t;" + versionFieldName + '\n' + data.version + '\n';
}
if (!data.website.empty())
{
std::string websiteFieldName;
GetResource(RES_TEXT, RT_MOD_WEBSITE_FIELD_NAME, websiteFieldName);
details += "\\t;" + websiteFieldName + '\n' + data.website + '\n';
}
std::string changesFieldName;
GetResource(RES_TEXT, RT_MOD_CHANGES_FIELD_NAME, changesFieldName);
details += "\\t;" + changesFieldName + '\n';
if (!data.changes.empty())
{
for (const auto& change : data.changes)
{
details += change + '\n';
}
}
else
{
std::string noChanges;
GetResource(RES_TEXT, RT_MOD_NO_CHANGES, noChanges);
details += noChanges;
}
pe->SetText(details);
pe->SetFirstLine(0);
}
void CScreenModList::UpdateModSummary()
{
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return;
CEdit* pe = static_cast<CEdit*>(pw->SearchControl(EVENT_INTERFACE_MOD_SUMMARY));
if (pe == nullptr) return;
std::string noSummary;
GetResource(RES_TEXT, RT_MOD_NO_SUMMARY, noSummary);
if (m_modManager->CountMods() == 0)
{
pe->SetText(noSummary);
return;
}
const auto& mod = m_modManager->GetMod(m_modSelectedIndex);
if (!mod.data.summary.empty())
{
pe->SetText(mod.data.summary);
}
else
{
pe->SetText(noSummary);
}
}
void CScreenModList::UpdateEnableDisableButton()
{
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return;
CButton* pb = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE));
if (pb == nullptr) return;
std::string buttonName{};
if (m_modManager->CountMods() == 0)
{
pb->ClearState(STATE_ENABLE);
// Set some default name
GetResource(RES_TEXT, RT_MOD_ENABLE, buttonName);
pb->SetName(buttonName);
return;
}
const auto& mod = m_modManager->GetMod(m_modSelectedIndex);
if (mod.enabled)
{
GetResource(RES_TEXT, RT_MOD_DISABLE, buttonName);
pb->SetName(buttonName);
}
else
{
GetResource(RES_TEXT, RT_MOD_ENABLE, buttonName);
pb->SetName(buttonName);
}
}
void CScreenModList::UpdateApplyButton()
{
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return;
CButton* pb = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MODS_APPLY));
if (pb == nullptr) return;
if (m_modManager->Changes())
{
pb->SetState(STATE_ENABLE);
}
else
{
pb->ClearState(STATE_ENABLE);
}
}
void CScreenModList::UpdateUpDownButtons()
{
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
if (pw == nullptr) return;
CButton* pb_up = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_UP));
if (pb_up == nullptr) return;
CButton* pb_down = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_DOWN));
if (pb_down == nullptr) return;
if (m_modManager->CountMods() == 0)
{
pb_up->ClearState(STATE_ENABLE);
pb_down->ClearState(STATE_ENABLE);
return;
}
if (m_modSelectedIndex == 0)
{
pb_up->ClearState(STATE_ENABLE);
}
else
{
pb_up->SetState(STATE_ENABLE);
}
if (m_modSelectedIndex >= m_modManager->CountMods() - 1)
{
pb_down->ClearState(STATE_ENABLE);
}
else
{
pb_down->SetState(STATE_ENABLE);
}
}
} // namespace Ui

View File

@ -0,0 +1,66 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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://gnu.org/licenses
*/
#pragma once
#include "app/modman.h"
#include "ui/maindialog.h"
#include "ui/screen/screen.h"
#include <map>
namespace Ui
{
/**
* \class CScreenModList
* \brief This class is the front-end for the \ref CModManager.
*/
class CScreenModList : public CScreen
{
public:
CScreenModList(CMainDialog* dialog, CModManager* modManager);
void CreateInterface() override;
bool EventProcess(const Event &event) override;
protected:
void FindMods();
void ApplyChanges();
void CloseWindow();
void UpdateAll();
void UpdateModList();
void UpdateModDetails();
void UpdateModSummary();
void UpdateEnableDisableButton();
void UpdateApplyButton();
void UpdateUpDownButtons();
protected:
Ui::CMainDialog* m_dialog;
CModManager* m_modManager;
size_t m_modSelectedIndex = 0;
};
} // namespace Ui

View File

@ -6,3 +6,8 @@ string_value=Hello world
[test_int] [test_int]
int_value=42 int_value=42
[test_array]
string_array=AAA,Hello world,Gold Edition
int_array=2,3,1
bool_array=1,0,1

View File

@ -52,3 +52,25 @@ TEST_F(CConfigFileTest, ReadTest)
ASSERT_TRUE(m_configFile.GetFloatProperty("test_float", "float_value", float_value)); ASSERT_TRUE(m_configFile.GetFloatProperty("test_float", "float_value", float_value));
ASSERT_FLOAT_EQ(1.5, float_value); ASSERT_FLOAT_EQ(1.5, float_value);
} }
TEST_F(CConfigFileTest, ReadArrayTest)
{
m_configFile.SetUseCurrentDirectory(true);
ASSERT_TRUE(m_configFile.Init()); // load colobot.ini file
std::vector<std::string> expected_string_values = { "AAA", "Hello world", "Gold Edition" };
std::vector<std::string> string_values;
ASSERT_TRUE(m_configFile.GetArrayProperty("test_array", "string_array", string_values));
ASSERT_EQ(expected_string_values, string_values);
std::vector<int> expected_int_values = { 2, 3, 1 };
std::vector<int> int_values;
ASSERT_TRUE(m_configFile.GetArrayProperty("test_array", "int_array", int_values));
ASSERT_EQ(expected_int_values, int_values);
std::vector<bool> expected_bool_values = { true, false, true };
std::vector<bool> bool_values;
ASSERT_TRUE(m_configFile.GetArrayProperty("test_array", "bool_array", bool_values));
ASSERT_EQ(expected_bool_values, bool_values);
}