diff --git a/source.list b/source.list index cf75873586..6c17fa94db 100644 --- a/source.list +++ b/source.list @@ -1235,6 +1235,8 @@ citymania/cm_locations.hpp citymania/cm_locations.cpp citymania/cm_minimap.hpp citymania/cm_minimap.cpp +citymania/cm_misc_gui.hpp +citymania/cm_misc_gui.cpp citymania/cm_station_gui.hpp citymania/cm_station_gui.cpp newgrf_revisions.hpp diff --git a/src/citymania/cm_misc_gui.cpp b/src/citymania/cm_misc_gui.cpp new file mode 100644 index 0000000000..9154070046 --- /dev/null +++ b/src/citymania/cm_misc_gui.cpp @@ -0,0 +1,394 @@ +#include "../stdafx.h" + +#include "cm_misc_gui.hpp" + +#include "../command_func.h" +#include "../company_base.h" +#include "../debug.h" +#include "../newgrf_debug.h" +#include "../string_func.h" +#include "../strings_func.h" +#include "../tile_cmd.h" +#include "../town.h" +#include "../widget_type.h" +#include "../window_func.h" +#include "../window_gui.h" +#include "../zoom_func.h" +#include "../widgets/misc_widget.h" + +namespace citymania { + +static const NWidgetPart _nested_land_info_widgets[] = { + NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), SetMinimalSize(64, 32), EndContainer(), +}; + +static WindowDesc _land_info_desc( + WDP_MANUAL, "land_info", 0, 0, + WC_LAND_INFO, WC_NONE, + 0, + _nested_land_info_widgets, lengthof(_nested_land_info_widgets) +); + +class LandInfoWindow : public Window { + enum LandInfoLines { + LAND_INFO_CENTERED_LINES = 32, ///< Up to 32 centered lines (arbitrary limit) + LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES, ///< One multicenter line + LAND_INFO_LINE_END, + }; + + static const uint LAND_INFO_LINE_BUFF_SIZE = 512; + +public: + char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE]; + TileIndex tile; + TileIndex end_tile; ///< For use in ruler(dragdrop) mode + + virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + { + int scr_top = GetMainViewTop() + 2; + int scr_bot = GetMainViewBottom() - 2; + Point pt; + pt.y = Clamp(_cursor.pos.y + _cursor.total_size.y + _cursor.total_offs.y + 5, scr_top, scr_bot); + if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.total_offs.y - 5, scr_bot) - sm_height; + pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width); + return pt; + } + + void DrawWidget(const Rect &r, int widget) const override + { + if (widget != WID_LI_BACKGROUND) return; + + GfxDrawLine(r.left, r.top, r.right, r.top, PC_BLACK); + GfxDrawLine(r.left, r.bottom, r.right, r.bottom, PC_BLACK); + GfxDrawLine(r.left, r.top, r.left, r.bottom, PC_BLACK); + GfxDrawLine(r.right, r.top, r.right, r.bottom, PC_BLACK); + + uint y = r.top + WD_TEXTPANEL_TOP; + for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { + if (StrEmpty(this->landinfo_data[i])) break; + + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING, SA_HOR_CENTER); + y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + if (i == 0) y += 4; + } + + if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { + SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_TEXTPANEL_BOTTOM, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); + } + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + { + if (widget != WID_LI_BACKGROUND) return; + + size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; + for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { + if (StrEmpty(this->landinfo_data[i])) break; + + uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + size->width = max(size->width, width); + + size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + if (i == 0) size->height += 4; + } + + if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { + uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + size->width = max(size->width, min(ScaleGUITrad(300), width)); + SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); + size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); + } + } + + LandInfoWindow(TileIndex tile, TileIndex end_tile=INVALID_TILE) : + Window(&_land_info_desc), tile(tile), end_tile(end_tile) + { + this->InitNested(); + CLRBITS(this->flags, WF_WHITE_BORDER); + +#if defined(_DEBUG) +# define LANDINFOD_LEVEL 0 +#else +# define LANDINFOD_LEVEL 1 +#endif + DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile)); + DEBUG(misc, LANDINFOD_LEVEL, "type = %#x", _m[tile].type); + DEBUG(misc, LANDINFOD_LEVEL, "height = %#x", _m[tile].height); + DEBUG(misc, LANDINFOD_LEVEL, "m1 = %#x", _m[tile].m1); + DEBUG(misc, LANDINFOD_LEVEL, "m2 = %#x", _m[tile].m2); + DEBUG(misc, LANDINFOD_LEVEL, "m3 = %#x", _m[tile].m3); + DEBUG(misc, LANDINFOD_LEVEL, "m4 = %#x", _m[tile].m4); + DEBUG(misc, LANDINFOD_LEVEL, "m5 = %#x", _m[tile].m5); + DEBUG(misc, LANDINFOD_LEVEL, "m6 = %#x", _me[tile].m6); + DEBUG(misc, LANDINFOD_LEVEL, "m7 = %#x", _me[tile].m7); + DEBUG(misc, LANDINFOD_LEVEL, "m8 = %#x", _me[tile].m8); +#undef LANDINFOD_LEVEL + } + + void OnInit() override + { + Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); + + /* Because build_date is not set yet in every TileDesc, we make sure it is empty */ + TileDesc td; + + td.build_date = INVALID_DATE; + + /* Most tiles have only one owner, but + * - drivethrough roadstops can be build on town owned roads (up to 2 owners) and + * - roads can have up to four owners (railroad, road, tram, 3rd-roadtype "highway"). + */ + td.owner_type[0] = STR_LAND_AREA_INFORMATION_OWNER; // At least one owner is displayed, though it might be "N/A". + td.owner_type[1] = STR_NULL; // STR_NULL results in skipping the owner + td.owner_type[2] = STR_NULL; + td.owner_type[3] = STR_NULL; + td.owner[0] = OWNER_NONE; + td.owner[1] = OWNER_NONE; + td.owner[2] = OWNER_NONE; + td.owner[3] = OWNER_NONE; + + td.station_class = STR_NULL; + td.station_name = STR_NULL; + td.airport_class = STR_NULL; + td.airport_name = STR_NULL; + td.airport_tile_name = STR_NULL; + td.railtype = STR_NULL; + td.rail_speed = 0; + td.roadtype = STR_NULL; + td.road_speed = 0; + td.tramtype = STR_NULL; + td.tram_speed = 0; + td.population = 0; + + td.grf = nullptr; + + CargoArray acceptance; + AddAcceptedCargo(tile, acceptance, nullptr); + GetTileDesc(tile, &td); + + uint line_nr = 0; + + /* Tiletype */ + SetDParam(0, td.dparam[0]); + GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Up to four owners */ + for (uint i = 0; i < 4; i++) { + if (td.owner_type[i] == STR_NULL) continue; + + SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A); + if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) GetNameOfOwner(td.owner[i], tile); + GetString(this->landinfo_data[line_nr], td.owner_type[i], lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Cost to clear/revenue when cleared */ + StringID str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A; + Company *c = Company::GetIfValid(_local_company); + if (c != nullptr) { + assert(_current_company == _local_company); + CommandCost costclear = DoCommand(tile, 0, 0, DC_QUERY_COST, CMD_LANDSCAPE_CLEAR); + if (costclear.Succeeded()) { + Money cost = costclear.GetCost(); + if (cost < 0) { + cost = -cost; // Negate negative cost to a positive revenue + str = STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED; + } else { + str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR; + } + SetDParam(0, cost); + } + } + GetString(this->landinfo_data[line_nr], str, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Location */ + char tmp[16]; + seprintf(tmp, lastof(tmp), "0x%.4X", tile); + SetDParam(0, TileX(tile)); + SetDParam(1, TileY(tile)); + SetDParam(2, GetTileZ(tile)); + SetDParamStr(3, tmp); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LANDINFO_COORDS, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Local authority */ + SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); + if (t != nullptr) { + SetDParam(0, STR_TOWN_NAME); + SetDParam(1, t->index); + } + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY, lastof(this->landinfo_data[line_nr])); + line_nr++; + + /* Build date */ + if (td.build_date != INVALID_DATE) { + SetDParam(0, td.build_date); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_BUILD_DATE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Station class */ + if (td.station_class != STR_NULL) { + SetDParam(0, td.station_class); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_CLASS, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Station type name */ + if (td.station_name != STR_NULL) { + SetDParam(0, td.station_name); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Airport class */ + if (td.airport_class != STR_NULL) { + SetDParam(0, td.airport_class); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_CLASS, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Airport name */ + if (td.airport_name != STR_NULL) { + SetDParam(0, td.airport_name); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_NAME, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Airport tile name */ + if (td.airport_tile_name != STR_NULL) { + SetDParam(0, td.airport_tile_name); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Rail type name */ + if (td.railtype != STR_NULL) { + SetDParam(0, td.railtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Rail speed limit */ + if (td.rail_speed != 0) { + SetDParam(0, td.rail_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Road type name */ + if (td.roadtype != STR_NULL) { + SetDParam(0, td.roadtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Road speed limit */ + if (td.road_speed != 0) { + SetDParam(0, td.road_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Tram type name */ + if (td.tramtype != STR_NULL) { + SetDParam(0, td.tramtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Tram speed limit */ + if (td.tram_speed != 0) { + SetDParam(0, td.tram_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* NewGRF name */ + if (td.grf != nullptr) { + SetDParamStr(0, td.grf); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_NEWGRF_NAME, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* House pop */ + if (td.population != 0) { + SetDParam(0, td.population); + GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_POP, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + assert(line_nr < LAND_INFO_CENTERED_LINES); + + /* Mark last line empty */ + this->landinfo_data[line_nr][0] = '\0'; + + /* Cargo acceptance is displayed in a extra multiline */ + char *strp = GetString(this->landinfo_data[LAND_INFO_MULTICENTER_LINE], STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + bool found = false; + + for (CargoID i = 0; i < NUM_CARGO; ++i) { + if (acceptance[i] > 0) { + /* Add a comma between each item. */ + if (found) strp = strecpy(strp, ", ", lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + found = true; + + /* If the accepted value is less than 8, show it in 1/8:ths */ + if (acceptance[i] < 8) { + SetDParam(0, acceptance[i]); + SetDParam(1, CargoSpec::Get(i)->name); + strp = GetString(strp, STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + } else { + strp = GetString(strp, CargoSpec::Get(i)->name, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); + } + } + } + if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0'; + } + + bool IsNewGRFInspectable() const override + { + return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), this->tile); + } + + void ShowNewGRFInspectWindow() const override + { + ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + void OnInvalidateData(int data = 0, bool gui_scope = true) override + { + if (!gui_scope) return; + switch (data) { + case 1: + /* ReInit, "debug" sprite might have changed */ + this->ReInit(); + break; + } + } +}; + +/** + * Show land information window. + * @param tile The tile to show information about. + */ +void ShowLandInfo(TileIndex tile, TileIndex end_tile) +{ + static TileIndex last_tooltip_tile = INVALID_TILE; + if (tile == last_tooltip_tile) return; + last_tooltip_tile = tile; + + DeleteWindowById(WC_LAND_INFO, 0); + if (tile == INVALID_TILE) return; + new LandInfoWindow(tile, end_tile); +} + +} // namespace citymania diff --git a/src/citymania/cm_misc_gui.hpp b/src/citymania/cm_misc_gui.hpp new file mode 100644 index 0000000000..eb200c5b3a --- /dev/null +++ b/src/citymania/cm_misc_gui.hpp @@ -0,0 +1,12 @@ +#ifndef CM_MISC_GUI_HPP +#define CM_MISC_GUI_HPP + +#include "../tile_type.h" + +namespace citymania { + +void ShowLandInfo(TileIndex tile, TileIndex end_tile = INVALID_TILE); + +} // namespace citymania + +#endif diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 7473fb3da4..b978bf4073 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -354,7 +354,6 @@ static void DrawTile_Industry(TileInfo *ti) DrawWaterClassGround(ti); } else { DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour))); - // DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour))); } /* If industries are transparent and invisible, do not draw the upper part */ diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 0e59781655..222365eefb 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -39,6 +39,7 @@ #include "industry.h" #include "citymania/cm_tooltips.hpp" +#include "citymania/cm_misc_gui.hpp" #include "safeguards.h" @@ -1322,10 +1323,10 @@ void GuiPrepareTooltipsExtra(Window *parent){ if (_cursor.sprite_seq[0].sprite == SPR_CURSOR_QUERY) { // Land info tool active - ShowLandInfo(tile); + citymania::ShowLandInfo(tile); return; } - ShowLandInfo(INVALID_TILE); + citymania::ShowLandInfo(INVALID_TILE); if (tile >= MapSize()) tile = INVALID_TILE; citymania::ShowLandTooltips(tile, parent); diff --git a/src/story.cpp b/src/story.cpp index e5fac1536b..b1071081f0 100644 --- a/src/story.cpp +++ b/src/story.cpp @@ -356,4 +356,4 @@ CommandCost CmdRemoveStoryPageElement(TileIndex tile, DoCommandFlag flags, uint3 } return CommandCost(); -} +} \ No newline at end of file