1
0
Fork 0

Add: "Many random towns" button in scenario editor now prompts for the number of towns, with defaults based on new game settings (#14158)

pull/14186/head
Iris-Persephone 2025-05-02 17:54:21 -04:00 committed by GitHub
parent 3eba97f67c
commit 2f020abe74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 13 deletions

View File

@ -231,7 +231,8 @@ void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags);
HouseZone GetTownRadiusGroup(const Town *t, TileIndex tile);
void SetTownRatingTestMode(bool mode);
TownActions GetMaskOfTownActions(CompanyID cid, const Town *t);
bool GenerateTowns(TownLayout layout);
uint GetDefaultTownsForMapSize();
bool GenerateTowns(TownLayout layout, std::optional<uint> number = std::nullopt);
const CargoSpec *FindFirstCargoWithTownAcceptanceEffect(TownAcceptanceEffect effect);
CargoArray GetAcceptedCargoOfHouse(const HouseSpec *hs);

View File

@ -2372,19 +2372,39 @@ static Town *CreateRandomTown(uint attempts, uint32_t townnameparts, TownSize si
return nullptr;
}
static const uint8_t _num_initial_towns[4] = {5, 11, 23, 46}; // very low, low, normal, high
/**
* Calculate the number of towns which should be on the map according to the current "town density" newgame setting and the map size.
* If the number of towns is set to "custom", the function will always return that value instead.
* @return The number of towns.
*/
uint GetDefaultTownsForMapSize()
{
static const uint8_t num_initial_towns[4] = {5, 11, 23, 46}; // very low, low, normal, high
if (_settings_game.difficulty.number_towns == static_cast<uint>(CUSTOM_TOWN_NUMBER_DIFFICULTY)) {
return _settings_newgame.game_creation.custom_town_number;
}
return Map::ScaleBySize(num_initial_towns[_settings_game.difficulty.number_towns]);
}
/**
* Generate a number of towns with a given layout.
* This function is used by the Random Towns button in Scenario Editor as well as in world generation.
* @param layout The road layout to build.
* @param number The number of towns to create. std::nullopt means to use the game settings.
* @return true if towns have been successfully created.
*/
bool GenerateTowns(TownLayout layout)
bool GenerateTowns(TownLayout layout, std::optional<uint> number)
{
uint current_number = 0;
uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.number_towns : 0;
uint total = (difficulty == (uint)CUSTOM_TOWN_NUMBER_DIFFICULTY) ? _settings_game.game_creation.custom_town_number : Map::ScaleBySize(_num_initial_towns[difficulty] + (Random() & 7));
uint total;
if (number.has_value()) {
total = number.value();
} else if (_settings_game.difficulty.number_towns == static_cast<uint>(CUSTOM_TOWN_NUMBER_DIFFICULTY)) {
total = GetDefaultTownsForMapSize();
} else {
total = GetDefaultTownsForMapSize() + (Random() & 7);
}
total = std::min<uint>(TownPool::MAX_SIZE, total);
uint32_t townnameparts;
TownNames town_names;

View File

@ -34,6 +34,7 @@
#include "townname_func.h"
#include "core/backup_type.hpp"
#include "core/geometry_func.hpp"
#include "core/string_consumer.hpp"
#include "genworld.h"
#include "fios.h"
#include "stringfilter_type.h"
@ -1249,16 +1250,10 @@ public:
break;
case WID_TF_MANY_RANDOM_TOWNS: {
Backup<bool> old_generating_world(_generating_world, true);
UpdateNearestTownForRoadTiles(true);
if (!GenerateTowns(this->town_layout)) {
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_GENERATE_TOWN), GetEncodedString(STR_ERROR_NO_SPACE_FOR_TOWN), WL_INFO);
}
UpdateNearestTownForRoadTiles(false);
old_generating_world.Restore();
std::string default_town_number = fmt::format("{}", GetDefaultTownsForMapSize());
ShowQueryString(default_town_number, STR_MAPGEN_NUMBER_OF_TOWNS, 5, this, CS_NUMERAL, {QueryStringFlag::AcceptUnchanged});
break;
}
case WID_TF_LOAD_FROM_FILE:
ShowSaveLoadDialog(FT_TOWN_DATA, SLO_LOAD);
break;
@ -1293,6 +1288,23 @@ public:
}
}
void OnQueryTextFinished(std::optional<std::string> str) override
{
/* Was 'cancel' pressed? */
if (!str.has_value()) return;
auto value = ParseInteger(*str);
if (!value.has_value()) return;
Backup<bool> old_generating_world(_generating_world, true);
UpdateNearestTownForRoadTiles(true);
if (!GenerateTowns(this->town_layout, value)) {
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_GENERATE_TOWN), GetEncodedString(STR_ERROR_NO_SPACE_FOR_TOWN), WL_INFO);
}
UpdateNearestTownForRoadTiles(false);
old_generating_world.Restore();
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
{
this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);