diff --git a/src/callback_table.cpp b/src/callback_table.cpp index 945a0e426d..981b305c99 100644 --- a/src/callback_table.cpp +++ b/src/callback_table.cpp @@ -37,7 +37,6 @@ CommandCallback CcCloneVehicle; CommandCallback CcPlaySound10; CommandCallback CcPlaceSign; CommandCallback CcTerraform; -CommandCallback CcFoundTown; CommandCallback CcGiveMoney; /* rail_gui.cpp */ @@ -61,6 +60,10 @@ CommandCallback CcBuildShip; CommandCallback CcBuildWagon; CommandCallback CcBuildLoco; +/* town_gui.cpp */ +CommandCallback CcFoundTown; +CommandCallback CcFoundRandomTown; + /* group_gui.cpp */ CommandCallback CcCreateGroup; @@ -93,6 +96,7 @@ CommandCallback * const _callback_table[] = { /* 0x16 */ CcCloneVehicle, /* 0x17 */ CcGiveMoney, /* 0x18 */ CcCreateGroup, + /* 0x19 */ CcFoundRandomTown, }; const int _callback_table_count = lengthof(_callback_table); diff --git a/src/command.cpp b/src/command.cpp index 8782763e0e..f3c5526585 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -296,7 +296,7 @@ static const Command _command_proc_table[] = { {CmdSellShareInCompany, 0}, // CMD_SELL_SHARE_IN_COMPANY {CmdBuyCompany, 0}, // CMD_BUY_COMANY - {CmdFoundTown, CMD_OFFLINE}, // CMD_FOUND_TOWN + {CmdFoundTown, CMD_NO_TEST | CMD_OFFLINE}, // CMD_FOUND_TOWN {CmdRenameTown, CMD_SERVER}, // CMD_RENAME_TOWN {CmdDoTownAction, 0}, // CMD_DO_TOWN_ACTION diff --git a/src/town.h b/src/town.h index c524f971d3..c2a73f306e 100644 --- a/src/town.h +++ b/src/town.h @@ -163,7 +163,6 @@ void UpdateAllTownVirtCoords(); void InitializeTown(); void ShowTownViewWindow(TownID town); void ExpandTown(Town *t); -Town *CreateRandomTown(uint attempts, TownSize size, bool city, TownLayout layout); enum TownRatingCheckType { ROAD_REMOVE = 0, @@ -239,6 +238,7 @@ enum TownActions { DECLARE_ENUM_AS_BIT_SET(TownActions); extern const byte _town_action_costs[TACT_COUNT]; +extern TownID _new_town_id; /** * Calculate a hash value from a tile position diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index db158fe2ec..49f462e0b1 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -56,6 +56,7 @@ Town *_cleared_town; int _cleared_town_rating; +TownID _new_town_id; uint32 _cur_town_ctr; ///< iterator through all towns in OnTick_Town uint32 _cur_town_iter; ///< frequency iterator at the same place @@ -174,6 +175,7 @@ enum TownGrowthResult { }; static bool BuildTownHouse(Town *t, TileIndex tile); +static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout); static void TownDrawHouseLift(const TileInfo *ti) { @@ -1581,7 +1583,7 @@ static CommandCost TownCanBePlacedHere(TileIndex tile) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } - return CommandCost(); + return CommandCost(EXPENSES_OTHER); } /** Create a new town. @@ -1592,6 +1594,7 @@ static CommandCost TownCanBePlacedHere(TileIndex tile) * @param p1 0..1 size of the town (@see TownSize) * 2 true iff it should be a city * 3..5 town road layout (@see TownLayout) + * 6 use random location (randomize \c tile ) * @param p2 town name parts * @param text unused * @return the cost of this operation or an error @@ -1605,6 +1608,7 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 bool city = HasBit(p1, 2); TownLayout layout = (TownLayout)GB(p1, 3, 3); TownNameParams par(_settings_game.game_creation.town_name); + bool random = HasBit(p1, 6); uint32 townnameparts = p2; if (size > TS_RANDOM) return CMD_ERROR; @@ -1612,22 +1616,34 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (!VerifyTownName(townnameparts, &par)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); - CommandCost cost = TownCanBePlacedHere(tile); - if (CmdFailed(cost)) return cost; - /* Allocate town struct */ if (!Town::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_TOWNS); + CommandCost cost(EXPENSES_OTHER); + if (!random) { + cost = TownCanBePlacedHere(tile); + if (CmdFailed(cost)) return cost; + } + /* Create the town */ if (flags & DC_EXEC) { - Town *t = new Town(tile); _generating_world = true; UpdateNearestTownForRoadTiles(true); - DoCreateTown(t, tile, townnameparts, size, city, layout); + if (random) { + const Town *t = CreateRandomTown(20, townnameparts, size, city, layout); + if (t == NULL) { + cost = CommandCost(STR_ERROR_NO_SPACE_FOR_TOWN); + } else { + _new_town_id = t->index; + } + } else { + Town *t = new Town(tile); + DoCreateTown(t, tile, townnameparts, size, city, layout); + } UpdateNearestTownForRoadTiles(false); _generating_world = false; } - return CommandCost(); + return cost; } /** @@ -1744,7 +1760,7 @@ static TileIndex FindNearestGoodCoastalTownSpot(TileIndex tile, TownLayout layou return INVALID_TILE; } -Town *CreateRandomTown(uint attempts, TownSize size, bool city, TownLayout layout) +static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout) { if (!Town::CanAllocateItem()) return NULL; @@ -1762,10 +1778,6 @@ Town *CreateRandomTown(uint attempts, TownSize size, bool city, TownLayout layou /* Make sure town can be placed here */ if (CmdFailed(TownCanBePlacedHere(tile))) continue; - uint32 townnameparts; - /* Get a unique name for the town. */ - if (!GenerateTownName(&townnameparts)) break; - /* Allocate a town struct */ Town *t = new Town(tile); @@ -1793,6 +1805,7 @@ bool GenerateTowns(TownLayout layout) uint num = 0; uint difficulty = _settings_game.difficulty.number_towns; uint n = (difficulty == (uint)CUSTOM_TOWN_NUMBER_DIFFICULTY) ? _settings_game.game_creation.custom_town_number : ScaleByMapSize(_num_initial_towns[difficulty] + (Random() & 7)); + uint32 townnameparts; SetGeneratingWorldProgress(GWP_TOWN, n); @@ -1802,22 +1815,28 @@ bool GenerateTowns(TownLayout layout) do { bool city = (_settings_game.economy.larger_towns != 0 && Chance16(1, _settings_game.economy.larger_towns)); IncreaseGeneratingWorldProgress(GWP_TOWN); + /* Get a unique name for the town. */ + if (!GenerateTownName(&townnameparts)) continue; /* try 20 times to create a random-sized town for the first loop. */ - if (CreateRandomTown(20, TS_RANDOM, city, layout) != NULL) num++; // if creation successfull, raise a flag + if (CreateRandomTown(20, townnameparts, TS_RANDOM, city, layout) != NULL) num++; // if creation successfull, raise a flag } while (--n); + if (num != 0) return true; + /* If num is still zero at this point, it means that not a single town has been created. * So give it a last try, but now more aggressive */ - if (num == 0 && CreateRandomTown(10000, TS_RANDOM, _settings_game.economy.larger_towns != 0, layout) == NULL) { - if (Town::GetNumItems() == 0) { - if (_game_mode != GM_EDITOR) { - extern StringID _switch_mode_errorstr; - _switch_mode_errorstr = STR_ERROR_COULD_NOT_CREATE_TOWN; - } - } - return false; // we are still without a town? we failed, simply + if (GenerateTownName(&townnameparts) && + CreateRandomTown(10000, townnameparts, TS_RANDOM, _settings_game.economy.larger_towns != 0, layout) != NULL) { + return true; } - return true; + + /* If there are no towns at all and we are generating new game, bail out */ + if (Town::GetNumItems() == 0 && _game_mode != GM_EDITOR) { + extern StringID _switch_mode_errorstr; + _switch_mode_errorstr = STR_ERROR_COULD_NOT_CREATE_TOWN; + } + + return false; // we are still without a town? we failed, simply } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 5b37a9f143..f5bce66a4c 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -848,6 +848,15 @@ void CcFoundTown(bool success, TileIndex tile, uint32 p1, uint32 p2) } } +void CcFoundRandomTown(bool success, TileIndex tile, uint32 p1, uint32 p2) +{ + if (success) { + tile = Town::Get(_new_town_id)->xy; + SndPlayTileFx(SND_1F_SPLAT, tile); + ScrollMainWindowToTile(tile); + } +} + /** Widget numbers of town scenario editor window. */ enum TownScenarioEditorWidgets { TSEW_CLOSEBOX, @@ -963,6 +972,18 @@ public: this->SetDirty(); } + void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc) + { + uint32 townnameparts; + if (!GenerateTownName(&townnameparts)) { + ShowErrorMessage(STR_ERROR_TOO_MANY_TOWNS, errstr, 0, 0); + return; + } + + DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6, + townnameparts, CMD_FOUND_TOWN | CMD_MSG(errstr), cc); + } + virtual void OnPaint() { this->DrawWidgets(); @@ -975,20 +996,10 @@ public: HandlePlacePushButton(this, TSEW_NEWTOWN, SPR_CURSOR_TOWN, HT_RECT, NULL); break; - case TSEW_RANDOMTOWN: { + case TSEW_RANDOMTOWN: this->HandleButtonClick(TSEW_RANDOMTOWN); - _generating_world = true; - UpdateNearestTownForRoadTiles(true); - const Town *t = CreateRandomTown(20, this->town_size, this->city, this->town_layout); - UpdateNearestTownForRoadTiles(false); - _generating_world = false; - - if (t == NULL) { - ShowErrorMessage(STR_ERROR_NO_SPACE_FOR_TOWN, STR_ERROR_CAN_T_GENERATE_TOWN, 0, 0); - } else { - ScrollMainWindowToTile(t->xy); - } - } break; + this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown); + break; case TSEW_MANYRANDOMTOWNS: this->HandleButtonClick(TSEW_MANYRANDOMTOWNS); @@ -1030,14 +1041,7 @@ public: virtual void OnPlaceObject(Point pt, TileIndex tile) { - uint32 townnameparts; - if (!GenerateTownName(&townnameparts)) { - ShowErrorMessage(STR_ERROR_TOO_MANY_TOWNS, STR_ERROR_CAN_T_FOUND_TOWN_HERE, 0, 0); - return; - } - - DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3, townnameparts, - CMD_FOUND_TOWN | CMD_MSG(STR_ERROR_CAN_T_FOUND_TOWN_HERE), CcFoundTown); + this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); } virtual void OnPlaceObjectAbort()