diff --git a/src/command.cpp b/src/command.cpp index a209f546e9..00bc9d46e7 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -130,6 +130,7 @@ CommandProc CmdRenameTown; CommandProc CmdDoTownAction; CommandProc CmdTownGrowthRate; CommandProc CmdTownCargoGoal; +CommandProc CmdTownSetText; CommandProc CmdExpandTown; CommandProc CmdDeleteTown; @@ -269,6 +270,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdDoTownAction, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_DO_TOWN_ACTION DEF_CMD(CmdTownCargoGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_CARGO_GOAL DEF_CMD(CmdTownGrowthRate, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_GROWTH_RATE + DEF_CMD(CmdTownSetText, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_SET_TEXT DEF_CMD(CmdExpandTown, CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_EXPAND_TOWN DEF_CMD(CmdDeleteTown, CMD_OFFLINE, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_DELETE_TOWN diff --git a/src/command_type.h b/src/command_type.h index e63e64b135..b0b1094552 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -250,6 +250,7 @@ enum Commands { CMD_DO_TOWN_ACTION, ///< do a action from the town detail window (like advertises or bribe) CMD_TOWN_CARGO_GOAL, ///< set the goal of a cargo for a town CMD_TOWN_GROWTH_RATE, ///< set the town growth rate + CMD_TOWN_SET_TEXT, ///< set the custom text of a town CMD_EXPAND_TOWN, ///< expand a town CMD_DELETE_TOWN, ///< delete a town diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 4a29209848..1a424308c0 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -157,6 +157,8 @@ static const SaveLoad _town_desc[] = { SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, 165, SL_MAX_VERSION), + SLE_CONDSTR(Town, text, SLE_STR, 0, 168, SL_MAX_VERSION), + SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, 0, 53), SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, 0, 53), SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, 0, 53), diff --git a/src/script/api/game/game_town.hpp.sq b/src/script/api/game/game_town.hpp.sq index b5837bc17e..ad0dfe4286 100644 --- a/src/script/api/game/game_town.hpp.sq +++ b/src/script/api/game/game_town.hpp.sq @@ -40,6 +40,7 @@ void SQGSTown_Register(Squirrel *engine) SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetTownCount, "GetTownCount", 1, "."); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::IsValidTown, "IsValidTown", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetName, "GetName", 2, ".i"); + SQGSTown.DefSQStaticMethod(engine, &ScriptTown::SetText, "SetText", 3, ".i."); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetPopulation, "GetPopulation", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetHouseCount, "GetHouseCount", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetLocation, "GetLocation", 2, ".i"); diff --git a/src/script/api/script_town.cpp b/src/script/api/script_town.cpp index d213f1d0d0..081bccd519 100644 --- a/src/script/api/script_town.cpp +++ b/src/script/api/script_town.cpp @@ -43,6 +43,12 @@ return town_name; } +/* static */ bool ScriptTown::SetText(TownID town_id, const char *text) +{ + EnforcePrecondition(false, IsValidTown(town_id)); + return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, 0, CMD_TOWN_SET_TEXT, text); +} + /* static */ int32 ScriptTown::GetPopulation(TownID town_id) { if (!IsValidTown(town_id)) return -1; diff --git a/src/script/api/script_town.hpp b/src/script/api/script_town.hpp index 0cee786942..d7f0c44f3a 100644 --- a/src/script/api/script_town.hpp +++ b/src/script/api/script_town.hpp @@ -127,6 +127,16 @@ public: */ static char *GetName(TownID town_id); + /** + * Set the custom text of a town, shown in the GUI. + * @param town_id The town to set the custom text of. + * @param text The text to set it to. + * @pre IsValidTown(town_id). + * @return True if the action succeeded. + * @api -ai + */ + static bool SetText(TownID town_id, const char *text); + /** * Gets the number of inhabitants in the town. * @param town_id The town to get the population of. diff --git a/src/town.h b/src/town.h index 35e3b84c8f..068a2053ab 100644 --- a/src/town.h +++ b/src/town.h @@ -78,6 +78,8 @@ struct Town : TownPool::PoolItem<&_town_pool> { TransportedCargoStat received[NUM_TE]; ///< Cargo statistics about received cargotypes. uint32 goal[NUM_TE]; ///< Amount of cargo required for the town to grow. + char *text; ///< General text with additional information. + inline byte GetPercentTransported(CargoID cid) const { return this->supplied[cid].old_act * 256 / (this->supplied[cid].old_max + 1); } /* Cargo production and acceptance stats. */ diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 096468599a..fac15efe50 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -62,6 +62,7 @@ INSTANTIATE_POOL_METHODS(Town) Town::~Town() { free(this->name); + free(this->text); if (CleaningPool()) return; @@ -2473,6 +2474,30 @@ CommandCost CmdTownCargoGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uin return CommandCost(); } +/** + * Set a custom text in the Town window. + * @param tile Unused. + * @param flags Type of operation. + * @param p1 Town ID to change the text of. + * @param p2 Unused. + * @param text The new text (empty to remove the text). + * @return Empty cost or an error. + */ +CommandCost CmdTownSetText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + if (_current_company != OWNER_DEITY) return CMD_ERROR; + Town *t = Town::GetIfValid(p1); + if (t == NULL) return CMD_ERROR; + + if (flags & DC_EXEC) { + free(t->text); + t->text = StrEmpty(text) ? NULL : strdup(text); + InvalidateWindowData(WC_TOWN_VIEW, p1); + } + + return CommandCost(); +} + /** * Change the growth rate of the town. * @param tile Unused. diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 0f64af3557..038b3cf05f 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -403,6 +403,10 @@ public: SetDParam(1, this->town->MaxTownNoise()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN); } + + if (this->town->text != NULL) { + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, this->town->text, TC_BLACK); + } } virtual void OnClick(Point pt, int widget, int click_count) @@ -448,7 +452,7 @@ public: { switch (widget) { case WID_TV_INFO: - size->height = GetDesiredInfoHeight(); + size->height = GetDesiredInfoHeight(size->width); break; } } @@ -457,7 +461,7 @@ public: * Gets the desired height for the information panel. * @return the desired height in pixels. */ - uint GetDesiredInfoHeight() const + uint GetDesiredInfoHeight(int width) const { uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; @@ -477,13 +481,18 @@ public: if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL; + if (this->town->text != NULL) { + SetDParamStr(0, this->town->text); + aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width); + } + return aimed_height; } void ResizeWindowAsNeeded() { const NWidgetBase *nwid_info = this->GetWidget(WID_TV_INFO); - uint aimed_height = GetDesiredInfoHeight(); + uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x); if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) { this->ReInit(); }