diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 4263ef4c1..c4e35afa5 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -637,14 +637,11 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti CAdventureMapButton * randomBtn = new CAdventureMapButton(CGI->generaltexth->zelp[47], 0, 411, 105, "GSPBUTT.DEF", SDLK_r); randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL); - if(settings["general"]["enableRMG"].Bool()) + randomBtn->callback = [&]() { - randomBtn->callback = [&]() - { - toggleTab(randMapTab); - changeSelection(&randMapTab->getMapInfo()); - }; - } + toggleTab(randMapTab); + changeSelection(&randMapTab->getMapInfo()); + }; start = new CAdventureMapButton(CGI->generaltexth->zelp[103], bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRBEG.DEF", SDLK_b); diff --git a/config/defaultSettings.json b/config/defaultSettings.json index 716470e5c..99279cf07 100644 --- a/config/defaultSettings.json +++ b/config/defaultSettings.json @@ -23,10 +23,6 @@ "sound" : { "type" : "number", "default" : 88 - }, - "enableRMG" : { - "type" : "bool", - "default" : false } }, "default" : {} diff --git a/config/terrainViewPatterns.json b/config/terrainViewPatterns.json index 888be7f93..262d366b1 100644 --- a/config/terrainViewPatterns.json +++ b/config/terrainViewPatterns.json @@ -272,9 +272,9 @@ { "data" : [ - "S", "S", "S", - "S", "N", "S", - "S", "S", "S" + "?", "?", "?", + "?", "N", "?", + "?", "?", "?" ], "mapping" : "0-23" } diff --git a/lib/Mapping/CMapEditManager.cpp b/lib/Mapping/CMapEditManager.cpp index 6bbc0d516..62237ea97 100644 --- a/lib/Mapping/CMapEditManager.cpp +++ b/lib/Mapping/CMapEditManager.cpp @@ -20,6 +20,18 @@ TerrainViewPattern::TerrainViewPattern() : minPoints(0), flipMode(FLIP_MODE_SAME } +TerrainViewPattern::WeightedRule::WeightedRule() : points(0) +{ + +} + +bool TerrainViewPattern::WeightedRule::isStandardRule() const +{ + return TerrainViewPattern::RULE_ANY == name || TerrainViewPattern::RULE_DIRT == name + || TerrainViewPattern::RULE_NATIVE == name || TerrainViewPattern::RULE_SAND == name + || TerrainViewPattern::RULE_TRANSITION == name; +} + CTerrainViewPatternConfig::CTerrainViewPatternConfig() { const JsonNode config(ResourceID("config/terrainViewPatterns.json")); @@ -46,19 +58,15 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() boost::split(rules, cell, boost::is_any_of(",")); BOOST_FOREACH(std::string ruleStr, rules) { - std::vector rule; - boost::split(rule, ruleStr, boost::is_any_of("-")); - std::pair pair; - pair.first = rule[0]; - if(rule.size() > 1) + std::vector ruleParts; + boost::split(ruleParts, ruleStr, boost::is_any_of("-")); + TerrainViewPattern::WeightedRule rule; + rule.name = ruleParts[0]; + if(ruleParts.size() > 1) { - pair.second = boost::lexical_cast(rule[1]); + rule.points = boost::lexical_cast(ruleParts[1]); } - else - { - pair.second = 0; - } - pattern.data[i].push_back(pair); + pattern.data[i].push_back(rule); } } @@ -95,6 +103,19 @@ const std::vector & CTerrainViewPatternConfig::getPatternsFo return patterns.find(terGroup)->second; } +const TerrainViewPattern & CTerrainViewPatternConfig::getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const +{ + const std::vector & groupPatterns = getPatternsForGroup(terGroup); + BOOST_FOREACH(const TerrainViewPattern & pattern, groupPatterns) + { + if(id == pattern.id) + { + return pattern; + } + } + throw std::runtime_error("Pattern with ID not found: " + id); +} + CMapEditManager::CMapEditManager(const CTerrainViewPatternConfig * terViewPatternConfig, CMap * map, int randomSeed /*= std::time(nullptr)*/) : map(map), terViewPatternConfig(terViewPatternConfig) { @@ -133,7 +154,7 @@ void CMapEditManager::drawTerrain(ETerrainType::ETerrainType terType, int posx, //TODO there are situations where more tiles are affected implicitely //TODO add coastal bit to extTileFlags appropriately - //updateTerrainViews(posx - 1, posy - 1, width + 2, height + 2, mapLevel); + updateTerrainViews(posx - 1, posy - 1, width + 2, height + 2, mapLevel); } void CMapEditManager::updateTerrainViews(int posx, int posy, int width, int height, int mapLevel) @@ -146,30 +167,31 @@ void CMapEditManager::updateTerrainViews(int posx, int posy, int width, int heig terViewPatternConfig->getPatternsForGroup(getTerrainGroup(map->terrain[i][j][mapLevel].terType)); // Detect a pattern which fits best - int totalPoints, bestPattern, bestFlip = -1; + int bestPattern = -1, bestFlip = -1; std::string transitionReplacement; - for(int i = 0; i < patterns.size(); ++i) + for(int k = 0; k < patterns.size(); ++k) { - const TerrainViewPattern & pattern = patterns[i]; + const TerrainViewPattern & pattern = patterns[k]; - for(int flip = 0; flip < 3; ++flip) + for(int flip = 0; flip < 4; ++flip) { ValidationResult valRslt = validateTerrainView(i, j, mapLevel, flip > 0 ? getFlippedPattern(pattern, flip) : pattern); if(valRslt.result) { - if(valRslt.points > totalPoints) - { - totalPoints = valRslt.points; - bestPattern = i; - bestFlip = flip; - transitionReplacement = valRslt.transitionReplacement; - } + tlog5 << "Pattern detected at pos " << i << "x" << j << "x" << mapLevel << ": P-Nr. " << k + << ", Flip " << flip << ", Repl. " << valRslt.transitionReplacement << std::endl; + + bestPattern = k; + bestFlip = flip; + transitionReplacement = valRslt.transitionReplacement; break; } } } if(bestPattern == -1) { + // This shouldn't be the case + tlog2 << "No pattern detected at pos " << i << "x" << j << "x" << mapLevel << std::endl; continue; } @@ -219,7 +241,7 @@ ETerrainGroup::ETerrainGroup CMapEditManager::getTerrainGroup(ETerrainType::ETer } } -CMapEditManager::ValidationResult CMapEditManager::validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern) const +CMapEditManager::ValidationResult CMapEditManager::validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern, int recDepth /*= 0*/) const { ETerrainType::ETerrainType centerTerType = map->terrain[posx][posy][mapLevel].terType; int totalPoints = 0; @@ -255,53 +277,79 @@ CMapEditManager::ValidationResult CMapEditManager::validateTerrainView(int posx, int topPoints = -1; for(int j = 0; j < pattern.data[i].size(); ++j) { - const std::pair & rulePair = pattern.data[i][j]; - const std::string & rule = rulePair.first; - bool isNative = (rule == TerrainViewPattern::RULE_NATIVE || rule == TerrainViewPattern::RULE_ANY) && !isAlien; - auto validationRslt = [&](bool rslt) -> bool + TerrainViewPattern::WeightedRule rule = pattern.data[i][j]; + if(!rule.isStandardRule()) + { + if(recDepth == 0) + { + const TerrainViewPattern & patternForRule = terViewPatternConfig->getPatternById(pattern.terGroup, rule.name); + ValidationResult rslt = validateTerrainView(cx, cy, mapLevel, patternForRule, 1); + if(!rslt.result) + { + return ValidationResult(false); + } + else + { + topPoints = std::max(topPoints, rule.points); + continue; + } + } + else + { + rule.name = TerrainViewPattern::RULE_NATIVE; + } + } + + bool nativeTestOk = (rule.name == TerrainViewPattern::RULE_NATIVE || rule.name == TerrainViewPattern::RULE_ANY) && !isAlien; + auto applyValidationRslt = [&](bool rslt) { if(rslt) { - topPoints = std::max(topPoints, rulePair.second); + topPoints = std::max(topPoints, rule.points); } - return rslt; }; // Validate cell with the ruleset of the pattern - bool validation; if(pattern.terGroup == ETerrainGroup::NORMAL) { - bool isDirt = (rule == TerrainViewPattern::RULE_DIRT - || rule == TerrainViewPattern::RULE_TRANSITION || rule == TerrainViewPattern::RULE_ANY) + bool dirtTestOk = (rule.name == TerrainViewPattern::RULE_DIRT + || rule.name == TerrainViewPattern::RULE_TRANSITION || rule.name == TerrainViewPattern::RULE_ANY) && isAlien && !isSandType(terType); - bool isSand = (rule == TerrainViewPattern::RULE_SAND || rule == TerrainViewPattern::RULE_TRANSITION - || rule == TerrainViewPattern::RULE_ANY) + bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION + || rule.name == TerrainViewPattern::RULE_ANY) && isSandType(terType); - if(transitionReplacement.empty() && (rule == TerrainViewPattern::RULE_TRANSITION - || rule == TerrainViewPattern::RULE_ANY) && (isDirt || isSand)) + if(transitionReplacement.empty() && (rule.name == TerrainViewPattern::RULE_TRANSITION + || rule.name == TerrainViewPattern::RULE_ANY) && (dirtTestOk || sandTestOk)) { - transitionReplacement = isDirt ? TerrainViewPattern::RULE_DIRT : TerrainViewPattern::RULE_SAND; + transitionReplacement = dirtTestOk ? TerrainViewPattern::RULE_DIRT : TerrainViewPattern::RULE_SAND; } - validation = validationRslt((isDirt && transitionReplacement != TerrainViewPattern::RULE_SAND) - || (isSand && transitionReplacement != TerrainViewPattern::RULE_DIRT) - || isNative); + applyValidationRslt((dirtTestOk && transitionReplacement != TerrainViewPattern::RULE_SAND) + || (sandTestOk && transitionReplacement != TerrainViewPattern::RULE_DIRT) + || nativeTestOk); } else if(pattern.terGroup == ETerrainGroup::DIRT) { - bool isSand = rule == TerrainViewPattern::RULE_SAND && isSandType(terType); - bool isDirt = rule == TerrainViewPattern::RULE_DIRT && !isSandType(terType) && !isNative; - validation = validationRslt(rule == TerrainViewPattern::RULE_ANY || isSand || isDirt || isNative); + bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && isSandType(terType); + bool dirtTestOk = rule.name == TerrainViewPattern::RULE_DIRT && !isSandType(terType) && !nativeTestOk; + applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || dirtTestOk || nativeTestOk); } - else if(pattern.terGroup == ETerrainGroup::SAND || pattern.terGroup == ETerrainGroup::WATER || - pattern.terGroup == ETerrainGroup::ROCK) + else if(pattern.terGroup == ETerrainGroup::SAND) { - bool isSand = rule == TerrainViewPattern::RULE_SAND && isSandType(terType) && !isNative; - validation = validationRslt(rule == TerrainViewPattern::RULE_ANY || isSand || isNative); + bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && isAlien; + applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); } - if(!validation) + else if(pattern.terGroup == ETerrainGroup::WATER) { - return ValidationResult(false); + bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && terType != ETerrainType::DIRT + && terType != ETerrainType::WATER; + applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); + } + else if(pattern.terGroup == ETerrainGroup::ROCK) + { + bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && terType != ETerrainType::DIRT + && terType != ETerrainType::ROCK; + applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); } } @@ -320,7 +368,7 @@ CMapEditManager::ValidationResult CMapEditManager::validateTerrainView(int posx, return ValidationResult(false); } - return ValidationResult(true, totalPoints, transitionReplacement); + return ValidationResult(true, transitionReplacement); } bool CMapEditManager::isSandType(ETerrainType::ETerrainType terType) const @@ -379,8 +427,8 @@ void CMapEditManager::insertObject(CGObjectInstance * obj, int posx, int posy, b map->addBlockVisTiles(obj); } -CMapEditManager::ValidationResult::ValidationResult(bool result, int points /*= 0*/, const std::string & transitionReplacement /*= ""*/) - : result(result), points(points), transitionReplacement(transitionReplacement) +CMapEditManager::ValidationResult::ValidationResult(bool result, const std::string & transitionReplacement /*= ""*/) + : result(result), transitionReplacement(transitionReplacement) { } diff --git a/lib/Mapping/CMapEditManager.h b/lib/Mapping/CMapEditManager.h index cf6f06f2f..eadf3333c 100644 --- a/lib/Mapping/CMapEditManager.h +++ b/lib/Mapping/CMapEditManager.h @@ -37,6 +37,30 @@ namespace ETerrainGroup */ struct TerrainViewPattern { + /** + * A weighted rule struct is a combination of the rule name and optionally points. + */ + struct WeightedRule + { + /** The name of the rule. Can be any value of the RULE_* constants or a ID of a another pattern. */ + std::string name; + + /** Optional. A rule can have points. Patterns may have a minimum count of points to reach to be successful. */ + int points; + + /** + * Constructor. + */ + WeightedRule(); + + /** + * Gets true if this rule is a standard rule which means that it has a value of one of the RULE_* constants. + * + * @return true for a standard rule + */ + bool isStandardRule() const; + }; + /** Constant for the flip mode same image. Pattern will be flipped and the same image will be used(which is given in the mapping). */ static const std::string FLIP_MODE_SAME_IMAGE; @@ -76,9 +100,8 @@ struct TerrainViewPattern * can be used. Their meaning differs also from type to type. * * std::vector -> several rules can be used in one cell - * std::pair -> combination of the name of the rule and a optional number of points */ - std::array >, 9> data; + std::array, 9> data; /** The identifier of the pattern, if it's referenced from a another pattern. */ std::string id; @@ -121,6 +144,15 @@ public: */ const std::vector & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; + /** + * Gets a pattern by ID. Throws if pattern isn't available(config error). + * + * @param terGroup the terrain group e.g. normal for grass, lava,... OR dirt OR sand,... + * @param id the id of the pattern + * @return the pattern which matches the ID + */ + const TerrainViewPattern & getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; + private: /** The patterns data. */ std::map > patterns; @@ -182,17 +214,13 @@ private: * Constructor. * * @param result the result of the validation either true or false - * @param points optional. the points which were achieved with that pattern * @param transitionReplacement optional. the replacement of a T rule, either D or S */ - ValidationResult(bool result, int points = 0, const std::string & transitionReplacement = ""); + ValidationResult(bool result, const std::string & transitionReplacement = ""); /** The result of the validation. */ bool result; - /** The points which were achieved with that pattern. */ - int points; - /** The replacement of a T rule, either D or S. */ std::string transitionReplacement; }; @@ -223,9 +251,10 @@ private: * @param posy the y position * @param mapLevel the map level, 0 for open and 1 for underground * @param pattern the pattern to validate the terrain view with + * @param recDepth the depth of the recursion, 0 for no recursion - 1 for recursion * @return a validation result struct */ - ValidationResult validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern) const; + ValidationResult validateTerrainView(int posx, int posy, int mapLevel, const TerrainViewPattern & pattern, int recDepth = 0) const; /** * Tests whether the given terrain type is a sand type. Sand types are: Water, Sand and Rock