diff --git a/AI/Nullkiller/AIUtility.cpp b/AI/Nullkiller/AIUtility.cpp index fa62afa19..7bd82c32c 100644 --- a/AI/Nullkiller/AIUtility.cpp +++ b/AI/Nullkiller/AIUtility.cpp @@ -109,7 +109,9 @@ const CGHeroInstance * HeroPtr::get(bool doWeExpectNull) const } else { - assert(obj); + if (!obj) + logAi->error("Accessing no longer accessible hero %s!", h->getNameTranslated()); + //assert(obj); //assert(owned); } } diff --git a/AI/Nullkiller/Behaviors/DefenceBehavior.cpp b/AI/Nullkiller/Behaviors/DefenceBehavior.cpp index 7b99df87c..df13141b3 100644 --- a/AI/Nullkiller/Behaviors/DefenceBehavior.cpp +++ b/AI/Nullkiller/Behaviors/DefenceBehavior.cpp @@ -211,7 +211,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta if(path.turn() <= treat.turn - 2) { #if NKAI_TRACE_LEVEL >= 1 - logAi->trace("Deffer defence of %s by %s because he has enough time to rich the town next trun", + logAi->trace("Defer defence of %s by %s because he has enough time to reach the town next trun", town->name, path.targetHero->name); #endif diff --git a/AI/Nullkiller/Goals/ExecuteHeroChain.cpp b/AI/Nullkiller/Goals/ExecuteHeroChain.cpp index 9f1839bf8..67f8a984f 100644 --- a/AI/Nullkiller/Goals/ExecuteHeroChain.cpp +++ b/AI/Nullkiller/Goals/ExecuteHeroChain.cpp @@ -161,7 +161,7 @@ void ExecuteHeroChain::accept(AIGateway * ai) if(node.turns == 0) { logAi->error( - "Enable to complete chain. Expected hero %s to arive to %s but he is at %s", + "Unable to complete chain. Expected hero %s to arive to %s but he is at %s", hero->getNameTranslated(), node.coord.toString(), hero->visitablePos().toString()); @@ -169,7 +169,7 @@ void ExecuteHeroChain::accept(AIGateway * ai) return; } - // no exception means we were not able to rich the tile + // no exception means we were not able to reach the tile ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN); blockedIndexes.insert(node.parentIndex); } @@ -177,7 +177,7 @@ void ExecuteHeroChain::accept(AIGateway * ai) { if(!heroPtr.validAndSet()) { - logAi->debug("Hero %s was killed while attempting to rich %s", heroPtr.name, node.coord.toString()); + logAi->debug("Hero %s was killed while attempting to reach %s", heroPtr.name, node.coord.toString()); return; } diff --git a/Mods/vcmi/mod.json b/Mods/vcmi/mod.json index 0201be3d8..6df15eb6c 100644 --- a/Mods/vcmi/mod.json +++ b/Mods/vcmi/mod.json @@ -8,6 +8,7 @@ "author" : "VCMI-Team", "modType" : "Grafik", + "skipValidation" : true, "translations" : [ "config/vcmi/german.json" ] @@ -19,6 +20,7 @@ "author" : "Zespół VCMI", "modType" : "Graficzny", + "skipValidation" : true, "translations" : [ "config/vcmi/polish.json" ] @@ -30,6 +32,7 @@ "author" : "Команда VCMI", "modType" : "Графический", + "skipValidation" : true, "translations" : [ "config/vcmi/russian.json" ] diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index efbc3417c..995b55998 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -613,7 +613,7 @@ bool MusicEntry::stop(int fade_ms) assert(startTime != uint32_t(-1)); float playDuration = (endTime - startTime + startPosition) / 1000.f; owner->trackPositions[currentName] = playDuration; - logGlobal->info("Stopping music file %s at %f", currentName, playDuration); + logGlobal->trace("Stopping music file %s at %f", currentName, playDuration); Mix_FadeOutMusic(fade_ms); return true; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 5fe8d706b..d6be0044d 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1963,7 +1963,8 @@ void CPlayerInterface::playerStartsTurn(PlayerColor player) } else { - adventureInt->infoBar->showSelection(); + if (player == playerID) + adventureInt->infoBar->showSelection(); while (GH.listInt.front() != adventureInt && !dynamic_cast(GH.listInt.front().get())) //don't remove dialogs that expect query answer GH.popInts(1); } diff --git a/client/mapView/MapRenderer.cpp b/client/mapView/MapRenderer.cpp index d5ba305fa..b56db25ed 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -617,7 +617,18 @@ void MapRendererDebug::renderTile(IMapRendererContext & context, Canvas & target uint8_t MapRendererDebug::checksum(IMapRendererContext & context, const int3 & coordinates) { - return 0; + uint8_t result = 0; + + if (context.showVisitable()) + result += 1; + + if (context.showBlockable()) + result += 2; + + if (context.showGrid()) + result += 4; + + return result; } MapRendererPath::MapRendererPath() diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index cf61e7572..73e3d0630 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -283,7 +283,7 @@ double MapRendererAdventureFadingContext::objectTransparency(ObjectInstanceID ob if(objectID == target) return progress; - return 1.0; + return MapRendererAdventureContext::objectTransparency(objectID, coordinates); } MapRendererAdventureMovingContext::MapRendererAdventureMovingContext(const MapRendererContextState & viewState) diff --git a/client/mapView/mapHandler.cpp b/client/mapView/mapHandler.cpp index 4a6495ee7..ac92ad0d6 100644 --- a/client/mapView/mapHandler.cpp +++ b/client/mapView/mapHandler.cpp @@ -118,6 +118,12 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj if(a->pos.y != b->pos.y) return a->pos.y < b->pos.y; + // heroes should appear on top of objects on the same tile + if(b->ID==Obj::HERO && a->ID!=Obj::HERO) + return true; + if(b->ID!=Obj::HERO && a->ID==Obj::HERO) + return false; + // or, if all other tests fail to determine priority - simply based on H3M order return a->id < b->id; } diff --git a/config/objects/rewardableOncePerHero.json b/config/objects/rewardableOncePerHero.json index 42b3f6111..2f921669a 100644 --- a/config/objects/rewardableOncePerHero.json +++ b/config/objects/rewardableOncePerHero.json @@ -222,7 +222,7 @@ }, { "message" : 152, - "appearChance" : { "min" : 67, "max" : 67 } + "appearChance" : { "min" : 67 } } ], "onVisitedMessage" : 147, diff --git a/config/schemas/mod.json b/config/schemas/mod.json index 802c155c8..855e13b69 100644 --- a/config/schemas/mod.json +++ b/config/schemas/mod.json @@ -26,6 +26,10 @@ "type":"string", "description": "Author of the mod. Can be nickname, real name or name of team" }, + "skipValidation" : { + "type":"boolean", + "description": "If set to true, vcmi will skip validation of current translation json files" + }, "translations":{ "type":"array", "description": "List of files with translations for this language", @@ -87,7 +91,7 @@ "language" : { "type":"string", "description": "Base language of the mod, before applying localizations. By default vcmi assumes English", - "enum" : [ "english", "german", "polish", "russian", "ukrainian" ], + "enum" : [ "chinese", "english", "german", "polish", "russian", "ukrainian" ], }, "depends": { "type":"array", diff --git a/config/schemas/settings.json b/config/schemas/settings.json index 0279ab55c..378452cbd 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -21,7 +21,6 @@ "playerName", "music", "sound", - "encoding", "language", "swipe", "swipeDesktop", @@ -46,10 +45,6 @@ "type" : "number", "default" : 88 }, - "encoding" : { - "type" : "string", - "default" : "auto" - }, "swipe" : { "type" : "boolean", "default" : true @@ -68,7 +63,7 @@ }, "language" : { "type":"string", - "enum" : [ "english", "german", "polish", "russian", "ukrainian" ], + "enum" : [ "chinese", "english", "german", "polish", "russian", "ukrainian" ], "default" : "english" }, "lastSave" : { diff --git a/launcher/settingsView/csettingsview_moc.cpp b/launcher/settingsView/csettingsview_moc.cpp index 4e7b3098e..7ed92c7e5 100644 --- a/launcher/settingsView/csettingsview_moc.cpp +++ b/launcher/settingsView/csettingsview_moc.cpp @@ -31,26 +31,10 @@ QString resolutionToString(const QSize & resolution) } } -/// List of encoding which can be selected from Launcher. -/// Note that it is possible to specify enconding manually in settings.json -static const std::string knownEncodingsList[] = //TODO: remove hardcode -{ - // Asks vcmi to automatically detect encoding - "auto", - // European Windows-125X encodings - "CP1250", // West European, covers mostly Slavic languages that use latin script - "CP1251", // Covers languages that use cyrillic scrypt - "CP1252", // Latin/East European, covers most of latin languages - // Chinese encodings - "GBK", // extension of GB2312, also known as CP936 - "GB2312", // basic set for Simplified Chinese. Separate from GBK to allow proper detection of H3 fonts - // Korean encodings - "CP949" // extension of EUC-KR. -}; - /// List of tags of languages that can be selected from Launcher (and have translation for Launcher) static const std::string languageTagList[] = { + "chinese", "english", "german", "polish", @@ -119,10 +103,6 @@ void CSettingsView::loadSettings() ui->lineEditGameDir->setText(pathToQString(VCMIDirs::get().binaryPath())); ui->lineEditTempDir->setText(pathToQString(VCMIDirs::get().userLogsPath())); - std::string encoding = settings["general"]["encoding"].String(); - size_t encodingIndex = boost::range::find(knownEncodingsList, encoding) - knownEncodingsList; - if(encodingIndex < ui->comboBoxEncoding->count()) - ui->comboBoxEncoding->setCurrentIndex((int)encodingIndex); ui->comboBoxAutoSave->setCurrentIndex(settings["general"]["saveFrequency"].Integer() > 0 ? 1 : 0); std::string language = settings["general"]["language"].String(); @@ -291,12 +271,6 @@ void CSettingsView::on_plainTextEditRepos_textChanged() } } -void CSettingsView::on_comboBoxEncoding_currentIndexChanged(int index) -{ - Settings node = settings.write["general"]["encoding"]; - node->String() = knownEncodingsList[index]; -} - void CSettingsView::on_openTempDir_clicked() { QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(ui->lineEditTempDir->text()).absoluteFilePath())); diff --git a/launcher/settingsView/csettingsview_moc.h b/launcher/settingsView/csettingsview_moc.h index 84a044eb7..967a4a565 100644 --- a/launcher/settingsView/csettingsview_moc.h +++ b/launcher/settingsView/csettingsview_moc.h @@ -49,8 +49,6 @@ private slots: void on_plainTextEditRepos_textChanged(); - void on_comboBoxEncoding_currentIndexChanged(int index); - void on_openTempDir_clicked(); void on_openUserDataDir_clicked(); diff --git a/launcher/settingsView/csettingsview_moc.ui b/launcher/settingsView/csettingsview_moc.ui index 8182a6d22..4592897ff 100644 --- a/launcher/settingsView/csettingsview_moc.ui +++ b/launcher/settingsView/csettingsview_moc.ui @@ -114,259 +114,159 @@ 0 0 620 - 762 + 731 - - - - - - 75 - true - + + + + + QPlainTextEdit::NoWrap - - General + + http://downloads.vcmi.eu/Mods/repository.json - - - - VCMI Language + + + + VCAI - - - - - - Heroes III character set - - - - - - Automatic detection + VCAI - Central European (Windows 1250) + Nullkiller - - - Cyrillic script (Windows 1251) - - - - - Western European (Windows 1252) - - - - - Simplified Chinese (GBK) - - - - - Simplified Chinese (GB2312) - - - - - Korean (Windows 949) - - - - - - - - Network port - - - - - - - Autosave - - - - - - - Build version - - - - - - - - 75 - true - - - - Video - - - - - - - Resolution - - - - - - - Fullscreen - - - - - - - Show intro - - - - - - - Display index - - - - - - - Cursor - - - - - - - - 75 - true - - - - Artificial Intelligence - - - - - - - Adventure Map AI - - - - - - - Neutral AI - - - - Friendly AI - - - - Enemy AI - - - - - 75 - true - - + + - Data Directories + Update now - - + + - Extra data directory + Network port - + + + + false + + + BattleAI + + + + BattleAI + + + + + StupidAI + + + + + + + + BattleAI + + + + BattleAI + + + + + StupidAI + + + + + + + + Autosave + + + + /usr/share/vcmi - - - - false - - - Change - - - - - - - Open - - - - - - - User data directory - - - - - - Open - - - - - - - Log files directory - - - - Open - + + + + Show intro + + + + + + + false + + + /home/user/.vcmi + + + true + + + + + + + 0 + + + + Off + + + + + On + + + + + Real + + + + + @@ -379,15 +279,15 @@ - - + + - Check on startup + Display index - - + + 1 @@ -403,24 +303,122 @@ - - + + + + + 75 + true + + - Update now + Video - - - - QPlainTextEdit::NoWrap - - - http://downloads.vcmi.eu/Mods/repository.json + + + + Log files directory - + + + + false + + + BattleAI + + + + BattleAI + + + + + StupidAI + + + + + + + + Build version + + + + + + + Open + + + + + + + + + + true + + + + + + + 1 + + + + Off + + + + + On + + + + + + + + + 75 + true + + + + Artificial Intelligence + + + + + + + Resolution + + + + + + + Cursor + + + + + + + Neutral AI + + + + @@ -439,6 +437,77 @@ + + + + Check on startup + + + + + + + Open + + + + + + + Fullscreen + + + + + + + + + + + + + false + + + /home/user/.vcmi + + + true + + + + + + + VCMI Language + + + + + + + 1 + + + + Off + + + + + On + + + + + + + + Adventure Map AI + + + @@ -446,6 +515,11 @@ English + + + 简体中文 (Simplified Chinese) + + Deutsch (German) @@ -468,7 +542,54 @@ - + + + + + 75 + true + + + + Data Directories + + + + + + + + 75 + true + + + + General + + + + + + + User data directory + + + + + + + Extra data directory + + + + + + + Friendly AI + + + + 1024 @@ -481,175 +602,13 @@ - - - - 1 - - - - Off - - - - - On - - - - - - - - - + + false - /home/user/.vcmi - - - true - - - - - - - false - - - /home/user/.vcmi - - - true - - - - - - - false - - - BattleAI - - - - BattleAI - - - - - StupidAI - - - - - - - - false - - - BattleAI - - - - BattleAI - - - - - StupidAI - - - - - - - - BattleAI - - - - BattleAI - - - - - StupidAI - - - - - - - - VCAI - - - - VCAI - - - - - Nullkiller - - - - - - - - - - - 1 - - - - Off - - - - - On - - - - - - - - 0 - - - - Off - - - - - On - - - - - Real - - - - - - - - - - - true + Change diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index 4d184f261..082211d7c 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/lib/CGeneralTextHandler.cpp @@ -25,8 +25,9 @@ void CGeneralTextHandler::detectInstallParameters() { using LanguageFootprint = std::array; - static const std::array knownFootprints = + static const std::array knownFootprints = { { + { { 0.1602, 0.0000, 0.0357, 0.0054, 0.0038, 0.0017, 0.0077, 0.0214, 0.0000, 0.0000, 0.1264, 0.1947, 0.2012, 0.1406, 0.0480, 0.0532 } }, { { 0.0559, 0.0000, 0.1983, 0.0051, 0.0222, 0.0183, 0.4596, 0.2405, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000 } }, { { 0.0493, 0.0000, 0.1926, 0.0047, 0.0230, 0.0121, 0.4133, 0.2780, 0.0002, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0259, 0.0008 } }, { { 0.0534, 0.0000, 0.1705, 0.0047, 0.0418, 0.0208, 0.4775, 0.2191, 0.0001, 0.0000, 0.0000, 0.0000, 0.0000, 0.0005, 0.0036, 0.0080 } }, @@ -35,8 +36,9 @@ void CGeneralTextHandler::detectInstallParameters() { { 0.0559, 0.0000, 0.1807, 0.0059, 0.0036, 0.0013, 0.0046, 0.0134, 0.0000, 0.0004, 0.0000, 0.0487, 0.0209, 0.0060, 0.4615, 0.1972 } }, } }; - static const std::array knownLanguages = + static const std::array knownLanguages = { { + "chinese", "english", "french", "german", @@ -257,27 +259,35 @@ const std::string & CGeneralTextHandler::deserialize(const TextIdentifier & iden void CGeneralTextHandler::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized) { + assert(!modContext.empty()); + assert(!getModLanguage(modContext).empty()); assert(UID.get().find("..") == std::string::npos); // invalid identifier - there is section that was evaluated to empty string //assert(stringsLocalizations.count(UID.get()) == 0); // registering already registered string? - if (stringsLocalizations.count(UID.get()) > 0) + if(stringsLocalizations.count(UID.get()) > 0) { - std::string oldValue = stringsLocalizations[UID.get()].baseValue; + auto & value = stringsLocalizations[UID.get()]; - if (oldValue != localized) - logMod->warn("Duplicate registered string '%s' found! Old value: '%s', new value: '%s'", UID.get(), oldValue, localized); - return; + if(value.baseLanguage.empty()) + { + value.baseLanguage = getModLanguage(modContext); + value.baseValue = localized; + } + else + { + if(value.baseValue != localized) + logMod->warn("Duplicate registered string '%s' found! Old value: '%s', new value: '%s'", UID.get(), value.baseValue, localized); + } } + else + { + StringState result; + result.baseLanguage = getModLanguage(modContext); + result.baseValue = localized; + result.modContext = modContext; - assert(!modContext.empty()); - assert(!getModLanguage(modContext).empty()); - - StringState result; - result.baseLanguage = getModLanguage(modContext); - result.baseValue = localized; - result.modContext = modContext; - - stringsLocalizations[UID.get()] = result; + stringsLocalizations[UID.get()] = result; + } } void CGeneralTextHandler::registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized) @@ -602,9 +612,6 @@ std::string CGeneralTextHandler::getInstalledLanguage() std::string CGeneralTextHandler::getInstalledEncoding() { - auto explicitSetting = settings["general"]["encoding"].String(); - if (explicitSetting != "auto") - return explicitSetting; return settings["session"]["encoding"].String(); } diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 0da476eb7..be7af936c 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -1156,6 +1156,9 @@ bool CModHandler::validateTranslations(TModID modName) const if (mod.config[language.identifier].isNull()) continue; + if (mod.config[language.identifier]["skipValidation"].Bool()) + continue; + auto fileList = mod.config[language.identifier]["translations"].convertTo >(); JsonNode json = JsonUtils::assembleFromFiles(fileList); result |= VLC->generaltexth->validateTranslation(language.identifier, modName, json); diff --git a/lib/Languages.h b/lib/Languages.h index 98a4681e0..c1610976d 100644 --- a/lib/Languages.h +++ b/lib/Languages.h @@ -14,6 +14,7 @@ namespace Languages enum class ELanguages { + CHINESE, ENGLISH, FRENCH, GERMAN, @@ -47,11 +48,13 @@ struct Options inline auto const & getLanguageList( ) { - static const std::array languages + static const std::array languages { { + { "chinese", "Chinese", "简体中文", "GBK", true, true }, { "english", "English", "English", "CP1252", true, true }, - { "french", "French", "Français", "CP1252", true, false }, + { "french", "French", "Français", "CP1252", true, true }, { "german", "German", "Deutsch", "CP1252", true, true }, + //TODO: korean - CP949 encoding { "polish", "Polish", "Polski", "CP1250", true, true }, { "russian", "Russian", "Русский", "CP1251", true, true }, { "ukrainian", "Ukrainian", "Українська", "CP1251", true, true } diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index 3f9de84c6..b67f8af19 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -404,7 +404,7 @@ void CObjectClassesHandler::afterLoadFinalization() std::string CObjectClassesHandler::getObjectName(si32 type, si32 subtype) const { const auto handler = getHandlerFor(type, subtype); - if (handler->hasNameTextID()) + if (handler && handler->hasNameTextID()) return handler->getNameTranslated(); else return objects[type]->getNameTranslated(); diff --git a/lib/mapObjects/CRewardableConstructor.h b/lib/mapObjects/CRewardableConstructor.h index e8d528aed..6e41c7ce6 100644 --- a/lib/mapObjects/CRewardableConstructor.h +++ b/lib/mapObjects/CRewardableConstructor.h @@ -46,6 +46,11 @@ public: void configureObject(CRewardableObject * object, CRandomGenerator & rng) const; void init(const JsonNode & objectConfig); + + template void serialize(Handler &h, const int version) + { + h & parameters; + } }; class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler @@ -60,6 +65,14 @@ public: void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; std::unique_ptr getObjectInfo(std::shared_ptr tmpl) const override; + + template void serialize(Handler &h, const int version) + { + AObjectTypeHandler::serialize(h, version); + + if (version >= 816) + h & objectInfo; + } }; VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/CRewardableObject.cpp b/lib/mapObjects/CRewardableObject.cpp index ba8cf39ea..9dd973bcb 100644 --- a/lib/mapObjects/CRewardableObject.cpp +++ b/lib/mapObjects/CRewardableObject.cpp @@ -544,6 +544,7 @@ void CRewardableObject::newTurn(CRandomGenerator & rand) const void CRewardableObject::initObj(CRandomGenerator & rand) { VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand); + assert(!info.empty()); } CRewardableObject::CRewardableObject(): diff --git a/lib/serializer/CSerializer.h b/lib/serializer/CSerializer.h index 12223598f..9b12c3c97 100644 --- a/lib/serializer/CSerializer.h +++ b/lib/serializer/CSerializer.h @@ -14,7 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN -const ui32 SERIALIZATION_VERSION = 815; +const ui32 SERIALIZATION_VERSION = 816; const ui32 MINIMAL_SERIALIZATION_VERSION = 813; const std::string SAVEGAME_MAGIC = "VCMISVG";